
Curso Kubernetes 26 — Capacidade e carga: HPA, k6 e rate limit
Capacidade não é "quantos usuários cabem". É em que ponto o sistema deixa de cumprir o SLO — e qual componente quebra primeiro.
Na maioria dos clusters que eu vi, não é a CPU. É o banco, a conexão, o disco ou o NAT.
Selo do curso: testado em Kubernetes 1.35 com k6 e HPA em homolog.
O que medir
| Métrica | Por quê |
|---|---|
| p50/p95/p99 | média esconde a cauda |
| taxa de erro | 200 com erro de negócio não conta |
| throughput | req/s sustentado |
| saturação | CPU, memória, conexões, disco |
| tempo de fila | onde o request espera |
Média de latência é a métrica mais inútil de capacidade. p95 com 83 ms e 0% de erro é um resultado; média de 40 ms com p99 de 4 s é um problema.
Baseline antes do teste
kubectl top nodes
kubectl -n portal top pods
kubectl -n portal get hpa
kubectl -n portal get pdb
kubectl -n portal get pods -o wide
Registre: réplicas, requests/limits, conexões do Postgres, uso de memória dos nós. Sem baseline, o teste vira anedota.
k6: ramp, não tiro único
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
stages: [
{ duration: '2m', target: 10 },
{ duration: '5m', target: 50 },
{ duration: '3m', target: 100 },
{ duration: '2m', target: 0 },
],
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<500'],
},
};
export default function () {
const res = http.get(`${__ENV.BASE_URL}/api/fornecedores`, {
headers: { Authorization: `Bearer ${__ENV.TOKEN}` },
});
check(res, { 'status 200': (r) => r.status === 200 });
sleep(1);
}
k6 run -e BASE_URL=https://homolog.example.com -e TOKEN=... k6.js
Ramp encontra o joelho da curva: o ponto em que latência sobe e throughput para de crescer.
O que aconteceu no nosso teste
Com 50 VUs contra o ingress:
| Métrica | Resultado |
|---|---|
| Erros | 0% |
| p95 | 83,9 ms |
| p99 | dentro do aceitável |
O teste seguinte, mais agressivo, derrubou o Postgres: o primário reiniciou e o failover levou o banco para outra instância. O app estava saudável; o banco não.
Conclusão prática: escalar o app sem dimensionar o banco transfere o problema. 10 pods de backend com pool de 10 conexões = 100 conexões, e o Postgres tem limite.
HPA: o que ele vê e o que ele ignora
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- HPA usa requests como denominador. Sem requests, não escala.
- CPU não vê fila de banco, latência ou conexões.
- Para filas, use métricas custom (KEDA) — tamanho de fila do RabbitMQ, por exemplo.
maxReplicasprecisa caber no cluster. HPA pedindo 8 pods com 4 nós cheios =Pending.
kubectl -n portal describe hpa portal-backend
A saída mostra unable to fetch metrics ou missing request for cpu quando falta requests.
Headroom de nó
Capacidade real = soma dos allocatable menos o que já está reservado, com margem para:
- um nó perdido (N+1);
- surge de rollout (
maxSurge); - DaemonSets.
kubectl describe node <node> | sed -n '/Allocated resources/,/Events/p'
Se cada nó está a 85%, você não tem HA: tem um cluster esperando o próximo drain.
Rate limit e proteção
Teste de carga também revela ausência de proteção:
- Rate limit no ingress (nginx
limit_req) ou no app. - Timeout de conexão e de leitura.
- Circuit breaker para dependência lenta.
- Connection pool com limite e timeout curto.
Sem isso, um pico vira fila infinita, e a fila vira timeout em cascata.
Teste seguro
Antes de rodar carga:
- Ambiente isolado (homolog), nunca prod sem janela.
- Backup recente do banco.
- Alerta de plantão avisado.
- Critério de parada definido (ex.: erro > 5% por 1 min).
- Observabilidade ligada: Prometheus, Grafana, logs.
- Plano de rollback.
E depois:
kubectl -n portal get pods
kubectl -n portal logs deploy/portal-backend --tail=100
kubectl -n portal get events --sort-by=.lastTimestamp | tail -20
Laboratório
- Rode um teste curto (10 VUs, 2 min) e valide o ambiente.
- Suba o ramp e acompanhe
kubectl get hpa -we o Grafana. - Identifique o primeiro componente saturado.
- Reduza
maxReplicase repita: veja o erro aparecer. - Ajuste o pool de conexões do app e repita.
- Documente: throughput máximo, p95 no limite e gargalo.
Erros comuns
| Sintoma | Causa |
|---|---|
| p95 explode com carga baixa | pool de conexão pequeno |
| HPA não escala | sem requests ou metrics-server fora |
Pods Pending no pico |
maxReplicas acima da capacidade |
| Banco reinicia sob carga | conexões/memória do Postgres |
| 429 inesperado | rate limit do ingress |
| Teste “passou” e prod caiu | ambiente de teste com mais recursos |
| Números irreproduzíveis | sem baseline nem script versionado |
Checklist
- [ ] Baseline registrado antes do teste.
- [ ] Script k6 versionado no repositório.
- [ ] Thresholds de erro e p95 definidos.
- [ ] HPA com requests e
maxReplicasque cabe no cluster. - [ ] Pool de conexões dimensionado com o banco.
- [ ] Headroom de N+1 validado.
- [ ] Rate limit e timeouts configurados.
- [ ] Critério de parada e rollback acordados.
- [ ] Resultado documentado com data e commit.
Glossário
- VU: usuário virtual do k6.
- ramp: aumento gradual de carga.
- joelho: ponto onde latência cresce sem ganho de throughput.
- headroom: folga de capacidade.
- pool: conjunto de conexões reutilizáveis.
- KEDA: autoscaling por eventos/filas.
Próximo
Você mediu capacidade e sabe onde quebra. Falta combinar isso com o que o negócio espera: SLO, SLI, on-call e postmortem sem culpa.
Próximo: Curso Kubernetes 27 — SLO/SLI, on-call e postmortem blameless
Continuar a ler
Leia também
KubernetesKubernetes de Verdade — do zero ao cluster em produção
Uma trilha prática para entender, montar e operar um cluster Kubernetes — do primeiro pod ao failover do Postgres.
4 min de leitura
KubernetesCurso Kubernetes 28 — DR e capstone: provar que o cluster volta
RPO, RTO e drills reais: cenários de desastre, runbook, restore medido e o capstone que fecha o curso com um cluster que se recupera.
5 min de leitura
KubernetesCurso Kubernetes 27 — SLO/SLI, on-call e postmortem blameless
O que prometer, como medir e o que fazer quando o erro estoura: SLI, SLO, error budget, alertas que acordam alguém e postmortem sem caça às bruxas.
4 min de leitura
Comentários
Ainda sem comentários
Seja o primeiro a compartilhar sua opinião sobre este artigo.
Deixe um comentário