AWS Builder Center

Autoscaling de pods no EKS: como escalar aplicações com HPA, KEDA e VPA

Sua aplicação no AWS EKS roda com o mesmo número de réplicas de madrugada e no pico? Neste artigo, você vai entender o autoscaling de pods no EKS: como o HPA calcula réplicas, como usar métricas customizadas e externas, como o KEDA escala por eventos e até zero, e quando o VPA entra. Inclui exemplos em YAML, boas práticas e um checklist para começar.

Series: Otimização de custos com AWS EKS (5 articles)

  1. …
  2. 4
    Autoscaling de pods no EKS: como escalar aplicações com HPA, KEDA e VPA This article
Solution Architect
No post sobre application profiling e rightsizing , ajustamos o tamanho de cada pod do AWS EKS  ao consumo real da aplicação. No entanto, a demanda muda ao longo do dia. Um serviço que precisa de 20 réplicas no pico pode precisar de 3 de madrugada. Se as réplicas não acompanham essa variação, você paga por pods ociosos fora do pico ou fica sem capacidade no pico. É isso que o autoscaling de pods no EKS resolve.
Um post da série "Otimização de custos com AWS EKS".
Neste post, você vai entender como o Horizontal Pod Autoscaler (HPA) calcula as réplicas e como escalar por métricas customizadas e externas. Em seguida, vai ver como o KEDA escala por eventos e até zero e, por fim, quando faz sentido usar o Vertical Pod Autoscaler (VPA) .

Por que escalar pods reduz desperdício

Num cluster EKS, as réplicas de cada aplicação reservam capacidade dos nós pelos seus requests. Assim, cada réplica a mais que fica rodando sem carga ocupa capacidade de nós AWS EC2  que você paga, mesmo sem processar nada.
O autoscaling de pods no EKS resolve uma parte do problema: ajusta quantas réplicas existem a cada momento. A outra parte, que é ajustar quantos nós existem, fica com o Karpenter ou o Cluster Autoscaler, assunto do próximo post. Na prática, os dois trabalham juntos: o HPA cria ou remove pods, e o autoscaler de nós cria ou remove os nós para acomodá-los.
Há ainda uma dependência importante com o post anterior. O HPA mede a utilização de CPU e memória como porcentagem do request. Se o request está inflado, a utilização parece baixa e o HPA demora a escalar. Por isso, o rightsizing vem antes do autoscaling.

Horizontal Pod Autoscaler (HPA): como funciona

O HPA é um recurso nativo do Kubernetes, então você não precisa instalá-lo. Ele só depende de uma fonte de métricas: segundo a documentação do EKS sobre o HPA , é o Metrics Server  que fornece esses dados — e ele não vem instalado por padrão no EKS.

O cálculo das réplicas

O controlador do HPA compara o valor atual da métrica com o valor desejado e calcula:
réplicas desejadas = arredondar para cima ( réplicas atuais × valor atual ÷ valor desejado )
Por exemplo, se o alvo é 50% de CPU e as 4 réplicas estão em 100%, o HPA dobra o número de réplicas, indo para 8, atingindo o alvo de 50%. Se estão em 25%, ele reduz pela metade a quantidade de réplicas, respeitando o mínimo e o máximo configurados. A documentação do Kubernetes sobre o HPA  detalha o algoritmo.

Estabilização: evitando o efeito sanfona

Se a métrica oscila, o HPA pode criar e remover pods o tempo todo. Para evitar isso, a API autoscaling/v2 tem o bloco behavior:
  • Scale down: por padrão, o HPA usa uma janela de estabilização de 300 segundos. Ou seja, ele considera as recomendações dos últimos 5 minutos e escolhe a maior, para só reduzir quando a queda se mantém.
  • Scale up: por padrão, não há janela de estabilização. Assim que a métrica sobe, o HPA escala.
  • Políticas: você pode limitar quantos pods (ou que porcentagem) entram e saem por período.

Exemplo: HPA por CPU com comportamento controlado

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: checkout
namespace: ecommerce
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: checkout
minReplicas: 2 # mínimo para alta disponibilidade
maxReplicas: 20 # teto para proteger o orçamento
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70 # porcentagem do request de CPU
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 50 # remove no máximo 50% das réplicas por minuto
periodSeconds: 60

Métricas de recurso, customizadas e externas

CPU e memória nem sempre representam bem a carga. Uma API, por exemplo, pode ficar lenta por excesso de requisições antes de a CPU subir. Por isso o HPA não lê de um componente específico, e sim de três APIs de métricas agregadas do Kubernetes — e para cada uma há uma implementação que a serve:
APIPara quêQuem serve
metrics.k8s.io (Resource Metrics)CPU e memória por podMetrics Server (padrão); ou o Prometheus Adapter
custom.metrics.k8s.io (Custom Metrics)métricas de dentro do cluster (ex.: requisições por segundo, conexões ativas)o Prometheus Adapter
external.metrics.k8s.io (External Metrics)métricas de fora do cluster (ex.: tamanho de uma fila, métrica de outro sistema)o KEDA
O Metrics Server implementa só a primeira — CPU e memória. Para escalar por requisições por segundo ou por profundidade de fila, você precisa de um adaptador que sirva as outras duas APIs. Num cluster que já roda Prometheus, o Prometheus Adapter pode inclusive servir também a metrics.k8s.io e dispensar o Metrics Server.
Para métricas do AWS CloudWatch , o caminho mais simples hoje é o KEDA, que tem um scaler específico para o CloudWatch.

Vários sinais no mesmo HPA: o maior vence

Essas APIs não são excludentes. Um único HPA pode declarar várias métricas ao mesmo tempo — CPU, uma métrica customizada e uma externa, misturadas. Quando há mais de uma, o HPA calcula as réplicas desejadas para cada métrica isoladamente e fica com o maior resultado.
Imagine um HPA com 4 réplicas e três métricas: CPU a 90% (alvo 70%), 30 requisições por segundo por pod (alvo 50) e uma fila com 120 mensagens (alvo de 10 por pod). As contas dão, respectivamente, 6, 3 e 12 réplicas — então o HPA vai para 12. A lógica é de segurança: se qualquer dimensão pede mais capacidade, o HPA atende a mais exigente.
Há duas consequências práticas:
  • O "maior vence" só vale para subir. Para o HPA reduzir réplicas, todas as métricas precisam concordar que dá para descer — e ainda respeitando a janela de estabilização. Uma métrica alta sozinha segura os pods lá em cima.
  • Se uma métrica fica indisponível, o HPA é conservador: pode seguir com um scale-up, mas evita o scale-down enquanto não tiver todas as leituras.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: checkout
namespace: ecommerce
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: checkout
minReplicas: 2
maxReplicas: 20
metrics:
- type: Resource # CPU — metrics.k8s.io (Metrics Server)
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Pods # req/s por pod — custom.metrics.k8s.io (Prometheus Adapter)
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "50"
- type: External # fila — external.metrics.k8s.io (KEDA)
external:
metric:
name: sqs_queue_length
target:
type: AverageValue
averageValue: "10"
É exatamente esse mecanismo que o KEDA usa por baixo: ao criar um ScaledObject, ele gera um HPA com a métrica externa nessa lista. Assim, CPU (Metrics Server) e fila (KEDA) podem escalar o mesmo Deployment lado a lado.

KEDA: autoscaling de pods no EKS orientado a eventos

Já encontramos o KEDA na seção anterior, como a peça que serve as métricas externas ao HPA. Agora vamos aprofundar. O KEDA (Kubernetes Event-Driven Autoscaling) é um projeto da CNCF que trabalha junto com o HPA, sem substituí-lo — foi ele que, no exemplo das três métricas, entregou o tamanho da fila. O que ainda não vimos é o que ele faz além de servir métricas: escala até zero quando não há eventos e traz o workload de volta quando eles chegam, algo que o HPA sozinho não faz. Os detalhes estão nos conceitos do KEDA .
Por isso, esse comportamento é especialmente útil para consumidores de filas e jobs em lote. Um consumidor que fica com 3 réplicas paradas a noite inteira à espera de mensagens passa a ficar com zero.

Exemplo: escalar um consumidor pelo tamanho de uma fila AWS SQS

O scaler aws-sqs-queue usa a profundidade de uma fila do AWS SQS . O parâmetro queueLength diz quantas mensagens cada pod consegue processar: se o alvo é 10 e a fila tem 30 mensagens, o KEDA escala para 3 pods.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
name: keda-aws-auth
namespace: pagamentos
spec:
podIdentity:
provider: aws # usa a identidade IAM configurada para o KEDA
---
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: consumidor-pedidos
namespace: pagamentos
spec:
scaleTargetRef:
name: consumidor-pedidos # Deployment que lê a fila
minReplicaCount: 0 # sem mensagens, nenhum pod
maxReplicaCount: 30
triggers:
- type: aws-sqs-queue
authenticationRef:
name: keda-aws-auth
metadata:
queueURL: https://sqs.us-east-1.amazonaws.com/111122223333/pedidos
queueLength: "10" # mensagens por pod
awsRegion: us-east-1
Por padrão, o KEDA conta as mensagens visíveis e as que estão em processamento. A identidade usada precisa de permissão de leitura dos atributos da fila. Veja os parâmetros e as opções de autenticação na documentação do scaler de SQS .

KEDA com métricas do Prometheus

O KEDA também escala por consultas PromQL. Um blog da AWS  mostra o KEDA escalando um microsserviço por requisições por segundo, uma métrica guardada no AWS Managed Service for Prometheus . Nesse padrão, o KEDA cria e alimenta o HPA por baixo, e os painéis do AWS Managed Grafana  mostram o escalonamento acontecendo.

KEDA e Karpenter juntos

O blog da AWS Brasil sobre KEDA e Karpenter  mostra o ciclo completo com uma fila SQS. À medida que a fila cresce, o KEDA cria novos pods; os pods que não cabem ficam pendentes, e o Karpenter provisiona os nós. Quando a fila esvazia, os pods saem e os nós ociosos são removidos. Além disso, num caso de produção mais recente , o time de tecnologia financeira das lojas da Amazon usa KEDA e Karpenter para escalar um banco analítico em picos de fechamento mensal, com centenas de usuários simultâneos.

VPA: quando ajustar o tamanho em vez do número de pods

O Vertical Pod Autoscaler, que vimos no post sobre application profiling e rightsizing, ajusta o tamanho de cada pod, e não o número de réplicas. Ele é útil em workloads que não escalam horizontalmente, como alguns bancos e serviços com estado, e para gerar recomendações de requests.
O ponto de atenção é a combinação com o HPA. O EKS Best Practices Guide sobre aplicações altamente disponíveis  recomenda não usar HPA e VPA na mesma métrica. Se o HPA escala por CPU e o VPA também ajusta a CPU, os dois reagem ao mesmo sinal e entram em conflito. Na prática:
  • Use o HPA para o número de réplicas;
  • Use o VPA em modo Off para gerar recomendações de requests e aplicá-las pelo seu pipeline;
  • Se precisar dos dois automáticos, faça o HPA escalar por uma métrica diferente, como requisições por segundo ou tamanho de fila.

Boas práticas de autoscaling de pods no EKS

  1. Faça o rightsizing antes. O HPA mede utilização como porcentagem do request; requests errados distorcem o autoscaling.
  2. Defina minReplicas pensando em disponibilidade. Em produção, pelo menos 2 réplicas, distribuídas entre zonas.
  3. Defina maxReplicas pensando no orçamento. O teto evita que um pico anômalo ou um erro escale a aplicação sem limite.
  4. Escolha a métrica certa. Para APIs, requisições por segundo ou latência costumam ser melhores que CPU. Para consumidores, o tamanho da fila.
  5. Controle o behavior. Suba rápido e desça devagar, para não remover pods no meio de uma oscilação.
  6. Prepare a aplicação para escalar. Readiness probes corretas, inicialização rápida e encerramento gracioso evitam erros durante o scale up e o scale down.
  7. Use PodDisruptionBudgets equilibrados. Eles protegem a aplicação, mas não podem impedir o autoscaler de nós de remover nós ociosos.
  8. Combine com o autoscaler de nós. Sem ele, os pods novos ficam pendentes e os nós vazios continuam na conta.

Por onde começar

Para colocar o autoscaling de pods no EKS em prática:
  1. Instale o Metrics Server como add-on do EKS.
  2. Comece pelos workloads com demanda variável, que aparecem na visibilidade de custos com grande diferença entre pico e vale.
  3. Crie um HPA por CPU com minReplicas, maxReplicas e behavior, e acompanhe por alguns dias.
  4. Troque para métricas de negócio onde a CPU não representa bem a carga, usando o KEDA ou um adaptador de métricas.
  5. Use o KEDA com minReplicaCount: 0 em consumidores de fila e workloads que podem ficar parados.

Checklist do post

  • O Metrics Server está instalado no cluster
  • Os workloads com HPA têm requests ajustados ao uso real
  • Todo HPA tem minReplicas, maxReplicas e behavior definidos
  • A métrica de escala representa a carga real da aplicação
  • Consumidores de fila e jobs avaliados para o KEDA com escala até zero
  • HPA e VPA não atuam na mesma métrica do mesmo workload
  • Readiness probes e encerramento gracioso estão configurados
  • Existe um autoscaler de nós para acompanhar o número de pods

Perguntas frequentes

Preciso instalar o HPA no EKS?

Não. O HPA é um recurso nativo do Kubernetes. Você só precisa de uma fonte de métricas, como o Metrics Server, que pode ser instalado como add-on do EKS.

Qual a diferença entre HPA e VPA?

O HPA muda o número de réplicas de um workload. O VPA muda o tamanho (requests e limits) de cada réplica. Eles resolvem problemas diferentes e não devem atuar na mesma métrica.

O KEDA substitui o HPA?

Não. O KEDA trabalha junto com o HPA: ele fornece métricas externas para o HPA e cuida da escala entre zero e uma réplica, que o HPA sozinho não faz.

Dá para escalar um deployment até zero no EKS?

Sim, com o KEDA e minReplicaCount: 0. Quando não há eventos, o KEDA remove todas as réplicas e as recria quando os eventos voltam.

Por que o meu HPA demora para escalar?

As causas mais comuns são requests de CPU acima do uso real, que fazem a utilização parecer baixa, e uma janela de estabilização longa demais. Também vale conferir se o Metrics Server está funcionando.

Próximo post

O autoscaling de pods decide quantos pods você precisa. Mas, se os nós não acompanharem, os pods novos ficam pendentes e os nós vazios continuam na conta. No próximo post da série, vamos comparar o Cluster Autoscaler e o Karpenter e mostrar como a consolidação de nós reduz o custo do cluster.

Series: Otimização de custos com AWS EKS (5 articles)

  1. …
  2. 4
    Autoscaling de pods no EKS: como escalar aplicações com HPA, KEDA e VPA This article
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article