Kubernetes 1.37 acaba com o resize de pod travado em estado Deferred
Novo recurso alpha deixa o scheduler despejar workloads de baixa prioridade para liberar CPU e memória e concluir o resize in-place de pods críticos sem restart.

O in-place pod resize chegou a GA no Kubernetes↳Kubernetes18 conteúdosGerenciamento de infraestrutura multicloud com Kubernetes proporciona otimização e economiaDevSecOps · set 2021Azure Kubernetes Services – AKS: referências gratuitas e dicas para solução de problemas comunsDevSecOps · abr 2019Kubernetes em produção: o que ninguém te conta e você aprende tarde demaisDev (Back & Front) · abr 2026Ver tudo em DevSecOps → v1.35, permitindo ajustar CPU e memória de containers em execução sem reiniciar o pod. Bom para quem roda banco em memória, servidor web ou qualquer coisa que não pode piscar. Mas ele nasceu com um buraco: se o nó não tinha folga (allocatable headroom) para acomodar o aumento, o Kubelet marcava o pedido como Deferred e o pod ficava parado, esperando o nó liberar espaço por conta própria. Podia esperar para sempre.
O Kubernetes v1.37, segundo anúncio no blog oficial, fecha essa lacuna com o scheduler preemption for in-place pod resize, em alpha atrás da feature gate InPlacePodVerticalScalingSchedulerPreemption. A ideia: quando um pod de alta prioridade precisa crescer e o nó está cheio, o scheduler despeja pods de menor prioridade daquele mesmo nó para abrir espaço, e o resize acontece sem restart.
O problema do Deferred na prática
Quando um controlador (o Vertical Pod Autoscaler, por exemplo) sobe o requests de um container ativo, o Kubelet checa se o nó tem capacidade alocável sobrando. Se não tem, o resizeStatus em status.containerStatuses[] vira Deferred. Vale distinguir de Infeasible: Infeasible é rejeição imediata porque o pedido estoura os limites físicos da máquina, o LimitRange do namespace ou a quota de admissão. Deferred é um pedido válido que só não pode ser executado agora.
O detalhe cruel é que, antes desse recurso, o Deferred podia ser permanente. Uma aplicação crítica prestes a levar OOM ficava presa esperando, e o operador tinha três saídas, todas ruins: despejar pods de baixa prioridade na mão, confiar no cluster autoscaler para subir um nó maior (o que reagenda o pod e viola a própria promessa de "sem restart") ou escrever um autoscaler customizado que redimensiona o nó. O kube-scheduler simplesmente não enxergava resizes deferidos em pods já rodando, então não podia usar a preemption por prioridade que ele já sabe fazer no agendamento inicial.
Para o time de SRE, esse era um dilema clássico de densidade contra confiabilidade. Encher os nós com jobs em batch e tarefas best-effort (o famoso bin-packing) melhora a utilização e corta custo, mas transforma a folga que a carga crítica precisaria em risco. Ou o cluster rodava com buffer ocioso, ou a aplicação importante ficava sem espaço para escalar num pico de tráfego. Não dava para ter os dois.
Como o scheduler passa a agir
A mecânica se integra ao ciclo normal de agendamento. Normalmente, pod com spec.nodeName preenchido é considerado colocado e não volta para a fila ativa. Com a feature gate ligada, o scheduler intercepta pods que carregam a condição Deferred e os mantém em avaliação ativa justamente para disparar a preemption, acompanhando cada um até o Kubelet concluir o resize.
Alguns pontos de arquitetura que mudam o comportamento e importam na hora de operar:
- Preemption presa ao nó. Diferente da preemption de colocação, que varre o cluster inteiro atrás do melhor encaixe, aqui a busca por "vítimas" é restrita ao nó onde o pod deferido já roda. Se, mesmo despejando todos os pods elegíveis de baixa prioridade daquele nó, ainda faltar capacidade, o resize continua
Deferred. Não há migração para outro nó. - Reserva de recurso. Para evitar corrida e dupla alocação, o scheduler trata o recurso pedido no resize como já consumido, o que dá ao Kubelet a garantia de executar assim que a preemption libera espaço.
- Separação de responsabilidades. O Kubelet tem um
critical Pod admission handlerque, na admissão, pode despejar pods localmente para garantir carga crítica. Com a feature gate ligada, esse handler não faz mais preemption local para operações de resize: ele defere e delega a decisão inteiramente ao scheduler. Um único orquestrador centralizado passa a mandar em toda a lógica de preemption de resize, respeitando prioridades globais, Pod Disruption Budgets e terminação graciosa. - Corridas entre resizes. Se, durante um ciclo ativo de preemption, chega um pedido de resize de prioridade ainda maior para outro pod do mesmo nó, o Kubelet prioriza esse pedido e o scheduler dispara uma nova rodada de preemption se precisar de mais capacidade.
Há também um freio no nível do nó. Um novo campo spec.podPreemptionPolicy no Node permite desligar a preemption de resize para nós específicos:
apiVersion: v1
kind: Node
metadata:
name: batch-workload-node
spec:
podPreemptionPolicy:
disableResizePreemption:
- "cluster-autoscaler.kubernetes.io/disable-preemption"
- "operator.example.com/policy-override"O caso de uso citado no blog é o de um controlador que prefere reduzir outros pods ou ajustar a capacidade do nó por conta própria, deixando a preemption do scheduler como último recurso. Faz sentido: despejar carga é a solução mais barata em latência, mas a mais violenta em disrupção. Ter o botão para desligá-la em nós de batch é o tipo de trade-off explícito que evita surpresa.
Vendo funcionar num kind local
A fonte traz um mini-tutorial reproduzível num cluster kind de nó único com CPU limitada. O gate liga na criação do cluster:
# kind-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
InPlacePodVerticalScalingSchedulerPreemption: truekind create cluster --config kind-config.yaml --image kindest/node:v1.37.0O nó de exemplo expõe 8 CPUs alocáveis. O roteiro cria duas PriorityClass (high-priority com valor 1000000 e low-priority com 1000), sobe um pod de baixa prioridade pedindo 3 CPUs e um de alta pedindo 4, consumindo 7 das 8 CPUs e deixando 1 de folga. Aí vem o teste: um patch sobe o requests/limits do pod de alta de 4 para 6 CPUs, um delta de +2 que não cabe na folga de 1.
kubectl patch pod high-priority-pod --subresource resize --patch \
'{"spec":{"containers":[{"name":"app", "resources":{"requests":{"cpu":"6"}, "limits":{"cpu":"6"}}}]}}'O ciclo de eventos conta a história inteira. No pod de baixa prioridade aparece um Preempted seguido de Killing. No de alta, a sequência ResizeDeferred (com o erro OutOfcpu: Node didn't have enough resource: cpu, requested: 6000, used: 3950, capacity: 8000), depois ResizeStarted quando a capacidade é liberada e, por fim, ResizeCompleted. A confirmação:
kubectl get pod high-priority-pod -o jsonpath='{.status.containerStatuses[0].allocatedResources.cpu}{"\n"}'
# 6O container passou de 4 para 6 CPUs atualizando os limites de cgroup via container runtime, sem reiniciar. Esse é o ponto: o ResizeCompleted sem RESTARTS incrementado é o que separa esse recurso de um reagendamento comum.
O que muda para quem opera cluster no Brasil
Na prática, a leitura é que dá para empurrar o bin-packing mais longe com menos medo. Preencher a folga dos nós com batch, processamento em background e tarefas best-effort deixa de ser uma aposta contra o pico da carga crítica, porque o scheduler agora tem como reabrir espaço quando essa carga precisa crescer. Para quem paga a conta de nós ociosos só para manter buffer (e no câmbio de cloud isso pesa), a promessa é utilização mais alta sem sacrificar a resposta das aplicações sensíveis.
Dito isso, é alpha, e alpha não vai para produção. A feature gate precisa estar ligada em kube-apiserver, kube-scheduler e kubelet, control plane e todos os workers em v1.37 ou superior. Vale entender bem o comportamento antes de confiar: como a preemption é presa ao nó, um resize pode continuar Deferred mesmo com o cluster tendo espaço em outro lugar, e é preciso ter certeza de que os PDBs e as prioridades estão configurados de forma que a carga despejada seja mesmo descartável. A régua continua a mesma: se não dá para medir o efeito da preemption e reverter o comportamento (pelo spec.podPreemptionPolicy), não vai para o cluster que importa. O caminho sensato é o que o próprio SIG Scheduling pede: ligar em ambiente de teste, observar os eventos e dar feedback antes de qualquer plano de produção.
Fonte: Kubernetes Blog
Este artigo foi escrito por Rafael Oliveira, colunista de DevOps. Conteúdo produzido por agente de IA da redação iMasters, sob revisão editorial humana. Saiba como produzimos no expediente.
Kubernetes 1.37 leva o modo rootless para beta e muda o jogo da segurança no nó
Com o feature gate KubeletInUserNamespace habilitado por padrão, kubelet, runtime, CNI e kube-proxy podem rodar como usuário comum, confinando o estrago de um container breakout à conta não-root.







Alex Hinckel





