Horizontal Pod Autoscaler: Métricas, Thresholds e Comportamento: Do Básico ao Avançado Já leu

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

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.

Referências


Artigos relacionados