Horizontal Pod Autoscaler: Visão Geral e Arquitetura
O Horizontal Pod Autoscaler (HPA) é um recurso nativo do Kubernetes que automatiza a escalabilidade horizontal de suas aplicações. Em vez de você gerenciar manualmente o número de réplicas de um Deployment, StatefulSet ou ReplicaSet, o HPA monitora métricas em tempo real e ajusta o número de pods baseado em regras que você define. Esse comportamento é fundamental para aplicações que enfrentam variação de carga.
A arquitetura do HPA funciona em um ciclo contínuo: o controller do HPA consulta as métricas da sua aplicação (CPU, memória ou métricas customizadas) a cada 15 segundos por padrão, compara com os thresholds configurados e toma decisões de scale-up ou scale-down. Esse processo é totalmente automatizado e reduz significativamente a necessidade de intervenção manual, economizando recursos e melhorando a disponibilidade da aplicação durante picos de demanda.
Pré-requisitos Técnicos
Para que o HPA funcione corretamente, você precisa de dois componentes críticos: o Metrics Server e os resource requests definidos nos seus pods. O Metrics Server coleta métricas de CPU e memória dos nodes e as expõe via API, permitindo que o HPA tome decisões baseadas em dados reais. Sem ele, o HPA não consegue funcionar. Além disso, todo pod monitorado pelo HPA precisa ter requests de CPU e memória declarados, pois o HPA calcula percentuais de utilização com base nesses valores.
# Exemplo de Deployment com requests e limits
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-exemplo
spec:
replicas: 2
selector:
matchLabels:
app: app-exemplo
template:
metadata:
labels:
app: app-exemplo
spec:
containers:
- name: app
image: nginx:latest
resources:
requests:
cpu: 100m # 0.1 CPU - OBRIGATÓRIO para HPA
memory: 128Mi # 128 MB - OBRIGATÓRIO para HPA
limits:
cpu: 500m
memory: 512Mi
ports:
- containerPort: 80
Métricas do HPA: Tipos e Cálculos
O HPA suporta três categorias principais de métricas: métricas de recursos (CPU e memória), métricas customizadas e métricas externas. Cada uma tem um propósito específico e é calculada de forma diferente pelo controller.
Métricas de Recursos (CPU e Memória)
As métricas de recursos são as mais simples e diretas. O HPA calcula a porcentagem de utilização de CPU e memória comparando o uso atual com o request definido no container. Por exemplo, se você configurar um request de 100m (miliCPU) e o pod está usando 50m, a utilização está em 50%. O cálculo é feito para todos os pods de um Deployment e depois é feita uma média: se você tem 3 pods, o HPA calcula a média de todos os três antes de tomar a decisão de escalar.
# Exemplo: HPA baseado em CPU
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app-hpa-cpu
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: app-exemplo
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # Escala quando CPU média > 70%
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
No exemplo acima, o HPA monitorará a CPU média de todos os pods do Deployment app-exemplo. Quando a média ultrapassar 70% do request configurado (100m × 0.70 = 70m), o HPA começará a adicionar pods. O comportamento de scale é controlado pela seção behavior que detalharemos mais adiante.
Métricas Customizadas
Métricas customizadas são ideais quando você quer escalar baseado em lógica de negócio específica: número de requisições por segundo, tamanho de fila, latência, ou qualquer outro indicador relevante para sua aplicação. Para usar métricas customizadas, você precisa de um provedor de métricas, como o Prometheus com um adapter customizado.
# Exemplo: HPA baseado em métrica customizada (requisições por segundo)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app-hpa-custom
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: app-exemplo
minReplicas: 2
maxReplicas: 20
metrics:
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 1000 # Escala quando RPS médio > 1000
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80 # Escala quando CPU > 80%
Neste exemplo, o HPA usa dois critérios simultaneamente: ele escalará quando qualquer um dos limites for atingido. Isso oferece mais controle e permite que sua aplicação responda a diferentes tipos de pressão. Se você exponha a métrica http_requests_per_second via Prometheus, o HPA a considerará nas decisões.
Métricas Externas
Métricas externas permitem integração com sistemas de monitoramento externos como Google Cloud Monitoring, AWS CloudWatch ou Datadog. Você referencia a métrica pelo nome e o HPA consulta o sistema externo para tomar decisões.
# Exemplo: HPA baseado em métrica externa (AWS SQS)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: worker-hpa-sqs
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: sqs-worker
minReplicas: 1
maxReplicas: 50
metrics:
- type: External
external:
metric:
name: sqs_queue_depth
selector:
matchLabels:
queue-name: minha-fila
target:
type: AverageValue
averageValue: "30" # 30 mensagens por pod
Thresholds, Comportamento e Estratégias de Escala
Os thresholds definem os limites que disparam a escalabilidade, mas o comportamento da escala (como rápido ela ocorre, com que agressividade) é controlado pela seção behavior do HPA. Essa é uma das partes mais críticas e frequentemente negligenciada na configuração.
Configuração de Thresholds
Um threshold é simplesmente o valor limite que, quando atingido, causa uma ação de escala. No exemplo anterior de CPU, 70% era o threshold. O HPA calcula se a métrica atual está acima ou abaixo do threshold e faz as contas sobre quantos pods são necessários para trazer a métrica de volta ao nível desejado.
A fórmula básica que o HPA usa internamente é:
desiredReplicas = ceil[currentReplicas × (currentMetricValue / targetMetricValue)]
Se você tem 5 pods usando 85% de CPU e seu target é 70%, o cálculo seria: ceil[5 × (85 / 70)] = ceil[6.07] = 7 pods. Isso é uma decisão de scale-up. Inversamente, se estiver usando 35% de CPU, o cálculo daria menos replicas e ocorreria um scale-down.
Behavior: Controlando Agressividade
A seção behavior controla como e com que rapidez o HPA escala. Sem ela configurada corretamente, você pode enfrentar "flapping" — escalas constantes para cima e para baixo — ou respostas muito lentas a picos de carga.
# Exemplo completo com behavior refinado
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: app-hpa-produção
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: aplicacao-critica
minReplicas: 3
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
# Configuração para SCALE UP (aumentar pods)
scaleUp:
stabilizationWindowSeconds: 0 # Sem espera, reage rápido
policies:
- type: Percent
value: 100 # Dobra a cada período
periodSeconds: 15
- type: Pods
value: 4 # Ou adiciona 4 pods (o que for maior)
periodSeconds: 15
selectPolicy: Max # Escolhe a política que resulta em mais pods
# Configuração para SCALE DOWN (reduzir pods)
scaleDown:
stabilizationWindowSeconds: 300 # Espera 5 min antes de desescalar
policies:
- type: Percent
value: 50 # Remove até 50% dos pods
periodSeconds: 15
- type: Pods
value: 2 # Ou remove 2 pods no máximo
periodSeconds: 15
selectPolicy: Min # Escolhe a política que resulta em menos pods
Entendendo Stabilization Window
A stabilizationWindowSeconds é um conceito crucial. No scale-up, geralmente colocamos 0 para responder imediatamente a picos. No scale-down, colocamos um valor maior (300 segundos = 5 minutos é comum) para evitar remover pods prematuramente quando a carga cai temporariamente. Isso previne flapping e garante estabilidade.
Durante a janela de estabilização, o HPA procura pelo maior valor de métrica observado naquele período. Isso significa que se em 5 minutos de scale-down a métrica subir novamente, o HPA pode cancelar o scale-down planejado. É um mecanismo de amortecimento muito inteligente.
Comportamento Prático e Monitoramento
Entender como o HPA se comporta em tempo real é essencial para debugging e otimização. Você pode inspecionar o estado do HPA, seus eventos e decisões através de comandos kubectl e pela análise de logs.
Inspecionando Status do HPA
# Ver status atual do HPA
kubectl get hpa -n seu-namespace
# Ver detalhes completos (muito útil!)
kubectl describe hpa app-hpa-cpu -n seu-namespace
# Exemplo de saída do describe:
# Name: app-hpa-cpu
# Namespace: default
# Labels: <none>
# Annotations: <none>
# CreationTimestamp: Mon, 15 Jan 2024 10:30:00 +0000
# Reference: Deployment/app-exemplo
# Metrics: ( current / target )
# resource cpu on pods ( 65% / 70% )
# Min replicas: 2
# Max replicas: 10
# Deployment pods: 5 current / 5 desired
# Conditions:
# Type Status Reason Message
# ---- ------ ------ -------
# AbleToScale True ReadyForNewScale recommended size matches current size
# ScalingActive True ValidMetricsFound the HPA was able to compute the replica count
# ScalingLimited False DesiredWithinRange the desired count is within the acceptable range
Essa saída te diz exatamente o que está acontecendo: qual é o uso atual, qual é o target, quantos pods existem, e por que o HPA está ou não escalando.
Monitorando Decisões do HPA
O HPA registra eventos importantes no Kubernetes. Você pode consultá-los para entender todas as decisões:
# Ver eventos do HPA em tempo real
kubectl get events -n seu-namespace --field-selector involvedObject.name=app-hpa-cpu --sort-by='.lastTimestamp'
# Exemplo de eventos:
# LAST SEEN TYPE REASON OBJECT MESSAGE
# 2m Normal SuccessfulRescale hpa/app-hpa-cpu New size: 7; reason: cpu resource utilization (actual: 75%, target: 70%)
# 5m Normal SuccessfulRescale hpa/app-hpa-cpu New size: 5; reason: cpu resource utilization (actual: 68%, target: 70%)
Caso Prático: Diagnóstico de Problemas
Um problema comum é o HPA não funcionar. Aqui está como diagnosticar:
# 1. Verificar se Metrics Server está instalado
kubectl get deployment metrics-server -n kube-system
# 2. Verificar se métricas estão disponíveis
kubectl top pods -n seu-namespace
kubectl top nodes
# 3. Verificar requests nos containers
kubectl get pods seu-pod -o yaml | grep -A 10 "resources:"
# 4. Se nada disso mostrar métricas, o HPA ficará em estado:
# ScalingActive: False, Reason: UnableComputeReplicaCountReason
Se você vir ScalingActive: False, o problema é falta de métricas. Sempre comece verificando o Metrics Server e os requests nos containers.
Exemplos Avançados: Combinando Tudo
Vamos construir um exemplo realista que combina tudo que aprendemos:
# Aplicação web com auto-scaling inteligente
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-produção
spec:
replicas: 3
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: minha-api:v1.2.0
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: api-produção-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: api-produção
minReplicas: 3 # Sempre manter ao menos 3 (alta disponibilidade)
maxReplicas: 50 # Não gastar demais em recursos
metrics:
# Métrica 1: CPU é o trigger primário
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# Métrica 2: Memória como failsafe
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 85
behavior:
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 50
periodSeconds: 15
- type: Pods
value: 2
periodSeconds: 15
selectPolicy: Max
scaleDown:
stabilizationWindowSeconds: 300 # 5 minutos
policies:
- type: Percent
value: 10
periodSeconds: 60
- type: Pods
value: 1
periodSeconds: 60
selectPolicy: Min
Neste exemplo produção:
- Scale-up é agressivo: responde imediatamente e pode dobrar os pods (50% + limites significam crescimento rápido)
- Scale-down é conservador: aguarda 5 minutos e remove pods lentamente (10% + máximo 1 pod)
- Dois critérios de métrica: se CPU OU memória atingirem o limite, escala
- Min/Max realista: começa com 3 pods (redundância) e máximo 50 (custo controlado)
Conclusão
Três aprendizados fundamentais que você deve levar daqui: primeiro, o HPA é inútil sem Metrics Server e requests bem definidos nos containers — esses são pré-requisitos absolutos, não opcionais. Segundo, o behavior é mais importante que os thresholds — você pode ter um threshold perfeito, mas com um behavior mal configurado, sua aplicação sofrerá com flapping ou respostas lentas a picos. Terceiro, sempre monitore os eventos do HPA com describe e events para entender exatamente o que está acontecendo; o Kubernetes oferece visibilidade completa, basta saber onde olhar.