Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

05 - Kubernetes HPA (Horizontal Pod Autoscaler)

#autoscaling#hpa#kubernetes#métricas
video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

Kubernetes HPA (Horizontal Pod Autoscaler)

O Horizontal Pod Autoscaler (HPA) é o controlador do Kubernetes que ajusta automaticamente o número de réplicas de um Deployment, ReplicaSet ou StatefulSet com base em métricas observadas, mantendo a carga por Pod próxima de um alvo declarado. Ele encerra a era do dimensionamento manual em clusters: picos de tráfego geram Pods novos em segundos, e vales devolvem capacidade ao cluster sem intervenção humana. Em produção, o HPA é a peça mais usada do pacote de autoscaling do Kubernetes, e sua corretude depende de um conjunto de peças coadjuvantes que costumam ser ignoradas: o metrics-server, as APIs de métricas, os limits declarados nos Pods e as janelas de estabilização do campo behavior. Este registro cobre o algoritmo de cálculo de réplicas, o HPA v2 com métricas de recurso e customizadas, o controle fino de comportamento, a interação com VPA e Cluster Autoscaler, a evolução do resize in-place introduzida no Kubernetes 1.33 e as armadilhas clássicas de operação.

Conceito e pré-requisitos

O HPA opera como um laço de controle assíncrono: a cada intervalo de sincronização, por padrão de 15 segundos, o controlador lê as métricas das réplicas atuais, calcula o número desejado de Pods e altera o campo de réplicas do alvo, que por sua vez cria ou remove Pods. O cálculo é declarativo, não reativo por alarme: nenhuma condição de gatilho, apenas uma função contínua entre métrica e capacidade.

Três pré-requisitos sustentam o funcionamento. O metrics-server precisa estar instalado, pois alimenta as métricas de recurso por Pod via API de métricas. Os contêineres precisam de requests declarados, porque as métricas de utilização são relativas ao request, não ao limit. E as aplicações devem se comportar razoavelmente como stateless, já que Pods removidos não preservam estado local. Sem um desses três pilares, o HPA fica em estado Unknown ou calcula valores absurdos.

O algoritmo de cálculo de réplicas

A fórmula central é uma proporção direta: réplicas desejadas igual a ceil de réplicas atuais multiplicadas pela razão entre métrica atual e métrica alvo. Se 4 Pods utilizam 80% do request de CPU e o alvo é 60%, o cálculo indica ceil de 4 vezes 1,33, ou seja, 6 Pods. Quando a métrica é de valor absoluto, como requisições por segundo agregadas, a fórmula usa o valor total dividido pelo alvo por Pod.

Detalhes finos evitam resultados contra-intuitivos. Pods com métrica indisponível são descontados do numerador e do denominador, e se a fração de Pods sem métrica for alta, o controlador abandona o cálculo. Pods que estão iniciando, dentro do tolerance period ou ainda não prontos, têm peso descontado. Há uma banda de tolerância, por padrão de 10%, abaixo da qual nenhuma ação ocorre, impedindo microajustes sem valor. Para métricas de objeto, como requisições por segundo de um Ingress, o HPA v2 soma os valores das réplicas e divide pelo alvo por Pod, comportamento útil quando a métrica só existe agregada.

Funcionamento interno do controlador

O controlador do HPA é um laço simples com guardas de segurança. A cada ciclo de sincronização, ele consulta as APIs de métricas, aplica a fórmula de proporção e compara com o estado atual do alvo. A sequência completa tem etapas que valem conhecer para diagnosticar.

  • Consulta o spec do HPA e identifica o alvo, por exemplo um Deployment, e o conjunto atual de Pods por seletor.
  • Busca métricas via API de métricas, no intervalo configurado; indisponibilidade de métrica marca o HPA como Unknown, e ele congela a escala.
  • Calcula o desejado por métrica, desconta Pods sem métrica e em warm-up, e aplica a banda de tolerância de 10%.
  • Seleciona o maior desejado entre as métricas declaradas e respeita minReplicas e maxReplicas.
  • Aplica as regras de behavior, verificando janelas de estabilização e políticas de taxa antes de gravar o novo número de réplicas.
  • Registra a decisão nos eventos do objeto, com o cálculo resumido, que é a principal fonte de diagnóstico operacional.

Conhecer esse laço explica comportamentos que confundem em incidente: um HPA Unknown não desescalda nem escalda, apenas congela; um Pod em boot não conta por inteiro na média; e um maxReplicas atingido produz estagnação silenciosa que só alarmes externos revelam.

HPA v2: métricas de recurso e customizadas

A API autoscaling/v2 substituiu as versões antigas e organiza as métricas em três tipos. As métricas de recurso, como CPU e memória, vêm do metrics-server e se expressam em porcentagem do request ou em valor absoluto. As métricas de Pod vêm de provedores customizados via API custom.metrics.k8s.io, como requisições por segundo por Pod expostas pelo Prometheus Adapter. E as métricas de objeto agregam um objeto externo ao Pod, como a profundidade média da fila SQS lida de um objeto externo via API externa.

# HPA v2: alvo por CPU e por métrica customizada de requisições por Pod
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: pagamentos-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: pagamentos
  minReplicas: 2          # piso de disponibilidade e de redundância
  maxReplicas: 12         # teto que protege o cluster e o custo
  metrics:
    - type: Resource      # métrica de recurso relativa ao request de CPU
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60
    - type: Pods          # métrica customizada exposta via adapter
      pods:
        metric:
          name: http_requests_per_second
        target:
          type: AverageValue
          averageValue: "100"
  behavior:               # controle fino de sobe e desce
    scaleUp:
      stabilizationWindowSeconds: 0    # sobe sem esperar estabilizar
      policies:
        - type: Percent
          value: 100           # pode dobrar a quantidade em 15s
          periodSeconds: 15
    scaleDown:
      stabilizationWindowSeconds: 300  # espera 5 min antes de reduzir
      policies:
        - type: Percent
          value: 25            # reduz no máximo 25% por minuto
          periodSeconds: 60

Quando múltiplas métricas são declaradas, o HPA calcula o desejado para cada uma e aplica o maior valor, garantindo que nenhuma dimensão de carga fique subdimensionada. A métrica customizada exige infraestrutura de provedor, tipicamente o Prometheus Adapter ou o KEDA, que traduz consultas em API de métricas consumível pelo controlador.

O exemplo abaixo mostra o caso de métrica de objeto externo, escalando a partir da profundidade de uma fila SQS agregada, padrão comum em workers de processamento.

# HPA v2 com métrica de objeto externo via KEDA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: processador-fila
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: processador
  minReplicas: 1
  maxReplicas: 30
  metrics:
    - type: External                 # métrica fora do cluster, da fila SQS
      external:
        metric:
          name: sqs_queue_depth      # exposta pelo provedor do KEDA
          selector:
            matchLabels:
              queue: pedidos-diario
        target:
          type: AverageValue
          averageValue: "30"         # 30 mensagens pendentes por Pod

Nesse padrão, o desejado é o total pendente dividido pelo alvo por Pod, o que dá escala linear com a dívida da fila. É a mesma semântica das políticas de fila na AWS, reinterpretada na taxonomia do Kubernetes.

Behavior: estabilização e taxas

O campo behavior é o arsenal contra o flapping. Ele separa scaleUp e scaleDown, cada um com uma janela de estabilização e políticas de taxa limitada por Pod ou por porcentagem. A janela de estabilização do scaleDown é a mais importante na prática: por padrão, o HPA aguarda 5 minutos de métricas menores antes de reduzir, desprezando picos breves que virariam churn de Pods. Políticas podem combinar seleção de máximo ou mínimo entre os candidatos, e valores podem expressar Pods absolutos ou percentuais da frota atual.

A calibragem deve refletir o custo de cada direção. Subir rápido e descer devagar é o padrão recomendado para serviços HTTP, pois o risco de saturar é maior que o risco de pagar alguns Pods a mais por minutos. Para workloads de fila caros por Pod, janelas maiores no descer economizam sem risco perceptível. A observação do campo de eventos do HPA, que registra cada decisão com a razão calculada, é a ferramenta primária de diagnóstico dessa calibragem.

HPA com VPA e Cluster Autoscaler

O HPA não atua sozinho, e as interações precisam ser deliberadas. O Cluster Autoscaler complementa na dimensão dos nós: quando Pods ficam pendentes por falta de capacidade, ele adiciona nós; quando nós ficam subutilizados, ele os remove com drenagem segura. Sem ele, o HPA satura o maxReplicas sem conseguir agendar os Pods criados. O VPA ajusta requests e limits verticamente, recomendando ou aplicando valores novos; em modo auto, por muito tempo ele reiniciava o Pod para aplicar o ajuste, o que conflita com o HPA na dimensão de CPU, pois mudanças de request alteram a porcentagem utilizada e confundem o cálculo.

A evolução recente resolve parte desse conflito: o Kubernetes 1.33 levou ao beta, habilitado por padrão, o redimensionamento in-place de recursos de Pod via subresource resize, permitindo alterar CPU e memória de um contêiner em execução sem recriar o Pod. As condições PodResizePending e PodResizeInProgress expõem o estado da transição, e o VPA com modo InPlaceOrRecreate passa a se valer do mecanismo, reduzindo disrupturas. Ainda assim, a combinação HPA e VPA sobre a mesma métrica de CPU permanece uma antipadronagem recomendada: pratique a separação clara, com HPA sobre CPU ou tráfego e VPA apenas sobre memória, ou vice-versa, dependendo do perfil do serviço.

Peça Dimensão ajustada Gatilho Cuidado de combinação
HPA Número de Pods CPU, memória, métricas customizadas Não dividir a mesma métrica com o VPA
VPA Requests e limits Histórico de uso Em modo auto, cuidado com restarts e com o HPA
Cluster Autoscaler Número de nós Pods pendentes ou nós ociosos Requisito para HPA com maxReplicas altos
KEDA Número de Pods via HPA Métricas externas, filas, cron Substitui a camada de coleta do HPA

Erros comuns e boas práticas

As falhas clássicas do HPA são previsíveis e evitáveis com disciplina de configuração.

  • Declarar métricas de recurso sem requests nos contêineres, deixando o HPA em Unknown; requests são a base de cálculo da utilização.
  • Alvo de CPU próximo de 100%, saturando o serviço antes do scale out ter efeito; alvos entre 50% e 70% dão margem para o tempo de provisionamento.
  • Não instalar o metrics-server, ou instalá-lo sem permissões, e descobrir no primeiro pico que o HPA nunca calculou nada.
  • Janela de scaleDown muito curta, gerando flapping com churn de Pods, re-agendamento e perda de cache de conexão.
  • Mínimo de 1 réplica, que derruba o serviço na substituição do único Pod; dois é o piso sanitário para serviços com tráfego.
  • Combinação HPA e VPA sobre CPU, produzindo oscilação mútua; separe as métricas entre os dois controladores.
  • Ignorar os eventos do HPA e alarmes de maxReplicas atingido, deixando oculto o momento em que a escala para de reagir.

Boas práticas consolidam a operação. Declarar requests e limits coerentes com o perfil real é o fundamento de todo o sistema. Prefira múltiplas métricas complementares, por exemplo CPU e requisições por segundo, para cubrir serviços com fases de I/O e de processamento. Ajuste behavior com base em teste de carga, observando o tempo de pico a capacidade plena. Monitore a distribuição de réplicas por zona, pois agendamento desbalanceado invalida a suposição de distribuição uniforme das métricas. E acompanhe a evolução da plataforma: o resize in-place em beta muda a fronteira entre escala horizontal e vertical, e serviços que antes oscilavam entre HPA e ajuste manual de limites ganham um terceiro caminho nativo, observável e sem reinício.