Como Resolver Recursos Presos em ‘Terminating’ no Kubernetes
Gerenciar clusters Kubernetes é sempre um trabalho árduo, e dentre os processos de gestão é comum precisar excluir objetos ou recursos que não são mais necessários.
Quem faz esta gerência sabe o quão frustrante pode ser encontrar recursos que permanecem presos no estado Terminating indefinidamente, impedindo sua remoção. Isso pode acontecer com diversos tipos de recursos, como Namespaces, Pods, PersistentVolumeClaims (PVCs) e Custom Resource Definitions (CRDs).
O motivo deste problema é porque geralmente ocorre devido à presença de finalizadores (finalizers), que são mecanismos do Kubernetes que garantem que determinadas operações sejam concluídas antes que o recurso seja excluído.
Neste post, abordaremos como resolver esse problema para qualquer recurso do Kubernetes e utilizaremos Namespaces como exemplo prático.
🔍 Entendendo o Problema
Quando um recurso do Kubernetes é excluído, o cluster inicia um processo de limpeza e o recurso ganhará uma flag de Finalizer. Ele deve ser processado antes que o Kubernetes conclua a exclusão, no entanto, se o controlador responsável pelo Finalizer não puder executá-lo, o recurso permanecerá indefinidamente no estado Terminating.
Esse problema pode ocorrer em diferentes contextos, por exemplo:
- Um Pod que depende de um PersistentVolumeClaim que ainda está em uso.
- Um Namespace que contém recursos órfãos impedindo a remoção.
- Um Custom Resource Definition (CRD) que não pode ser removido porque um controlador não processou sua finalização.
⚠️ ATENÇÃO!!
Quais Riscos ao Remover Finalizers Manualmente?
Há inúmeros riscos ao realizar esta ação sem analisar o contexto desta falha, podemos listar alguns:
- Perda de Processamento do Controlador: Finalizers existem para garantir que processos específicos sejam concluídos antes da remoção do recurso. Ao removê-los manualmente, você pode impedir a execução dessas etapas, o que pode causar:
- Volumes não desmontados corretamente (PVCs).
- Falha na liberação de IPs, cargas de trabalho e sessões de rede (Pods).
- Remoção inconsistente de objetos filhos em CRDs.
- Referências Órfãs e Consistência do Cluster: Alguns controladores do Kubernetes dependem de Finalizers para limpar estados internos ou atualizar referências antes da remoção do recurso. A remoção manual pode resultar em:
- Entradas inválidas em bancos de dados de estados (etcd).
- Recursos órfãos que nunca serão completamente excluídos.
- Problemas na reconciliação de objetos por controladores que esperavam processar o Finalizer.
- Impacto em Aplicações e Serviços: No caso de Finalizers aplicados a Namespaces, a remoção pode fazer com que serviços ainda em execução dentro do namespace sejam encerrados abruptamente, potencialmente corrompendo aplicações dependentes.
🛠️ Solução: Removendo Finalizers Manualmente
A solução para este problema é relativamente fácil, podemos editar o recurso diretamente e remover os Finalizers.
Vamos exemplificar com um Namespace, mas essa abordagem pode ser aplicada a outros recursos.
🔎 Identificando o Namespace Preso
Primeiro, liste todos os namespaces no cluster e veja quais estão no estado Terminating:
1 | kubectl get namespaces |
Exemplo de saída indicando um namespace com problema:
1 | NAME STATUS AGE |
2 | app-frontend Active 2d |
3 | app-backend Active 2d |
4 | old-namespace Terminating 10h |
O namespace old-namespace está no estado Terminating há 10 horas, o que indica um possível problema.
Para verificar, use o comando:
1 | kubectl get namespace old-namespace -o json |
A saída pode conter algo semelhante a:
1 | "spec" : { |
2 | "finalizers" : [ |
3 | "kubernetes" |
4 | ] |
5 | } |
📝 Verificar Objetos Existentes Dentro do Namespace
Antes de forçar a remoção do namespace, é importante verificar se existem recursos pendentes dentro dele. Use os comandos abaixo para listar os objetos dentro do namespace problemático:
1 | kubectl get all -n old-namespace |
Isso mostrará os pods, serviços, deployments e outros recursos dentro do namespace.
Caso ainda existam recursos ativos, tente deletá-los manualmente:
1 | kubectl delete all --all -n old-namespace |
Há recursos de Persistent Volume Claims (PVCs) que podem estar impedindo a exclusão, liste e remova-os:
1 | kubectl get pvc -n old-namespace |
2 | kubectl delete pvc --all -n old-namespace |
Verifique também se há NetworkPolicies que podem estar bloqueando a comunicação:
1 | kubectl get networkpolicy -n old-namespace |
2 | kubectl delete networkpolicy --all -n old-namespace |
Se todos os recursos forem removidos e o namespace ainda estiver em Terminating, vá para a próxima etapa.
🧹 Removendo o Finalizer
Para remover manualmente os Finalizers, edite o recurso e remova a seção finalizers:
1 | kubectl edit namespace old-namespace |
Apague a seção finalizers e salve o arquivo. Se preferir uma abordagem mais direta, utilize:
1 | kubectl patch namespace old-namespace -p '{"metadata":{"finalizers":[]}}' -- type =merge |
Após isso, o Kubernetes concluirá a exclusão do Namespace.
📝 Editar Diretamente o Namespace
Você pode editar diretamente o objeto do namespace e realizar a alteração do finalizers, para isso faça os passos abaixo:
1 | kubectl edit namespace old-namespace |
No editor, localize e remova a seção:
1 | spec: |
2 | finalizers: |
3 | - kubernetes |
Salve e saia do editor, o editor mais comum é o vim e para salvar e sair basta pressionar ‘Esc’ e depois digite: :wq! ou 😡 . Se o namespace ainda não for removido, use a abordagem forçada abaixo.
💀 Remover Finalizadores e Forçar a Exclusão do Namespace
Se a remoção manual não funcionar, há uma abordagem mais hardcore que você poderá executar:
1 | kubectl get namespace old-namespace -o json > namespace.json |
Abra o arquivo `namespace.json` e remova a linha que contém:
1 | "finalizers" : [ "kubernetes" ] |
Agora, execute o comando abaixo para atualizar o namespace diretamente na API do Kubernetes:
1 | kubectl replace --raw "/api/v1/namespaces/old-namespace/finalize" -f namespace.json |
Isso removerá o finalizador e permitirá que o namespace seja excluído corretamente.
Para confirmar a remoção, execute:
1 | kubectl get namespaces |
🔥 Prática DevOps: Automatizando a Remoção de Namespaces Presos
Se esse problema for recorrente em seu cluster, você pode criar um script Bash para automatizar a remoção de finalizadores de namespaces que estão presos no estado Terminating.
Crie um arquivo chamado force-delete-namespace.sh e adicione o seguinte código:
1 | #!/bin/bash |
2 | NAMESPACE=$1 |
3 | kubectl get namespace $NAMESPACE -o json | jq 'del(.spec.finalizers)' > temp.json |
4 | kubectl replace --raw "/api/v1/namespaces/$NAMESPACE/finalize" -f temp.json |
5 | rm -f temp.json |
Dê permissão de execução ao script:
1 | chmod +x force-delete-namespace.sh |
Agora, para remover um namespace preso, basta rodar:
1 | ./force-delete-namespace.sh old-namespace |
Isso automatiza o processo e pode ser útil em ambientes onde a remoção de namespaces presos ocorre com frequência.
🔄 Aplicação para Outros Recursos
Essa mesma abordagem pode ser aplicada para outros tipos de recursos presos em Terminating. Basta identificar o recurso e seguir os mesmos passos:
Para Pods
1 | kubectl get pod <NOME_DO_POD> -o json |
2 | kubectl patch pod <NOME_DO_POD> -p '{"metadata":{"finalizers":[]}}' -- type =merge |
Para PersistentVolumeClaims (PVCs)
1 | kubectl get pvc <NOME_DO_PVC> -o json |
2 | kubectl patch pvc <NOME_DO_PVC> -p '{"metadata":{"finalizers":[]}}' -- type =merge |
Para Custom Resource Definitions (CRDs)
1 | kubectl get crd <NOME_DO_CRD> -o json |
2 | kubectl patch crd <NOME_DO_CRD> -p '{"metadata":{"finalizers":[]}}' -- type =merge |
🚀 Conclusão
Recursos presos em Terminating são um problema comum no Kubernetes e podem afetar diferentes tipos de objetos. Ao entender como remover manualmente os Finalizers, conseguimos desbloquear a exclusão de qualquer recurso problemático.
Mas lembrando, a remoção de Finalizers pode parecer uma solução rápida, mas pode trazer riscos ao cluster. A melhor abordagem é investigar o problema antes de remover um Finalizer manualmente.
Se for realmente necessário fazer, garanta que você compreenda o impacto e tenha um plano de mitigação. O mais importante: documente a intervenção pois a remoção manual pode ter consequências futuras.
A remoção manual de Finalizers deve ser tratada como último recurso e apenas quando:
- O controlador responsável não pode ser restaurado (exemplo: foi desinstalado acidentalmente).
- O recurso em questão está bloqueando operações críticas no cluster.
- Você já investigou dependências e não há impacto na remoção forçada.
Essa técnica é essencial para manter um ambiente Kubernetes saudável e sem resíduos de recursos desnecessários! 🚀