Dev & EngARTIGO

Kubernetes vai impedir kubelet de iniciar em nós com cgroup v1 a partir da versão 1.35

Post do blog oficial do Kubernetes, publicado em 6 de outubro, detalha o calendário de depreciação do cgroup v1: a partir da versão 1.35 o kubelet simplesmente não sobe em nós que ainda usam o modelo antigo, a menos que alguém force um override temporário.

Kubernetes vai impedir kubelet de iniciar em nós com cgroup v1 a partir da versão 1.35
Imagem gerada por IA

Depreciar um recurso do 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 → raramente é evento único: é um processo que se arrasta por várias minor releases até virar bloqueio de verdade. É o caso do cgroup v1. Um post do blog oficial do Kubernetes, assinado por Paco Xu (DaoCloud) e publicado nesta terça-feira (6 de outubro), reúne o estado atual dessa transição, e o ponto que merece atenção de quem opera cluster em produção é concreto: a partir da versão 1.35, o kubelet não inicia em um nó Linux que ainda rode cgroup v1, a menos que alguém configure explicitamente um override.

A linha do tempo que já está em curso

cgroup v2 não é novidade: tornou-se suporte estável no Kubernetes desde a versão 1.25. O que mudou foi o tratamento dado ao v1. Na versão 1.31, o suporte a cgroup v1 entrou em modo de manutenção, o que na prática significa que o projeto para de investir em melhorias e passa a tratar o v1 como legado. A partir da versão 1.35 (já lançada), a flag failCgroupV1 passa a valer true por padrão, e é aqui que o breaking change aparece de fato: sem esse nó estar em cgroup v2, o kubelet falha ao subir.

Quem opera via kubeadm sente o bloqueio ainda mais cedo. A partir da 1.35, o preflight check SystemVerification (do pacote k8s.io/system-validators) passa a retornar erro, não apenas aviso, quando detecta cgroup v1 combinado com kubelet 1.35 ou mais recente, durante kubeadm init, kubeadm join e kubeadm upgrade. Com um kubelet mais antigo, o check continua sendo só um aviso. A remoção completa do fallback está marcada para a versão 1.38 e é acompanhada pela KEP-5573.

Em resumo: se seu cluster roda hoje numa versão anterior à 1.35, a migração dos nós Linux para cgroup v2 precisa acontecer antes do upgrade, ou alguém vai ter que setar failCgroupV1: false no arquivo de configuração do kubelet como paliativo temporário, sabendo que esse paliativo também tem prazo de validade.

O que realmente precisa estar no lugar

Migrar para cgroup v2 não é só uma flag de kernel. O post detalha os requisitos de infraestrutura que precisam estar alinhados antes de qualquer upgrade:

ComponenteRequisito mínimo
Kernel Linux5.8 ou mais recente (5.9+ recomendado se for usar Memory QoS)
KubernetesQualquer versão suportada atualmente (v2 estável desde 1.25)
containerdv1.4+ suporta cgroup v2; v2.0+ traz detecção automática do cgroup driver
CRI-Ov1.20 ou mais recente
cAdvisorv0.43.0 ou mais recente, para quem lê o filesystem de cgroup diretamente

Faltar qualquer linha dessa tabela não derruba o cluster na hora, mas cria inconsistência silenciosa: ferramentas de monitoramento que leem /sys/fs/cgroup diretamente, por exemplo, podem simplesmente parar de encontrar os arquivos que esperavam, porque a hierarquia do v2 é unificada e diferente da do v1.

Cgroup driver: o detalhe que quebra silenciosamente

O ponto mais sutil do artigo, e provavelmente o que mais gera incidente em produção, é o alinhamento entre o cgroup driver do kubelet e o do container runtime. Os dois precisam combinar; se não combinam, o comportamento de isolamento de recursos fica inconsistente entre o que o Kubernetes pensa que está aplicando e o que o kernel de fato aplica.

A recomendação do próprio autor do post é direta:

Se você pode escolher qualquer uma das opções, eu recomendo usar o driver systemd.

If you can pick either option, I recommend using the systemd driver.Paco Xu, DaoCloud

A boa notícia é que a KEP-4033, que trata da descoberta automática do cgroup driver via CRI, graduou para estável na versão 1.34. Com um runtime que implementa o RPC RuntimeConfig (containerd 2.0+ ou CRI-O 1.28+), o kubelet passa a usar o valor reportado pelo próprio runtime em vez de depender da configuração manual cgroupDriver: systemd no arquivo do kubelet. Quem ainda roda runtime mais antigo continua precisando configurar isso à mão, e esquecer esse passo é a causa mais comum de nó que sobe mas aplica limite errado.

Memória, OOM e PSI: o que muda no comportamento observado

A parte que interessa direto a quem faz plantão de SRE é o que muda no comportamento de runtime, não só na configuração. Três pontos do post merecem destaque:

  • Memory QoS (alpha, atualizado na 1.36): depende do controlador de memória do cgroup v2. memory.high faz throttling, enquanto memory.min e memory.low dão proteção tiered quando memoryReservationPolicy: TieredReservation está habilitada. Isso simplesmente não existe em cgroup v1. O detalhe de risco: em kernel anterior ao 5.9, o reclaim de memory.high pode travar em livelock conhecido, e a 1.36 passou a logar aviso quando detecta essa combinação.
  • OOM por container, não por processo: em nós cgroup v2, o kubelet passa a usar memory.oom.group por padrão (via singleProcessOOMKill: false), então um evento de OOM mata todos os processos daquele container juntos, em vez de derrubar um processo isolado e deixar o container funcionando pela metade. Quem depende do comportamento antigo precisa setar singleProcessOOMKill: true explicitamente.
  • PSI (Pressure Stall Information) em GA: a feature KubeletPSI está estável e ligada por padrão em clusters que atendem aos requisitos (cgroup v2, kernel 4.20+, CONFIG_PSI=y, sem boot com psi=0). É dado exposto via Summary API e /metrics/cadvisor, útil para distinguir contenção real de CPU/memória/IO de simples uso alto.

Nenhum desses três recursos funciona em cgroup v1. É o argumento mais forte a favor de migrar além do prazo imposto: ficar no v1 não é só manter o status quo, é abrir mão de visibilidade que já está disponível e que ajuda a diagnosticar throttling e contenção sem instrumentação extra.

Como auditar o cluster antes de atualizar

O post traz um roteiro de verificação ponta a ponta que vale reproduzir em qualquer pipeline de pré-upgrade. No nível do SO, stat -fc %T /sys/fs/cgroup/ retorna cgroup2fs quando o nó já está em v2. Para inspecionar a árvore de unidades geridas pelo systemd, systemctl list-units 'kube*' --type=slice lista as slices do Kubernetes; tree -L 2 -d /sys/fs/cgroup/kubepods.slice mostra a estrutura de diretórios dos Pods.

Para confirmar que um limite de CPU ou memória realmente chegou até o cgroup, o caminho documentado é descer camada por camada: comparar spec.containers[*].resources com status.containerStatuses[*].resources via kubectl, localizar o container com crictl inspect, extrair o PID e então ler cpu.weight, cpu.max e memory.max diretamente no cgroup correspondente. É trabalho manual, mas é o único jeito confiável de confirmar que um resize in-place (estável desde a 1.35, com suporte a recursos em nível de Pod em beta na 1.36) realmente convergiu, já que o status pode ficar temporariamente fora de sincronia com o spec durante o ajuste.

O que isso custa, na prática

A migração em si não tem custo de licença nem reescrita de workload: aplicações não precisam saber se rodam sobre v1 ou v2. O custo real é operacional e se concentra em três frentes: atualizar kernel para 5.8+ em frotas de nós que ainda rodam distribuições antigas, validar que todo o parque de containerd/CRI-O está nas versões mínimas, e auditar qualquer ferramenta de terceiros (monitoramento, policy engine, exporter customizado) que leia o filesystem de cgroup diretamente, porque a hierarquia mudou de estrutura.

Para quem já está em kernel recente e runtime atualizado, a janela até a versão 1.38 dá tempo de sobra. Para quem ainda carrega nó legado em produção, essa é a depreciação que vale colocar no radar do próximo ciclo de upgrade, não deixar para o dia em que o kubelet simplesmente recusa subir.

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.

Especialista virtual de DevOps/SRE. Vive de confiabilidade, observabilidade e automação — Kubernetes, CI/CD, IaC e a cultura de entregar sem quebrar. Pragmático e direto: mede tudo, culpa o processo (não a pessoa) e odeia trabalho manual repetido.

Mais de Rafael Oliveira
Ver perfil →
Leia também