Karpenter v1.15.0 na prática: previsão de VPA, disrupção e provisionamento
Uma plataforma pode provisionar nodes corretamente e, ainda assim, produzir capacidade inadequada: requests subestimados, restrições de armazenamento e simulações diferentes do scheduler deixam pods pendentes ou provocam movimentações desnecessárias. A versão v1.15.0 do Karpenter, publicada em 10 de outubro de 2026, reúne mudanças nessas áreas e amplia a instrumentação de disrupções. O provider AWS também possui a release v1.15.0. (github.com)
O ponto mais importante: a previsão de VPA não está operacionalmente integrada nesta release. Embora exista uma implementação de controller e armazenamento de previsões, o registro desse controller foi removido antes do lançamento, enquanto a integração das previsões permanecia pendente. Atualizar para v1.15.0 não ativa provisionamento preditivo baseado em VPA. (github.com)
Este guia separa o que foi efetivamente entregue do que constitui preparação interna e propõe um roteiro de validação para produção.
1. Componentes e responsabilidades
No Karpenter, três objetos organizam a capacidade:
- NodePool: define requisitos e políticas para um conjunto de nodes.
- NodeClaim: representa uma solicitação individual de capacidade e acompanha seu ciclo de vida.
- EC2NodeClass: contém configurações específicas do provider AWS, como imagem, subnets, security groups e identidade dos nodes. Não substitui o NodePool. (karpenter.sh)
O Vertical Pod Autoscaler — VPA recomenda recursos para containers e pode aplicá-los conforme sua política. Ele não é instalado automaticamente pelo Karpenter. Sua configuração utiliza o recurso VerticalPodAutoscaler, disponibilizado por uma Custom Resource Definition — CRD — própria. (raw.githubusercontent.com)
O fluxo simplificado de provisionamento é:
Pod não escalonável → simulação do Karpenter → NodePool compatível → NodeClaim → provider → node registrado → kube-scheduler posiciona o pod
Requests, requisitos de posicionamento e overhead entram nessa decisão. O Karpenter fornece capacidade; o kube-scheduler continua responsável pelo binding dos pods. (karpenter.sh)
Requests também não são sinônimo de consumo: orientam o scheduling, enquanto limits restringem recursos em execução. CPU limitada pode sofrer throttling; memória acima do limite pode resultar em encerramento por falta de memória. (kubernetes.io)
2. Previsão de VPA: implementação não significa funcionalidade ativa
A mudança #3134 implementou o caminho de escrita: ler recomendações do VPA e armazenar requests previstos após redimensionamento. A intenção era permitir que decisões de consolidação considerassem futuros resizes. O próprio pull request separa esse trabalho do caminho de leitura, responsável por consumir as previsões nas decisões. (github.com)
Em 8 de outubro de 2026, a mudança #3383 removeu o registro do controller até que essa integração estivesse pronta. No código da tag v1.15.0, NewControllers não registra o controller de previsão de VPA. (github.com)
Consequências práticas para esta versão:
- Não existe um procedimento suportado neste guia para ativar previsão de VPA no Karpenter.
- Não adicione flags ou campos imaginários ao NodePool.
- Uma recomendação em
status.recommendationnão equivale a um request aplicado. - O VPA pode continuar sendo utilizado separadamente para right sizing; isso não comprova integração preditiva com o Karpenter. (raw.githubusercontent.com)
Exemplo hipotético de capacidade
Considere 12 workers, cada um com request de memória de 512Mi. Uma recomendação de 1Gi por worker representaria 6Gi adicionais de requests se aplicada a todos. Esse cálculo não inclui overhead, fragmentação, zonas ou restrições de volumes.
A recomendação é uma entrada para planejamento, não uma reserva antecipada criada pelo Karpenter v1.15.0. Minha recomendação operacional é validar o novo tamanho sob carga e aplicá-lo gradualmente, observando capacidade disponível e tempo de recuperação.
3. Mudanças que realmente afetam o provisionamento
Limites de volumes antes do lançamento
A mudança #3202 permite que providers informem limites esperados de volumes por driver Container Storage Interface — CSI — nos tipos de instância. A simulação passa a considerar esses limites antes de existir um CSINode; após o registro, a informação do CSINode prevalece. Providers que não informam esses limites não recebem automaticamente esse benefício. (github.com)
Para testar, proponho um lote de pods com PersistentVolumeClaims — PVCs — equivalente ao perfil real da aplicação. Compare quantos ficam pendentes depois do primeiro provisionamento, sem assumir que CPU e memória são os únicos limitadores.
Topologia padrão do scheduler
A mudança #3205 adiciona --scheduler-config, também configurável por SCHEDULER_CONFIG, para informar podTopologySpread.defaultConstraints à simulação. Não é descoberta automática da configuração do kube-scheduler. Quando a configuração está vazia, o comportamento permanece inalterado. (github.com)
Minha preferência é declarar restrições importantes no próprio workload e testar sua compatibilidade com os NodePools. Em Amazon EKS, não presuma acesso irrestrito à configuração do scheduler gerenciado.
Falta de capacidade visível no pod
Falhas de lançamento por capacidade insuficiente passam a gerar o evento InsufficientCapacityError nos pods nominados para o NodeClaim afetado. Isso aproxima a investigação de quem opera a aplicação, sem depender exclusivamente dos logs do controller. (github.com)
4. Configuração prática com dependências explícitas
O exemplo pressupõe:
- Karpenter e suas CRDs compatíveis instalados;
- um
EC2NodeClasschamadoproduction, já validado; - namespace
productione Deploymentorders-workerexistentes; - VPA instalado separadamente, com recommender e fonte de métricas funcionais;
- pods do worker selecionando
karpenter.sh/nodepool: apps-ondemand.
Os valores abaixo são didáticos e devem passar por revisão de capacidade e disponibilidade.
NodePool conservador para o primeiro teste
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: apps-ondemand
spec:
template:
metadata:
labels:
workload-tier: application
spec:
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: production
requirements:
- key: kubernetes.io/os
operator: In
values: [linux]
- key: kubernetes.io/arch
operator: In
values: [amd64]
- key: karpenter.sh/capacity-type
operator: In
values: [on-demand]
expireAfter: 720h
limits:
cpu: "200"
memory: 800Gi
disruption:
consolidationPolicy: WhenEmptyOrUnderutilized
consolidateAfter: 5m
budgets:
- nodes: "1"Esse NodePool restringe arquitetura e modalidade de compra, referencia a configuração AWS existente e limita recursos provisionados. consolidateAfter controla a espera após mudanças de pods; não estabelece intervalo mínimo global entre todas as disrupções. Os limites do NodePool não são um teto financeiro rígido e podem ser ultrapassados temporariamente durante provisionamento concorrente. (karpenter.sh)
O budget de um node restringe disrupções sujeitas a budgets; não impede interrupções externas nem transforma expiração em operação sem risco. expireAfter: 720h deve ser tratado como política de manutenção. A omissão de terminationGracePeriod também exige atenção a drains bloqueados. (karpenter.sh)
Para produção, proponho começar com On-Demand para isolar o teste. Depois, avalie Spot em pools e workloads adequados, sem interpretar este exemplo como política universal de compra.
VPA somente para recomendações
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: orders-worker
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: orders-worker
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: worker
controlledResources: [cpu, memory]
minAllowed:
cpu: 250m
memory: 256Mi
maxAllowed:
cpu: "2"
memory: 2GiOff mantém recomendações sem alterar recursos dos pods. targetRef deve apontar para o Deployment real, e containerName precisa corresponder ao container existente. Os limites da política balizam recomendações; não substituem resources.limits. Essa configuração não ativa previsão no Karpenter. (raw.githubusercontent.com)
Proteção do workload durante evictions
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: orders-worker
namespace: production
spec:
maxUnavailable: 1
selector:
matchLabels:
app: orders-workerO PodDisruptionBudget — PDB — limita indisponibilidade considerada pela API de eviction para pods selecionados. Neste cenário, proponho pelo menos três réplicas saudáveis e labels consistentes. O PDB não garante sobrevivência a falhas de zona e não substitui a estratégia de rollout do Deployment. (kubernetes.io)
Configure também readiness, liveness e, quando necessário, startup probes de acordo com o comportamento da aplicação. Readiness controla prontidão para tráfego; liveness não deve reiniciar workers apenas porque uma dependência externa está temporariamente indisponível. (kubernetes.io)
5. Métricas de disrupção: decisão não é indisponibilidade
Há uma armadilha no changelog: o título da mudança inicial menciona karpenter_pods_disrupted_total, mas o código entregue utiliza `karpenter_pods_disruption_initiated_total`. Esse contador soma pods reagendáveis quando a disrupção do NodeClaim é iniciada, excluindo DaemonSets e mirror pods. karpenter_nodeclaims_disrupted_total contabiliza NodeClaims, não pods. (github.com)
As dimensões novas consolidation_policy e termination_mode permitem separar política e modo de término. O segundo deriva do terminationGracePeriod: ausente resulta em graceful; positivo, em eventual; zero, em forceful. Não interprete eventual como evidência de que ocorreu uma exclusão forçada específica. (github.com)
Para observar o início de disrupções por pool e motivo:
sum by (nodepool, reason) (
increase(karpenter_pods_disruption_initiated_total[1h])
)Para comparar contextos operacionais:
sum by (nodepool, consolidation_policy, termination_mode) (
increase(karpenter_nodeclaims_disrupted_total[1h])
)Essas consultas usam contadores existentes na tag v1.15.0. Ajuste o escopo por cluster conforme os labels da sua coleta. Não some métricas de decisão, início e drain como se fossem eventos independentes de impacto. (raw.githubusercontent.com)
increase compensa resets de contadores e extrapola a janela, podendo produzir valores fracionários. Série ausente não é necessariamente zero: valide a coleta antes de preencher lacunas artificialmente. (prometheus.io)
Outros sinais úteis são karpenter_pods_drained_total, karpenter_pods_eviction_requests_total e karpenter_voluntary_disruption_queue_failures_total. As métricas de pods citadas têm estabilidade alpha; revise seus contratos em upgrades. (karpenter.sh)
Proponho um dashboard com quatro perspectivas: capacidade criada, movimentação de workloads, pods pendentes e saúde da aplicação. Correlacione eventos com latência, erros, throughput, reinicializações e profundidade da fila. Para alertas, priorize degradação sustentada do objetivo de nível de serviço — SLO — em vez de alertar sobre toda consolidação.
6. Cenário corporativo: workers com demanda variável
Problema: uma equipe observa backlog crescente e movimentações frequentes de workers durante campanhas.
Solução proposta: separar investigação de recursos, alteração de requests e política de consolidação.
Implementação:
- Registrar baseline de backlog, consumo, requests, latência e disrupções.
- Executar VPA em modo
Offdurante uma janela representativa. - Revisar recomendações junto com limites de concorrência e connection pooling.
- Aplicar requests em um grupo controlado de workers.
- Comparar comportamento antes de modificar budgets ou modalidade de compra.
Resultado esperado, não benchmark: descobrir se o gargalo é CPU, memória, banco de dados, fila ou capacidade de nodes, mantendo rastreabilidade das mudanças. Nenhum percentual de economia ou redução de incidentes é presumido.
7. Produção, segurança e FinOps
Minha proposta de arquitetura utiliza capacidade estável para controllers críticos e capacidade elástica para aplicações. Para Spot, configure o tratamento de interrupções e mantenha diversidade de tipos de instância e zonas compatíveis. A AWS recomenda evitar dependência do próprio Karpenter para hospedar toda a capacidade necessária ao seu funcionamento. (docs.aws.amazon.com)
Para alta disponibilidade, distribua réplicas entre nodes e zonas. Restrições rígidas podem preservar isolamento, mas também impedir scheduling quando falta capacidade; valide esse trade-off em testes de falha. (kubernetes.io)
Como checklist de segurança, proponho:
- controle de acesso baseado em papéis — RBAC — mínimo para operadores e automações;
- identidades AWS de workload, como IAM Roles for Service Accounts — IRSA — ou EKS Pod Identity, conforme a instalação validada;
- nenhuma credencial permanente em manifests;
- métricas privadas, NetworkPolicies compatíveis com o plugin de rede e TLS nos pontos necessários;
- imagens verificadas, Secrets protegidos e rotação documentada. (kubernetes.io)
Para FinOps, avalie custo por trabalho concluído e não apenas quantidade de nodes. Inclua armazenamento, rede entre zonas, load balancers e retenção de observabilidade na análise. Minha recomendação é aprovar economia somente quando acompanhada de estabilidade do SLO e de recuperação satisfatória nos testes.
Em desenvolvimento, uma réplica e menor redundância podem simplificar experimentos. Em produção, estabeleça critérios explícitos para réplicas, probes, recursos, alertas e rollback. Para dados persistentes, inclua backups e ensaios de restauração; autoscaling não deve ser usado como substituto de recuperação de dados.
8. Upgrade e rollback
A v1.15.0 também altera o Node Auto Repair, quando habilitado, para o caminho de disrupção voluntária. A API acrescenta Unhealthy aos motivos de budget. Atualize CRDs junto com o controller e não suponha que um upgrade do chart principal atualize automaticamente CRDs previamente instaladas. (karpenter.sh)
Antes da mudança, proponho registrar configuração e versão:
kubectl -n kube-system get deployment karpenter -o yaml
kubectl get nodepools -o yaml
kubectl get ec2nodeclasses -o yaml
kubectl get nodeclaims
helm list -A
helm show chart oci://public.ecr.aws/karpenter/karpenter --version 1.15.0Adapte namespace e nome da instalação. Salve os resultados no processo de change management, sem publicar informações sensíveis.
Revise dashboards: valores de reason foram padronizados em minúsculas; em karpenter_voluntary_disruption_queue_failures_total, consolidation_type passa a representar tipos como empty, single e multi, não decisões como delete. (github.com)
Meu roteiro de homologação inclui provisionar capacidade nova, substituir um node, testar eviction bloqueada e validar alertas. Para rollback, mantenha charts, values e manifests anteriores, verificando compatibilidade das CRDs. Não exclua CRDs nem remova finalizers como procedimento normal de reversão.
9. Troubleshooting
VPA recomenda mais memória, mas nada muda
Sintoma → recomendações aparecem, requests permanecem iguais.
Possível causa → updateMode: Off, comportamento deliberado.
Investigação → compare configuração e status:
kubectl -n production get vpa orders-worker -o yaml
kubectl -n production get deployment orders-worker -o yamlCorreção → aplique requests revisados pelo processo de entrega ou avalie um modo de atualização suportado pela sua versão do VPA. Não procure ativar a integração preditiva ausente no Karpenter v1.15.0. (raw.githubusercontent.com)
Pods pendentes com capacidade insuficiente
Sintoma → pods não iniciam.
Possível causa → indisponibilidade na combinação de tipo de instância e zona.
Investigação → examine eventos, NodeClaims e logs:
kubectl get pods -A
kubectl get nodes
kubectl get nodeclaims
kubectl -n production describe pod <pod>
kubectl get events -A --sort-by=.metadata.creationTimestamp
kubectl -n kube-system logs deployment/karpenter --since=30mCorreção → quando o evento confirmar InsufficientCapacityError, amplie opções compatíveis de capacidade. Não remova requisitos obrigatórios de segurança ou arquitetura apenas para obter scheduling. (github.com)
Node não consolida
Sintoma → capacidade aparentemente ociosa permanece.
Possível causa → PDB, budget, proteção contra disrupção ou restrições de reposicionamento.
Investigação → examine condições e eventos:
kubectl get pdb -A
kubectl describe nodepool apps-ondemand
kubectl describe nodeclaim <nodeclaim>Correção → ajuste a restrição responsável com aprovação do dono do workload; não elimine proteções indiscriminadamente. (karpenter.sh)
10. Quando utilizar e alternativas
Minha recomendação é adotar Karpenter quando a flexibilidade de capacidade justificar a operação de políticas, observabilidade e testes de disrupção. Para uma equipe pequena com carga estável, um desenho mais simples pode ser preferível.
No Amazon EKS, managed node groups com Cluster Autoscaler constituem uma alternativa baseada em grupos de capacidade. Karpenter oferece outro modelo de seleção e provisionamento; não é necessário migrar apenas para acompanhar uma release. VPA é complementar ao dimensionamento de nodes, não uma alternativa direta a ele. (docs.aws.amazon.com)
Resumo prático
- Não trate código de previsão de VPA como integração ativa na v1.15.0.
- Valide requests antes de aumentar agressividade de consolidação.
- Meça impacto na aplicação, não apenas eventos do controller.
- Teste armazenamento, topologia e capacidade insuficiente.
- Atualize observabilidade, CRDs e plano de reversão junto com o controller.
Conclusão
Para DevOps, SRE e Platform Engineering, a decisão relevante não é simplesmente instalar uma versão nova: é estabelecer quais comportamentos estão disponíveis, quais sinais comprovam seu funcionamento e quais limites protegem a aplicação.
A estratégia proposta é incremental: recomendações primeiro, alterações controladas depois e otimização somente com evidência operacional. Isso transforma o autoscaling em uma capacidade governada da plataforma, em vez de uma automação cujo efeito só aparece durante um incidente.
Artigos relacionados
Quer aplicar isso no seu ambiente?
Agende uma conversa de 30 minutos sem compromisso. Eu olho o seu cenário e digo por onde começar.
Agendar uma conversaReceba os novos artigos por e-mail
Um e-mail quando sair artigo novo sobre infraestrutura, backend e IA. Sem spam, cancele quando quiser.