- Documentar trigger único (unavailable) em vez de restarts - Explicar fórmula intuitiva: 5 + (unavailable * 2) - Adicionar seção sobre scrape interval de 5s - Documentar fluxo de detecção (~6-7s) - Explicar por que não usar restarts (CrashLoopBackOff) - Atualizar lições e trade-offs
Aula 05 - KEDA + Victoria Metrics (Auto-scaling por Métricas)
Auto-scaling inteligente baseado em métricas customizadas usando KEDA e Victoria Metrics.
O Problema
HPA padrão do Kubernetes escala apenas por CPU/memória:
# HPA tradicional - limitado
metrics:
- type: Resource
resource:
name: cpu
targetAverageUtilization: 70
Limitações:
- App pode estar "saudável" em CPU mas travada
- Não detecta pods indisponíveis
- Reação lenta (~15-30s)
A Solução: KEDA
KEDA (Kubernetes Event-driven Autoscaling) permite escalar baseado em qualquer métrica:
Victoria Metrics ──► KEDA ──► HPA ──► Deployment
│ │
│ └─ Consulta métricas a cada 1s
│
└─ Coleta métricas do cluster a cada 5s (kube-state-metrics)
Arquitetura
┌─────────────────────────────────────────────────────────────┐
│ Victoria Metrics │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ kube_deployment_status_replicas_unavailable = 3 │ │
│ │ Scrape interval: 5s (detecção rápida) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
Query PromQL a cada 1s
│
▼
┌─────────────────────────────────────────────────────────────┐
│ KEDA │
│ ┌────────────────────────────────────────────────────────┐│
│ │ Query: 5 + (unavailable * 2) ││
│ │ ││
│ │ 0 unavailable → 5 réplicas (mínimo) ││
│ │ 3 unavailable → 11 réplicas (5 + 6) ││
│ │ 5 unavailable → 15 réplicas (5 + 10) ││
│ └────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
│
Cria/Atualiza
│
▼
┌─────────────────────────────────────────────────────────────┐
│ HPA │
│ minReplicas: 5 ──────► maxReplicas: 30 │
└─────────────────────────────────────────────────────────────┘
│
Escala
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Deployment │
│ [Pod1] [Pod2] [Pod3] [Pod4] [Pod5] ... [Pod30] │
└─────────────────────────────────────────────────────────────┘
Instalação
cd aula-05
# Instala Victoria Metrics, KEDA e NGINX Ingress
./setup.sh
O setup.sh instala:
- Victoria Metrics - Coleta e armazena métricas
- kube-state-metrics - Expõe métricas do Kubernetes (scrape 5s)
- KEDA - Event-driven autoscaler
- NGINX Ingress - Load balancer
Trigger: Pods Indisponíveis (Instantâneo)
- type: prometheus
metricType: AverageValue
metadata:
serverAddress: http://vmsingle-vm-victoria-metrics-k8s-stack.monitoring:8428
# Query que calcula réplicas desejadas diretamente
query: |
5 + (kube_deployment_status_replicas_unavailable{
deployment="node-bugado",
namespace="default"
} * 2)
threshold: '1'
Como funciona a fórmula
| Pods Unavailable | Query Retorna | Réplicas Desejadas |
|---|---|---|
| 0 | 5 + (0 × 2) = 5 | 5 (mínimo) |
| 1 | 5 + (1 × 2) = 7 | 7 |
| 3 | 5 + (3 × 2) = 11 | 11 |
| 5 | 5 + (5 × 2) = 15 | 15 |
Vantagem: Detecção instantânea - não precisa de janela de tempo como métricas de restarts.
Configuração de Velocidade
Scrape Rápido (5s)
# vmservicescrape-kube-state-metrics.yaml
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMServiceScrape
spec:
endpoints:
- port: http
interval: 5s # Default é 30s - muito lento para workshop!
Scale UP - Agressivo
scaleUp:
stabilizationWindowSeconds: 0 # Sem espera
policies:
- type: Pods
value: 5 # +5 pods por vez
periodSeconds: 1 # A cada 1s
Scale DOWN - Agressivo
scaleDown:
stabilizationWindowSeconds: 0 # Sem espera
policies:
- type: Pods
value: 10 # -10 pods por vez
periodSeconds: 1 # A cada 1s
Fluxo de Detecção
Tempo 0.0s: Pod crasha
Tempo 0.0s: kube-state-metrics atualiza (imediato)
Tempo 5.0s: Victoria Metrics coleta (scrape interval)
Tempo 6.0s: KEDA consulta (polling interval)
Tempo 6.0s: HPA escala (imediato)
─────────────────────────────────────────────────
Total: ~6-7 segundos de reação
Exemplo de Scaling
Tempo 0s: 5 pods, 0 unavailable
Tempo 6s: Pod1 trava → detectado → escala para 7 pods
Tempo 7s: Pod2 trava → detectado → escala para 9 pods
Tempo 8s: Pod3 trava → detectado → escala para 11 pods
...
Tempo 15s: Pods reiniciaram, 0 unavailable
Tempo 16s: Scale down: 15 → 5 (instantâneo)
Teste de Stress
# Terminal 1: Monitorar pods
watch kubectl get pods -l app=node-bugado
# Terminal 2: Monitorar HPA
watch kubectl get hpa
# Terminal 3: Teste de stress
./teste-stress.sh
Comandos Úteis
# Ver ScaledObject
kubectl get scaledobject
kubectl describe scaledobject node-bugado-scaledobject
# Ver HPA criado pelo KEDA
kubectl get hpa
kubectl describe hpa keda-hpa-node-bugado-scaledobject
# Testar query no Victoria Metrics
kubectl run curl --rm -it --restart=Never --image=curlimages/curl -- \
-s 'http://vmsingle-vm-victoria-metrics-k8s-stack.monitoring:8428/api/v1/query' \
--data-urlencode 'query=5 + (kube_deployment_status_replicas_unavailable{deployment="node-bugado"} * 2)'
# Logs do KEDA
kubectl logs -n keda -l app=keda-operator -f
Queries PromQL Úteis
# Pods indisponíveis (usado pelo KEDA)
kube_deployment_status_replicas_unavailable{deployment="node-bugado"}
# Query completa do KEDA
5 + (kube_deployment_status_replicas_unavailable{deployment="node-bugado"} * 2)
# Pods prontos
kube_deployment_status_replicas_ready{deployment="node-bugado"}
# Total de restarts (para debug)
sum(kube_pod_container_status_restarts_total{pod=~"node-bugado.*"})
Por que não usar Restarts como trigger?
O trigger de restarts usa increase([window]) que requer uma janela de tempo:
# ❌ Problema: CrashLoopBackOff usa backoff exponencial
# Restart 1: imediato
# Restart 2: espera 10s
# Restart 3: espera 20s
# Restart 4: espera 40s
#
# Com janela de 15s, após restart 3+, o backoff > janela
# → increase([15s]) = 0 → KEDA não detecta!
Solução: Usar kube_deployment_status_replicas_unavailable que é instantâneo.
Victoria Metrics vs Prometheus
| Aspecto | Prometheus | Victoria Metrics |
|---|---|---|
| Recursos | Alto consumo | Baixo consumo |
| Armazenamento | Local apenas | Distribuído opcional |
| API | Nativa | Compatível 100% |
| Performance | Boa | Excelente |
| Para este workshop | Funciona | Recomendado |
Cleanup
./cleanup.sh
Lições
- Métrica instantânea: Use
unavailableem vez derestartspara detecção imediata - Scrape rápido: Configure 5s em vez do default 30s
- Query intuitiva:
5 + (unavailable * 2)calcula réplicas diretamente - Scale agressivo:
stabilizationWindow: 0para reação imediata - metricType correto:
AverageValuepara cálculo proporcional
Trade-offs
| Aspecto | HPA Padrão | KEDA (esta aula) |
|---|---|---|
| Configuração | Simples | Mais complexa |
| Métricas | CPU/Mem | Qualquer |
| Latência | ~15-30s | ~6-7s |
| Dependências | Nenhuma | Victoria Metrics |
| Flexibilidade | Baixa | Alta |
Próxima Aula
Aula 06: Deploy do n8n via Helm em ambiente local.