O que era o bug do kyaml no Kubernetes

O Kubernetes 1.37 trouxe uma correção crítica para um bug que existia ha vários anos: o output do kyaml podia silenciosamente apagar campos de recursos YAML durante a execução do kubectl apply. O problema estava na forma como o kyaml serializava e desserializava objetos YAML com determinadas estruturas de dados.

O bug se manifestava em cenários específicos, mas era perigoso justamente porque não gerava erro nenhum. O kubectl reportava sucesso, o recurso era atualizado, mas alguns campos eram simplesmente removidos. Para equipes sem uma rotina rigorosa de auditoria de estado do cluster, isso podia passar despercebido por dias ou semanas.

Com o Kubernetes 1.37, esse comportamento foi corrigido no nível da biblioteca kyaml, que é a base para toda a manipulação de YAML no ecossistema de ferramentas do Kubernetes. A correção afeta o kubectl, kustomize e outros toolings que dependem dessa biblioteca.

Como o bug funcionava

O kyaml e uma biblioteca Go que o Kubernetes usa para ler, escrever e transformar recursos YAML. Ela foi projetada especificamente para preservar comentários, ordem de campos e outros detalhes de formatação importantes para workflows GitOps.

O bug estava na fase de merge de campos durante o apply. Quando o kubectl apply compara o estado desejado (o YAML local) com o estado atual do cluster, ele precisa mesclar as diferenças. Em certos tipos de campos aninhados, o algoritmo de merge descartava campos que não estavam presentes no manifesto local mas que tinham sido adicionados por outros processos, como controllers ou admission webhooks.

O resultado era que campos gerenciados por outros sistemas podiam ser apagados a cada apply, quebrando integrações e causando comportamentos imprevistos. Em clusters de produção com vários controladores e operadores rodando, esse tipo de perda de dados causava outages sutis e difíceis de diagnosticar.

🔴
Cuidado

Versões do Kubernetes anteriores a 1.37 ainda são vulneráveis a esse bug. Se você usa kubectl apply com frequência em clusters de produção, verifique a versão e considere atualizar.

Principais mudanças no Kubernetes 1.37

Além da correção do kyaml, o Kubernetes 1.37 inclui outras melhorias relevantes para o dia a dia das equipes:

  • Correção do kyaml output: o bug de perda de dados no apply foi corrigido na base da biblioteca, afetando kubectl, kustomize e todos os toolings dependentes.
  • Server-Side Apply mais estável: melhorias no mecanismo de Server-Side Apply, que é a abordagem recomendada para evitar conflitos de gerenciamento de campos.
  • Melhorias no kubelet: redução de memoria usada pelo kubelet em nodes com muitos pods e containers.
  • Gateway API avançada: a Gateway API, sucessora do Ingress para casos de uso mais complexos, avançou em maturidade no 1.37.
  • Atualizações de segurança: correções de CVEs e melhorias no mecanismo de auditoria de acesso a API.

O foco da versão 1.37 foi estabilidade e correção de bugs acumulados, mais do que adicionar grandes funcionalidades novas.

Como verificar e atualizar seu cluster

Para verificar a versão atual do Kubernetes no seu cluster, rode o comando abaixo e compare com a versão 1.37:

kubectl version --short

Para atualizar o kubectl para a versão 1.37 no Linux:

curl -LO https://dl.k8s.io/release/v1.37.0/bin/Linux/amd64/kubectl

Para ver o diff antes de aplicar mudanças, use o dry-run no servidor. Isso mostra exatamente o que vai mudar no cluster antes de confirmar:

kubectl apply --dry-run=server -f seu-recurso.yaml
💡
Dica

Antes de atualizar o cluster em produção, sempre atualize o kubectl local para a nova versão e teste em um cluster de staging primeiro.

Exemplo prático: o bug em ação

Imagine que você tem um Deployment e um admission webhook que adiciona automaticamente anotações a todos os recursos. O webhook adiciona managed-by: meu-operator no momento da criação do recurso.

Seu manifesto local não tem essa anotação, porque ela é gerenciada pelo webhook. Em versões anteriores ao 1.37, cada vez que você rodava kubectl apply com seu manifesto local, a anotação managed-by era removida, porque o kyaml a entendia como um campo que deveria ser deletado.

Com o fix do Kubernetes 1.37, o algoritmo de merge respeita campos que não estavam no manifesto original, preservando o que foi adicionado por outros sistemas. E exatamente o comportamento esperado que o Server-Side Apply já fazia certo, mas agora o Client-Side Apply também faz.

Client-Side Apply vs Server-Side Apply

Esse bug reforça uma discussão que a comunidade Kubernetes já tem ha anos sobre as duas abordagens de apply:

  • Client-Side Apply: o kubectl calcula o merge localmente, usando a annotation kubectl.Kubernetes.io/last-applied-configuration como referência. Mais simples, mas historicamente mais propenso a bugs de merge como esse do kyaml.
  • Server-Side Apply (SSA): o servidor e quem calcula o merge, com controle granular por campo sobre qual controller possui cada parte do recurso. Mais robusto para ambientes com múltiplos controladores.

Para ambientes de produção com operadores e controllers, o SSA continua sendo a recomendação. Mas a correção do 1.37 melhora bastante a segurança do Client-Side Apply para quem ainda o usa ou que não pode migrar tudo de uma vez.

Pontos positivos e limitações

Pontos positivos da atualização: correção de um bug real que causava perda silenciosa de dados, melhor compatibilidade entre Client-Side Apply e recursos gerenciados por controllers, redução de memoria no kubelet beneficia todos os nodes do cluster.

Limitações e considerações: atualizar um cluster Kubernetes não e trivial, especialmente em produção. Mesmo com a correção, o Server-Side Apply ainda e a abordagem mais robusta para ambientes complexos. A correção não volta atrás campos que já foram apagados por versões anteriores.

⚠️
Atenção

Se você suspeita que campos foram apagados por esse bug em versões anteriores, compare o estado atual do cluster com a fonte de verdade no seu repositório Git antes de atualizar.

Quem e mais afetado pelo bug

Os cenários que mais sofriam com esse problema eram:

  • Times com muitos operadores instalados: cada operador que adiciona campos em recursos existentes estava sujeito a ver esses campos apagados no próximo apply manual.
  • GitOps com Argo CD ou Flux: workflows onde o estado do cluster e sempre reconciliado com o Git podiam ter conflitos silenciosos entre o que o Git tem e o que os controllers adicionam.
  • Desenvolvimento com admission webhooks: ambientes de dev que simulam webhooks de produção, como Istio ou OPA Gatekeeper, podiam ter comportamentos diferentes entre dev e prod.
  • Helm com hooks: charts com hooks que modificam recursos após a criação podiam ter essas modificações removidas no próximo helm upgrade.

Dicas e boas práticas para quem usa kubectl apply

💡
Dica

Use sempre --dry-run=server antes de aplicar mudanças em produção. Assim você ve exatamente o que vai mudar no cluster antes de confirmar.

🚀
Pro tip

Migre gradualmente para Server-Side Apply usando a flag --server-side no kubectl apply. Comece por recursos menos críticos e va expandindo conforme ganha confiança.

⚠️
Atenção

Configure seu cluster para auditar todas as modificações de recursos via Audit Log do Kubernetes API Server. Isso facilita muito diagnosticar perdas de dados silenciosas como essa.

Vale a pena atualizar para o 1.37?

Para equipes que usam kubectl apply frequentemente em produção, especialmente com operadores e admission webhooks, a resposta e sim. A correção do kyaml resolve um problema real que podia causar incidentes difíceis de diagnosticar.

Para quem já usa Server-Side Apply como padrão, o impacto e menor mas as outras melhorias de estabilidade e segurança ainda justificam a atualização planejada.

O próximo passo: cheque a versão atual do seu cluster com kubectl version --short e consulte o changelog do Kubernetes 1.37 no GitHub para ver a lista completa de mudanças antes de planejar a atualização.