Entendendo Autoscaling em Kubernetes
Autoscaling é um dos pilares da infraestrutura moderna em Kubernetes. Quando sua aplicação recebe picos de tráfego, você precisa de mais recursos de forma automática. Da mesma forma, quando a demanda cai, você não quer pagar por capacidade ociosa. O Kubernetes oferece duas estratégias principais de autoscaling: o Horizontal Pod Autoscaler (HPA) e o Vertical Pod Autoscaler (VPA). Embora ambos resolvam o problema de escalabilidade, eles abordam o problema de ângulos completamente diferentes.
O HPA adiciona mais réplicas do seu pod quando a carga aumenta, enquanto o VPA ajusta os recursos (CPU e memória) solicitados e os limites de cada pod individual. Entender a diferença entre essas duas abordagens e quando usá-las é essencial para qualquer engenheiro que trabalha com Kubernetes em produção.
Horizontal Pod Autoscaler (HPA)
O que é e como funciona
O Horizontal Pod Autoscaler monitora métricas como CPU e memória (ou métricas personalizadas) e automaticamente aumenta ou diminui o número de réplicas de um Deployment, StatefulSet ou ReplicaSet. O controlador HPA funciona em um loop contínuo, consultando as métricas a cada 15 segundos (por padrão) e calculando se mais ou menos réplicas são necessárias.
A fórmula básica do HPA é: desiredReplicas = ceil[currentReplicas * (currentMetricValue / targetMetricValue)]. Se sua aplicação tem 2 réplicas consumindo 80% de CPU e o alvo é 50%, o HPA tentará escalar para 3 réplicas (2 * 80/50 = 3.2, arredondado para 3).
Pré-requisitos e instalação de métricas
Antes de usar HPA, você precisa ter o Metrics Server instalado no seu cluster. Este componente coleta métricas de uso de recursos dos nodes e pods. Se você estiver usando um cluster gerenciado (GKE, EKS, AKS), o Metrics Server já vem pré-instalado.
# Para verificar se o Metrics Server está instalado
kubectl get deployment metrics-server -n kube-system
# Se não estiver instalado, faça a instalação
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# Verifique se está rodando
kubectl top nodes
kubectl top pods -n default
Se os comandos kubectl top funcionarem, você está pronto para usar HPA.
Exemplo prático de HPA
Vamos criar um exemplo completo com uma aplicação simples que consome CPU sob demanda. Primeiro, criaremos um Deployment:
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: app
image: nginx:latest
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
ports:
- containerPort: 80
Agora criamos o HPA que escalará este Deployment:
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-app-hpa
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
Aplicar os recursos:
kubectl apply -f deployment.yaml
kubectl apply -f hpa.yaml
# Monitorar o status do HPA
kubectl get hpa web-app-hpa --watch
kubectl describe hpa web-app-hpa
Agora, para testar o autoscaling, vamos simular carga com um pod auxiliar:
# Criar um pod de teste
kubectl run -i --tty load-generator --rm --image=busybox --restart=Never -- /bin/sh -c "while sleep 0.01; do wget -q -O- http://web-app; done"
Observe como o número de pods aumenta gradualmente enquanto a carga é mantida. Quando você encerrar o gerador de carga (Ctrl+C), verá os pods sendo reduzidos após o stabilizationWindowSeconds.
Métricas personalizadas com HPA
O HPA não se limita apenas a CPU e memória. Você pode escalar baseado em métricas customizadas coletadas de ferramentas como Prometheus. Aqui está um exemplo:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-app-custom-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "1000"
Neste caso, o HPA escalará a aplicação para manter aproximadamente 1000 requisições por segundo por pod.
Vertical Pod Autoscaler (VPA)
O que é e como funciona
O Vertical Pod Autoscaler é fundamentalmente diferente do HPA. Em vez de aumentar o número de pods, o VPA ajusta os requests e limits de CPU e memória de cada pod existente. Ele analisa o histórico de uso de cada container e faz recomendações sobre qual deveria ser o tamanho ideal.
O VPA funciona em três modos principais: Off (apenas faz recomendações), Initial (define recursos apenas na criação), Recreate (mata e recria pods com novos valores) e Auto (escolhe automaticamente entre os anteriores). A maioria das implementações em produção usa o modo Auto, que tenta ser menos disruptivo possível.
Instalação do VPA
O VPA é mais complexo de instalar porque requer três componentes: o Recommender (que coleta dados), o Updater (que modifica pods) e o Admission Controller (que define recursos em novos pods). A maneira mais fácil é usar o script fornecido pela comunidade:
# Clone o repositório
git clone https://github.com/kubernetes/autoscaler.git
cd autoscaler/vertical-pod-autoscaler
# Execute o script de instalação
./hack/vpa-up.sh
# Verifique a instalação
kubectl get deployment -n kube-system | grep vpa
kubectl get pods -n kube-system | grep vpa
Exemplo prático de VPA
Vamos criar uma aplicação que têm requests iniciais inadequados e deixar o VPA otimizá-los:
# app-for-vpa.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: memory-intensive-app
spec:
replicas: 3
selector:
matchLabels:
app: memory-app
template:
metadata:
labels:
app: memory-app
spec:
containers:
- name: app
image: polinux/stress
resources:
requests:
cpu: 50m # Muito baixo para o que a app precisa
memory: 64Mi # Muito baixo para o que a app precisa
limits:
cpu: 200m
memory: 256Mi
command: ["stress"]
args:
- "--cpu"
- "1"
- "--vm"
- "1"
- "--vm-bytes"
- "150M"
- "--vm-hang"
- "1"
Agora criamos a política do VPA:
# vpa-policy.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: memory-app-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: memory-intensive-app
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: "*"
minAllowed:
cpu: 50m
memory: 64Mi
maxAllowed:
cpu: 1
memory: 1Gi
controlledResources: ["cpu", "memory"]
controlledValues: RequestsAndLimits
Aplicar:
kubectl apply -f app-for-vpa.yaml
kubectl apply -f vpa-policy.yaml
# Monitorar as recomendações
kubectl describe vpa memory-app-vpa
kubectl get vpa memory-app-vpa --watch
# Ver em tempo real as mudanças
kubectl describe deployment memory-intensive-app
Após alguns minutos, o VPA enviará as recomendações. Quando está em modo "Auto", ele criará novos pods com os recursos recomendados, matando os antigos.
Entendendo as recomendações do VPA
Quando você executa kubectl describe vpa, você verá algo como:
Status:
Recommendation:
Container Recommendations:
- Container Name: app
Lower Bound:
Cpu: 100m
Memory: 256Mi
Target:
Cpu: 200m
Memory: 512Mi
Uncapped Target:
Cpu: 200m
Memory: 512Mi
Upper Bound:
Cpu: 500m
Memory: 1Gi
Essas recomendações vêm de percentis de uso histórico: o Target geralmente é o P95 (95º percentil) do uso observado, o Lower Bound é um valor seguro mínimo, e o Upper Bound garante que você não aloque recursos demais.
Comparando HPA vs VPA: Quando usar cada um
HPA: Escalabilidade horizontal
Use HPA quando sua aplicação é stateless ou quando os pods podem ser criados e destruídos facilmente. Exemplos incluem APIs REST, serviços web e workers de processamento de filas. O HPA é ideal quando você quer distribuir a carga entre múltiplas instâncias da aplicação.
HPA também é a escolha certa quando você sabe que picos de tráfego são temporários. Se você recebe 10x mais requisições por uma hora e depois volta ao normal, escalar horizontalmente é mais eficiente que aumentar a memória de cada pod permanentemente.
VPA: Escalabilidade vertical
Use VPA quando sua aplicação é stateful ou quando o custo de criação de novos pods é alto (como em bancos de dados que replicam dados). O VPA também é essencial quando você não tem ideia de qual é o tamanho correto dos seus containers — ele aprende com o tempo e ajusta.
O VPA brilha em cenários de "right-sizing": muitas organizações definem requests com valores aleatórios ou muito conservadores. O VPA analisa semanas de dados e diz exatamente quanto cada container precisa.
Combinando HPA e VPA
A melhor prática em muitos cenários é usar ambos juntos, mas com cuidado. O HPA escalará horizontalmente para distribuir a carga, enquanto o VPA garante que cada pod tem o tamanho correto. No entanto, você deve configurá-los com inteligência:
# Exemplo: HPA + VPA juntos
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
---
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: app-vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Auto"
Nesta configuração, o VPA define requests/limits ideais, e o HPA escala horizontalmente quando a utilização ultrapassa 70%. Isso funciona bem porque o VPA está sempre ajustando os tamanhos dos containers para o valor ideal, enquanto HPA reage em tempo real ao tráfego.
Troubleshooting e Boas Práticas
Problemas comuns com HPA
Se seu HPA não está escalando, verifique: (1) o Metrics Server está rodando? (2) os pods têm requests definidos? (3) as métricas estão disponíveis via kubectl top? O HPA precisa de requests para calcular a utilização percentual. Sem requests, ele não consegue fazer cálculos.
# Diagnóstico: verificar eventos do HPA
kubectl describe hpa seu-hpa-name
kubectl get events -n seu-namespace --sort-by='.lastTimestamp'
# Verificar métricas manualmente
kubectl get --raw /apis/metrics.k8s.io/v1beta1/namespaces/default/pods
Problemas comuns com VPA
O VPA às vezes não faz recomendações se há dados insuficientes. Aguarde alguns dias de coleta de dados antes de esperar recomendações precisas. Além disso, se você definir maxAllowed muito apertado, o VPA não conseguirá fazer recomendações maiores que esse valor.
# Ver o status do VPA em detalhes
kubectl get vpa seu-vpa-name -o yaml | grep -A 20 "recommendation"
# Verificar logs do recommender
kubectl logs -n kube-system -l app=vpa-recommender -f
Boas práticas gerais
-
Sempre defina requests: Tanto HPA quanto VPA dependem de requests bem definidos. Requests são diferentes de limits — um request é o que você garante que o pod vai ter, enquanto limit é o máximo que pode usar.
-
Monitore o comportamento do autoscaling: Use ferramentas como Prometheus e Grafana para rastrear quando e por que o autoscaling foi acionado. Às vezes o comportamento revela problemas na aplicação, não no Kubernetes.
-
Use políticas de
scaleDownconservadoras: Escalar para cima é bom, mas escalar para baixo agressivamente pode matar requisições em progresso. O exemplo anterior temstabilizationWindowSeconds: 300para scale-down, o que é razoável. -
Teste em staging primeiro: Não implante HPA/VPA em produção sem testar o comportamento em um ambiente de teste idêntico.
-
Considere custos: HPA pode aumentar sua conta de cloud rapidamente em picos de tráfego. Sempre defina
maxReplicasemaxAllowedcom responsabilidade.
Conclusão
O Horizontal Pod Autoscaler e o Vertical Pod Autoscaler são ferramentas complementares, não concorrentes. O HPA resolve o problema de distribuir carga entre múltiplas instâncias (escala horizontal), enquanto o VPA resolve o problema de garantir que cada instância tem o tamanho certo (escala vertical). Na prática, você provavelmente usará ambos em sua infraestrutura Kubernetes: HPA para aplicações stateless que recebem tráfego variável, e VPA para right-sizing de todas as suas cargas de trabalho e para aplicações stateful que não podem ser replicadas trivialmente. O segredo é começar com HPA se você está começando em Kubernetes, ganhar experiência com o comportamento de sua aplicação sob carga, e depois introduzir VPA para otimização fina dos recursos.