AWS Builder Center

Autoscaling de nós no EKS: CAS e Karpenter para otimizar custo

Seu cluster AWS EKS mantém nós meio vazios ou demora minutos para escalar? Neste artigo, você vai comparar o Cluster Autoscaler e o Karpenter no EKS, entender como a consolidação remove e troca nós ociosos, configurar NodePools e disruption budgets e desligar ambientes fora do horário. Inclui exemplos em YAML, casos de clientes e um checklist.

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

  1. …
  2. 5
    Autoscaling de nós no EKS: CAS e Karpenter para otimizar custo This article
Solution Architect
No post sobre autoscaling de pods  no AWS EKS , vimos como o HPA e o KEDA ajustam o número de réplicas à demanda. Só que cada pod novo precisa de um nó para rodar, e cada pod removido pode deixar um nó AWS EC2  meio vazio. Se a capacidade de nós não acompanha os pods, o resultado é pod pendente no pico e nó ocioso — pelo qual você continua pagando — quando a demanda cai. Neste post, vamos comparar o Cluster Autoscaler e o Karpenter no EKS e ver como a consolidação de nós ataca exatamente esse desperdício.
 
Um post da série "Otimização de custos com AWS EKS".
 
Você vai entender como cada autoscaler de nós funciona e como configurar o Karpenter na API v1. Em seguida, vai ver como usar consolidação e disruption budgets com segurança e, por fim, como desligar ambientes fora do horário.

 

Dois jeitos de escalar nós

O EKS suporta dois autoscalers de nós principais, descritos na documentação de autoscaling do EKS . Os dois reagem a pods pendentes, mas trabalham de formas diferentes.

Cluster Autoscaler: escala grupos de nós

O Cluster Autoscaler (CAS) é um projeto da comunidade Kubernetes. Ele trabalha com node groups — conjuntos de nós EC2 gerenciados juntos, cada um apoiado por um Auto Scaling group do AWS EC2 Auto Scaling . Quando há pods pendentes, o CAS aumenta o número de nós de um grupo; quando há nós subutilizados, ele reduz.
No EKS, um node group pode ser de dois tipos:
 
  • Managed node groups : a AWS cuida do ciclo de vida dos nós — provisionamento, atualização da AMI e drenagem dos nós durante a atualização. É o caminho mais comum e com menos trabalho operacional.
  • Self-managed node groups : você mesmo cria e administra o Auto Scaling group dos nós. Dá mais controle sobre a configuração (AMI customizada, parâmetros do kubelet, bootstrap próprio) e, em troca, mais responsabilidade de manutenção.
 
Por isso, o CAS depende de um planejamento prévio:
  • Cada node group deve ter instâncias com o mesmo perfil de CPU e memória, porque o CAS assume que todos os nós do grupo são iguais ao simular o escalonamento. Isso não quer dizer um único tipo de instância: o grupo pode misturar famílias diferentes (por exemplo, m5, m5a e m5n), desde que todas tenham a mesma capacidade de CPU e memória.
  • Workloads diferentes (Spot, GPU, Graviton) costumam exigir node groups separados, e o número de grupos cresce rápido.
  • O CAS respeita o mínimo e o máximo de cada grupo e escolhe qual grupo escalar por meio de expanders. O EKS Best Practices Guide sobre o Cluster Autoscaler  sugere o least-waste como bom padrão.
 

Karpenter: provisiona o nó certo para os pods pendentes

O Karpenter é um projeto open source criado pela AWS que dispensa node groups. Ele parte dos pods pendentes e das restrições de agendamento (arquitetura, zona, tipo de capacidade) e provisiona a instância com a melhor relação custo-benefício para atendê-los — não um nó qualquer que caiba, mas o mais barato que caiba.
 
Segundo o FAQ do Karpenter , o processo tem três etapas:
  1. Agrupa os pods pendentes e faz o bin packing por CPU, memória e GPU, já descontando o overhead do nó, os recursos reservados pelo VPC CNI e os DaemonSets.
  2. Encontra o tipo mais eficiente — a menor instância em que o lote cabe — e reúne a ela outras 59 opções maiores, formando 60 tipos candidatos.
  3. Entrega os 60 tipos ao EC2 Fleet em modo instantâneo , que provisiona pela estratégia Price Capacity Optimized: para On-Demand, equivale ao menor preço; para Spot, o menor preço combinado com a menor chance de interrupção.
 
A diferença fica clara num exemplo. Imagine dois pods pendentes de tamanhos diferentes:
  • Com o CAS, cada node group só cria instâncias do seu próprio tipo. O resultado pode ser dois nós, um para cada pod.
  • Com o Karpenter, a decisão considera os dois pods juntos e escolhe o tipo mais barato que acomoda ambos. O resultado tende a ser um único nó do tamanho certo.
 
Além de escalar, o Karpenter também remove e troca nós continuamente, o que chamamos de consolidação. É aí que o Karpenter no EKS elimina boa parte da capacidade ociosa.
 
 
 
Cluster AutoscalerKarpenter
Unidade de escalaNode group (Auto Scaling group)Instância individual
Tipos de instânciaDefinidos por grupo, com o mesmo perfil (CPU e Memória)Escolhidos a cada provisionamento pelo menor preço, dentro das restrições do NodePool
Como lança a instânciaAjusta o desiredCapacity do ASG, que chama a API do EC2Chama a API do EC2 Fleet diretamente, sem ASG
Remoção de nósNós subutilizados do grupoConsolidação: remove nós vazios, junta pods e troca nós por opções mais baratas
ConfiguraçãoNode groups + parâmetros do CASNodePools e EC2NodeClasses

 

Karpenter no EKS na API v1

A API estável do Karpenter (v1) tem dois recursos principais, documentados no site do Karpenter :
  • NodePool (karpenter.sh/v1): define quais nós podem ser criados (tipos de instância, capacidade Spot ou On-Demand, arquitetura, zonas), os limites de recursos e as regras de disrupção.
  • EC2NodeClass  (karpenter.k8s.aws/v1): define como os nós são criados na AWS (AMI, sub-redes, security groups e a role do AWS IAM  dos nós).
⚠️ Se você tem manifestos antigos com Provisioner (karpenter.sh/v1alpha5), eles não funcionam mais. O anúncio do Karpenter 1.0 , de agosto de 2024, e o guia de migração explicam o caminho para NodePool e EC2NodeClass.
 

Exemplo: NodePool e EC2NodeClass

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
34
35
36
37
38
39
40
41
42
43
44
45
46
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: default
spec:
template:
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: default
requirements:
- key: karpenter.sh/capacity-type
operator: In
values: ["spot", "on-demand"] # Spot quando houver, On-Demand como alternativa
- key: kubernetes.io/arch
operator: In
values: ["amd64"] # arm64 só com imagens multi-arch (veja o próximo post)
- key: karpenter.k8s.aws/instance-category
operator: In
values: ["c", "m", "r"]
- key: karpenter.k8s.aws/instance-generation
operator: Gt
values: ["5"]
expireAfter: 720h # tempo máximo de vida do nó (padrão: 30 dias)
limits: # teto de capacidade do NodePool
cpu: "1000"
memory: 1000Gi
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 1m
---
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: default
spec:
role: KarpenterNodeRole-meu-cluster
amiSelectorTerms:
- alias: al2023@latest # em produção, fixe uma versão da AMI
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: meu-cluster
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: meu-cluster
Quanto mais tipos de instância o NodePool permite, mais opções o Karpenter tem para encontrar a combinação mais barata. Por isso, prefira requisitos por categoria e geração em vez de uma lista fechada de tipos. O blog da AWS sobre EC2 Spot com Karpenter  reforça esse ponto ao recomendar diversificar ao máximo os tipos — por categoria, tamanho e zona — para ampliar o leque de capacidade que o Karpenter pode escolher.

 

Consolidação: onde o Karpenter economiza

A consolidação é o recurso que mais diferencia o Karpenter no EKS: é o processo em que ele procura nós que podem sair do cluster. Segundo a documentação de disruption do Karpenter , ela acontece de três formas:
  1. Remover nós vazios, que não têm mais pods de workload.
  2. Remover nós subutilizados, quando os pods deles cabem na capacidade livre de outros nós.
  3. Substituir nós por uma opção mais barata, quando os pods cabem numa combinação de nós existentes com um nó menor.
Dois campos controlam esse comportamento:
  • consolidationPolicy: WhenEmptyOrUnderutilized considera nós vazios e subutilizados; WhenEmpty considera só os vazios. Desde a versão 1.14 (julho de 2026), há também Balanced, que compara o ganho de cada troca com a disrupção e pula as pouco vantajosas. O padrão continua WhenEmptyOrUnderutilized.
  • consolidateAfter: quanto tempo o Karpenter espera, depois que um pod é adicionado ou removido do nó, antes de considerá-lo para consolidação. O padrão é 0s.
 

Disruption budgets: consolidar sem susto

Consolidar significa drenar nós e recriar pods em outro lugar. Para controlar o ritmo, o NodePool aceita disruption budgets. Sem nenhum budget definido, o Karpenter limita a disrupção voluntária a 10% dos nós por vez. Você pode criar regras mais específicas por motivo (Empty, Underutilized, Drifted) e por horário:
1
2
3
4
5
6
7
8
9
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 1m
budgets:
- nodes: "10%" # regra geral
- nodes: "0" # sem consolidar nós em uso no horário comercial
schedule: "0 9 * * mon-fri"
duration: 8h
reasons: ["Underutilized", "Drifted"]
Os budgets não impedem a expiração de nós pelo expireAfter. Além disso, a documentação alerta que PodDisruptionBudgets mal configurados e a anotação karpenter.sh/do-not-disrupt podem travar a drenagem. Por isso, ao usar expireAfter, defina também um terminationGracePeriod.
 

PodDisruptionBudgets: proteja a aplicação durante a consolidação

Vale separar dois mecanismos de nomes parecidos. Os disruption budgets do NodePool, que acabamos de ver, limitam quantos nós o Karpenter mexe de uma vez — protegem o cluster. Já o PodDisruptionBudget (PDB) é um objeto do Kubernetes que a própria aplicação declara para garantir uma disponibilidade mínima de réplicas — protege o workload.
Quando o Karpenter consolida, ele drena nós, e drenar é uma disrupção voluntária. Antes de despejar um pod, o Kubernetes consulta o PDB da aplicação: nele você define quantas réplicas precisam continuar no ar (minAvailable) ou quantas podem sair ao mesmo tempo (maxUnavailable). Se remover aquele pod violasse o mínimo declarado, a drenagem espera até que outra réplica suba e fique pronta. Assim, a consolidação acontece aos poucos, sem levar a aplicação abaixo da capacidade de que ela precisa para atender tráfego.
É isso que torna o PDB essencial para usar o Karpenter com segurança: sem ele, uma consolidação poderia remover várias réplicas de uma vez e causar indisponibilidade; com ele, a economia da consolidação não custa a resiliência. O cuidado é calibrar o mínimo com folga — alto o bastante para proteger a aplicação, baixo o bastante para não travar a consolidação, como veremos a seguir. Para aprofundar, veja a documentação do Kubernetes sobre PodDisruptionBudgets  e o EKS Best Practices Guide sobre Karpenter .
 

O que bloqueia a consolidação

Na prática, porém, a consolidação costuma falhar por causa das aplicações, e não do Karpenter:
  • PodDisruptionBudgets restritivos demais. O EKS Best Practices Guide recomenda que o minAvailable fique abaixo do número de réplicas, com folga.
  • Uso excessivo de karpenter.sh/do-not-disrupt. Reserve a anotação para casos justificados e revise periodicamente quem a usa.
  • Topology spread constraints e anti-afinidade rígidas, que forçam pods a ficarem espalhados em mais nós do que o necessário.
  • Requests inflados, assunto do post sobre application profiling e rightsizing .

 

Casos reais

Stone: 35% de redução de custo com ajustes no Karpenter

Um blog da AWS Brasil , publicado em abril de 2026, mostra como a Stone reduziu em 35% o custo da infraestrutura da sua plataforma interna sobre o EKS. A redução veio de ajustes no Karpenter e nas aplicações. Entre os problemas encontrados:
  • O cluster criava muitos nós pequenos em vez de consolidar em nós maiores.
  • Regras de anti-afinidade e topology spread com maxSkew: 1 espalhavam pods mais do que o necessário.
  • O consolidateAfter que a Stone usava, de 10 minutos, era lento demais. Novos pods chegavam aos nós subutilizados antes da consolidação, e o timer recomeçava.
  • Sem preferência explícita por Spot, pods compatíveis com Spot ocupavam nós On-Demand e impediam a remoção deles.
💰 Preços de referência: outubro de 2026. A redução de 35% foi relatada pela Stone no blog da AWS Brasil de abril de 2026 e depende do ambiente e dos preços da época. Para estimar o impacto no seu cluster, use os valores atuais da página de preços do AWS EC2 .

Salesforce: do Cluster Autoscaler ao Karpenter em mais de mil clusters

Num blog de arquitetura de janeiro de 2026 , a AWS descreve a migração da Salesforce do Cluster Autoscaler para o Karpenter em mais de 1.000 clusters EKS. Antes, a necessidade de atender workloads diferentes tinha gerado milhares de node groups e Auto Scaling groups. Depois da migração, a latência de escala caiu de minutos para segundos. Além disso, o esforço operacional manual caiu 80%, com automação e autoatendimento para os times.

 

Downscaling fora do horário

Por outro lado, nem todo ambiente precisa ficar no ar o dia inteiro. Ambientes de desenvolvimento, homologação e ferramentas internas costumam ser usados só no horário comercial. Desligá-los à noite e no fim de semana é, portanto, uma das formas mais simples de cortar capacidade ociosa.
O caminho mais idiomático hoje é combinar o KEDA com o Karpenter:
  1. O scaler cron do KEDA  mantém as réplicas no horário de trabalho e, com minReplicaCount: 0, leva o deployment a zero fora dele.
  2. Sem pods, os nós ficam vazios, e a consolidação do Karpenter os remove.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: app-homologacao
namespace: homologacao
spec:
scaleTargetRef:
name: app
minReplicaCount: 0 # zero réplicas fora do horário
triggers:
- type: cron
metadata:
timezone: America/Sao_Paulo
start: 0 8 * * 1-5 # 8h, de segunda a sexta
end: 0 20 * * 1-5 # 20h, de segunda a sexta
desiredReplicas: "3"
Por padrão, a redução acontece cinco minutos depois do horário de fim, que é o cooldownPeriod do ScaledObject. Como alternativa para casos simples, o kube-downscaler original não é mais mantido, mas existe um fork ativo, o py-kube-downscaler .

 

Boas práticas de Karpenter no EKS

  1. Faça o rightsizing e o autoscaling de pods antes. O Karpenter provisiona pelos requests; requests inflados viram nós grandes demais.
  2. Dê flexibilidade ao NodePool do Karpenter. Quanto mais categorias, gerações e tamanhos de instância o NodePool permite, mais opções o Karpenter tem para empacotar os pods e escolher o nó mais barato — e, no caso de Spot, mais pools de capacidade para reduzir o risco de interrupção.
  3. Defina limits em cada NodePool, para que um erro de configuração não crie capacidade sem teto.
  4. Use consolidação com WhenEmptyOrUnderutilized, ou Balanced se quiser menos trocas de nós, e ajuste o consolidateAfter ao ritmo dos seus workloads.
  5. Proteja a produção com disruption budgets, por motivo e por horário.
  6. Revise PDBs, do-not-disrupt e topology spread, que costumam bloquear a consolidação.
  7. Configure expireAfter com terminationGracePeriod, para renovar os nós sem deixá-los presos.
  8. Separe NodePools só quando necessário, por exemplo, para GPU ou para isolar times, e use weight para definir prioridades.

 

Por onde começar

Para adotar o Karpenter no EKS com segurança:
  1. Instale o Karpenter seguindo o guia de primeiros passos do projeto ou o guia de migração a partir do Cluster Autoscaler .
  2. Crie um NodePool flexível, com limites e disruption budgets, e comece por um ambiente não produtivo.
  3. Mova os workloads aos poucos, reduzindo os node groups antigos e mantendo um grupo pequeno para o próprio Karpenter e os componentes críticos.
  4. Desligue o Cluster Autoscaler quando todos os workloads estiverem nos nós do Karpenter.
  5. Acompanhe a utilização dos nós e o custo ocioso na visibilidade de custos, para medir o efeito da consolidação.

Checklist do post

  • Nenhum manifesto usa Provisioner ou karpenter.sh/v1alpha5
  • Os NodePools permitem vários tipos e tamanhos de instância
  • Todo NodePool tem limits definidos
  • A consolidação está ativa, com consolidateAfter adequado
  • Existem disruption budgets para a produção
  • PDBs têm folga entre minAvailable e o número de réplicas
  • O uso de karpenter.sh/do-not-disrupt foi revisado
  • expireAfter e terminationGracePeriod estão configurados
  • Ambientes não produtivos são desligados fora do horário

 

Perguntas frequentes

Qual a diferença entre Cluster Autoscaler e Karpenter?

O Cluster Autoscaler aumenta ou diminui node groups com instâncias de mesmo perfil. O Karpenter cria diretamente a instância mais adequada para os pods pendentes e consolida continuamente os nós, removendo ou trocando os ociosos.

Se o Karpenter dispensa node groups, ainda preciso de algum?

Sim, de um pequeno. O Karpenter dispensa node groups para os nós de workload — as suas aplicações rodam em nós que ele provisiona diretamente. Mas o controlador do Karpenter (os pods do próprio Karpenter) precisa rodar em algum lugar que já exista antes de ele estar no ar; senão vira um problema de "ovo e galinha", em que o Karpenter teria de provisionar o nó em que ele mesmo roda. Por isso, o padrão é manter um node group de tamanho fixo (dois nós costumam bastar), sem Cluster Autoscaler — é só capacidade estática para o Karpenter e os componentes críticos, não um grupo que alguém fica escalando. Como alternativa, o Fargate roda o controlador sem nenhum nó para gerenciar. Todo o restante da capacidade fica a cargo do Karpenter.

O que é consolidação no Karpenter?

É o processo em que o Karpenter remove nós vazios, junta pods de nós subutilizados e troca nós por opções mais baratas, respeitando os disruption budgets e os PodDisruptionBudgets.

O Provisioner do Karpenter ainda funciona?

Não. Na API v1 do Karpenter, o Provisioner foi substituído pelo NodePool, e o AWSNodeTemplate pelo EC2NodeClass.

Posso usar o Cluster Autoscaler e o Karpenter ao mesmo tempo?

Durante a migração, sim, com cuidado para que os dois não disputem os mesmos pods. O guia de migração do Karpenter mostra como fazer a transição e desligar o Cluster Autoscaler no fim.

Como desligar um ambiente de homologação à noite?

Use o scaler cron do KEDA com minReplicaCount: 0 para levar os deployments a zero fora do horário. Em seguida, a consolidação do Karpenter remove os nós vazios.

 

Próximo post

Com o Karpenter escolhendo os nós, fica fácil trocar a arquitetura das instâncias. No próximo post da série, vamos falar de AWS Graviton no EKS: como montar clusters com arquitetura mista, criar imagens multi-arch e evitar a armadilha de subir um pod x86 num nó Arm.

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

  1. …
  2. 5
    Autoscaling de nós no EKS: CAS e Karpenter para otimizar custo 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