Como Resolver Recursos Presos em ‘Terminating’ no Kubernetes

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!!

A remoção manual de Finalizers pode ser uma solução eficaz para desbloquear recursos presos em Terminating, porém não é considerada uma BOA PRÁTICA para o gerenciamento de clusters Kubernetes. Essa ação deve ser utilizada com cautela, pois pode gerar problemas secundários, dependendo do tipo de recurso e do seu controlador.

Quais Riscos ao Remover Finalizers Manualmente?

Há inúmeros riscos ao realizar esta ação sem analisar o contexto desta falha, podemos listar alguns:

  1. 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.
  2. 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.
  3. 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:

1kubectl get namespaces

Exemplo de saída indicando um namespace com problema:

1NAME             STATUS   AGE
2app-frontend      Active   2d
3app-backend       Active   2d
4old-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:

1kubectl 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:

1kubectl 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:

1kubectl delete all --all -n old-namespace
Há recursos de Persistent Volume Claims (PVCs) que podem estar impedindo a exclusão, liste e remova-os:
1kubectl get pvc -n old-namespace
2kubectl delete pvc --all -n old-namespace
Verifique também se há NetworkPolicies que podem estar bloqueando a comunicação:
1kubectl get networkpolicy -n old-namespace
2kubectl 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:

1kubectl edit namespace old-namespace

Apague a seção finalizers e salve o arquivo. Se preferir uma abordagem mais direta, utilize:

1kubectl 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:

1kubectl edit namespace old-namespace

No editor, localize e remova a seção:

1spec:
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:

1kubectl 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:

1kubectl 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:

1kubectl get namespaces
O namespace old-namespace não deve mais aparecer na lista.

🔥 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
2NAMESPACE=$1
3kubectl get namespace $NAMESPACE -o json | jq 'del(.spec.finalizers)' > temp.json
4kubectl replace --raw "/api/v1/namespaces/$NAMESPACE/finalize" -f temp.json
5rm -f temp.json

Dê permissão de execução ao script:

1chmod +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

1kubectl get pod <NOME_DO_POD> -o json
2kubectl patch pod <NOME_DO_POD> -p '{"metadata":{"finalizers":[]}}' --type=merge

Para PersistentVolumeClaims (PVCs)

1kubectl get pvc <NOME_DO_PVC> -o json
2kubectl patch pvc <NOME_DO_PVC> -p '{"metadata":{"finalizers":[]}}' --type=merge

Para Custom Resource Definitions (CRDs)

1kubectl get crd <NOME_DO_CRD> -o json
2kubectl 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:

  1. O controlador responsável não pode ser restaurado (exemplo: foi desinstalado acidentalmente).
  2. O recurso em questão está bloqueando operações críticas no cluster.
  3. 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! 🚀

 

Anterior Kubernetes Gateway API - um "adeus e obrigado" ao Ingress Controller
Próxima Índices são sempre bons?

About author

Jeovany Batista
Jeovany Batista 10 posts

Formado em Segurança da Informação, trabalha com tecnologia há 11 anos, atualmente é Analista de Infraestrutura e Monitoramento na 4Linux, nas horas vagas se aventura na culinária e nos games. Entusiasta em opensource tools e no momento curtindo a distro OpenSuse!

View all posts by this author →

Você pode gostar também

DevOps

Lançamento do curso DevSecOps: Segurança em Infraestrutura e Desenvolvimento Ágil

Treinamento possui conteúdo único em relação a qualquer outro no mercado A 4Linux anuncia hoje o lançamento de mais um curso para enriquecer a sua oferta de treinamentos na carreira

Infraestrutura TI

Segurança em Acesso: Entenda a Importância do Controle de Acesso

O controle de acesso é uma prática voltada para segurança do ambiente e que visa garantir que somente pessoas autorizadas tenham permissão para visualizar e realizar operações dentro de uma

Containers

Guia Prático: Como Configurar um Cluster de OpenShift Origin

Esse post tem como objetivo criar um cluster de OpenShift Origin com um master e dois nós, a fim de fazer o deploy automático e definir o fluxo de integração