- 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
284 lines
9.7 KiB
Markdown
284 lines
9.7 KiB
Markdown
# 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:
|
||
|
||
```yaml
|
||
# 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
|
||
|
||
```bash
|
||
cd aula-05
|
||
|
||
# Instala Victoria Metrics, KEDA e NGINX Ingress
|
||
./setup.sh
|
||
```
|
||
|
||
O setup.sh instala:
|
||
1. **Victoria Metrics** - Coleta e armazena métricas
|
||
2. **kube-state-metrics** - Expõe métricas do Kubernetes (scrape 5s)
|
||
3. **KEDA** - Event-driven autoscaler
|
||
4. **NGINX Ingress** - Load balancer
|
||
|
||
## Trigger: Pods Indisponíveis (Instantâneo)
|
||
|
||
```yaml
|
||
- 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)
|
||
|
||
```yaml
|
||
# 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
|
||
|
||
```yaml
|
||
scaleUp:
|
||
stabilizationWindowSeconds: 0 # Sem espera
|
||
policies:
|
||
- type: Pods
|
||
value: 5 # +5 pods por vez
|
||
periodSeconds: 1 # A cada 1s
|
||
```
|
||
|
||
### Scale DOWN - Agressivo
|
||
|
||
```yaml
|
||
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
|
||
|
||
```bash
|
||
# 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
|
||
|
||
```bash
|
||
# 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
|
||
|
||
```promql
|
||
# 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:
|
||
|
||
```yaml
|
||
# ❌ 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
|
||
|
||
```bash
|
||
./cleanup.sh
|
||
```
|
||
|
||
## Lições
|
||
|
||
1. **Métrica instantânea**: Use `unavailable` em vez de `restarts` para detecção imediata
|
||
2. **Scrape rápido**: Configure 5s em vez do default 30s
|
||
3. **Query intuitiva**: `5 + (unavailable * 2)` calcula réplicas diretamente
|
||
4. **Scale agressivo**: `stabilizationWindow: 0` para reação imediata
|
||
5. **metricType correto**: `AverageValue` para 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.
|