Kubernetes 5 Jun 2026 12 min read

Como Reduzimos 40% dos Custos no EKS com Karpenter e Spot Instances

Quando operamos clusters Kubernetes em produção com dezenas de workloads, o custo de compute rapidamente se torna o maior item na fatura da AWS. Neste artigo, compartilho a experiência da migração do Cluster Autoscaler para o Karpenter, combinando spot instances, consolidation policies e right-sizing para otimizar FinOps sem sacrificar a confiabilidade dos nossos serviços.

O Problema: Cluster Autoscaler e Node Groups Estáticos

O Cluster Autoscaler funciona bem para cenários simples, mas apresenta limitações significativas quando o cluster precisa escalar de forma heterogênea. Com node groups estáticos, acabávamos com nodes superdimensionados para a maioria dos pods, desperdiçando recursos e aumentando custos desnecessariamente.

Nosso cluster rodava 47 microserviços com requisitos variados de CPU e memória. Alguns precisavam de instâncias compute-optimized (c6i), outros de memory-optimized (r6i), e muitos poderiam rodar em instâncias general purpose (m6i). O Cluster Autoscaler não conseguia fazer essa distinção de forma eficiente, resultando em over-provisioning constante.

Além disso, a latência de scaling era um problema recorrente. Em picos de tráfego, novos nodes levavam entre 3 a 5 minutos para ficarem prontos, causando throttling nos HPAs e degradação de performance para os usuários finais.

Karpenter: A Abordagem Just-in-Time

O Karpenter resolve esses problemas com uma abordagem fundamentalmente diferente. Em vez de depender de Auto Scaling Groups pré-configurados, ele provisiona nodes diretamente via EC2 Fleet API, escolhendo o tipo de instância ideal para cada pod pendente.

O Karpenter não escala node groups — ele escala a capacidade computacional de forma granular, escolhendo o tipo certo de instância para cada workload.

A configuração básica de um NodePool no Karpenter v1 é declarativa e expressiva. Definimos constraints como instance families, availability zones, capacity types e limites de recursos, e o Karpenter toma decisões inteligentes de placement.

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: default
spec:
  template:
    spec:
      requirements:
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["spot", "on-demand"]
        - key: node.kubernetes.io/instance-type
          operator: In
          values: ["m6i.large", "m6i.xlarge", "c6i.large", "c6i.xlarge"]
      nodeClassRef:
        group: karpenter.k8s.aws
        kind: EC2NodeClass
        name: default
  limits:
    cpu: "1000"
    memory: 2000Gi
  disruption:
    consolidationPolicy: WhenEmptyOrUnderutilized
    consolidateAfter: 60s

Spot Instances: O Multiplicador de Economia

Spot instances oferecem desconto de 60-90% em relação a on-demand, mas com o risco de interrupção com aviso de 2 minutos. A chave para usar spot em produção é diversificação e graceful handling.

Configuramos o Karpenter para priorizar spot com fallback para on-demand. A diversificação entre múltiplas instance families e availability zones minimiza o risco de interrupção simultânea. Nosso Spot Interruption Handler (baseado no AWS Node Termination Handler) garante que pods sejam drenados gracefully antes da terminação.

Na prática, observamos uma taxa de interrupção de apenas 3.2% ao mês, e nenhuma dessas interrupções resultou em impacto visível para os usuários, graças ao pod disruption budgets e à redundância multi-AZ.

Consolidation: Eliminando Waste Automaticamente

Uma das features mais poderosas do Karpenter é a consolidation automática. Quando nodes ficam subutilizados — por exemplo, após um scale-down de pods — o Karpenter automaticamente move os pods remanescentes para outros nodes e termina os nodes vazios.

A consolidation policy WhenEmptyOrUnderutilized verifica continuamente se existem nodes que podem ser eliminados ou substituídos por instâncias menores. Isso resolve o problema clássico de "nodes fantasma" que ficam rodando com 10% de utilização após picos de tráfego.

Nosso cluster passou de uma utilização média de CPU de 34% para 72% após habilitar consolidation, sem nenhum impacto na disponibilidade dos serviços. Isso representa uma redução significativa de waste computacional.

Métricas de Antes e Depois

Após 3 meses de operação com Karpenter em produção, comparamos os números com o período equivalente usando Cluster Autoscaler:

  • Custo mensal de compute: redução de 41.3% ($47,200 → $27,700)
  • Utilização média de CPU: 34% → 72%
  • Tempo médio de scaling: 4.2min → 1.1min
  • Número médio de nodes: 89 → 52
  • Incidentes de capacity: 7/mês → 0/mês

Right-Sizing com VPA e Goldilocks

A economia não veio só do Karpenter. Implementamos o Vertical Pod Autoscaler (VPA) em modo recommendation-only junto com o Goldilocks dashboard para identificar pods over-provisioned.

Descobrimos que 63% dos nossos deployments tinham requests de memória 2-4x acima do necessário — herança de configurações "safe" feitas durante incidentes passados que nunca foram revisitadas. Ajustar os requests permitiu que o Karpenter escolhesse instâncias menores e fizesse melhor bin-packing.

Lições Aprendidas

A migração não foi sem desafios. Compartilho aqui os principais aprendizados que podem ajudar quem está considerando a mesma jornada:

  1. Comece com workloads stateless: Migre primeiro os serviços que toleram interrupção. Deixe databases e stateful workloads em on-demand até ganhar confiança.
  2. Pod Disruption Budgets são obrigatórios: Sem PDBs configurados corretamente, a consolidation do Karpenter pode causar downtime ao mover pods agressivamente.
  3. Monitore Spot Interruption Rates por instance family: Algumas families têm taxa de interrupção muito maior. Use o Spot Placement Score para fazer escolhas informadas.
  4. Teste consolidation em staging primeiro: A consolidation agressiva pode conflitar com pod anti-affinity rules e topology spread constraints. Valide antes de produção.
  5. Dashboards de FinOps são essenciais: Sem visibilidade, é impossível medir o impacto. Usamos Kubecost integrado com Grafana para tracking granular por namespace e team.

Conclusão

A combinação de Karpenter + Spot Instances + Consolidation + Right-Sizing nos permitiu reduzir custos em mais de 40% mantendo — e em alguns casos melhorando — a confiabilidade e performance dos nossos serviços. O investimento de 3 sprints na migração se pagou em menos de 2 meses de operação.

Se sua organização opera clusters EKS com mais de 20 nodes e ainda usa Cluster Autoscaler com node groups estáticos, a migração para Karpenter deveria estar no topo do seu backlog de platform engineering. Os ganhos de FinOps e operational efficiency justificam amplamente o esforço.

No próximo artigo, vou detalhar como configuramos alertas proativos de drift de custo usando Kubecost + Prometheus + AlertManager, com runbooks automatizados para investigação. Stay tuned.