Pods en Terminating: ¿Solución rápida o buscar la raíz?

Cuando un pod de Kubernetes se queda pegado en estado 'Terminating', mucha gente recurre al borrado forzado. Yo creo que esa es casi siempre la respuesta equivocada.

Mira, lo digo de entrada: usar kubectl delete pod --grace-period=0 --force para un pod que se queda pegado en Terminating es un parche. Es la solución rápida que todos usamos alguna vez, pero raras veces ataca el problema de fondo. Y a mí, la verdad, me frustra un poco esa tendencia a barrer la mugre debajo de la alfombra.

Si trabajas con Kubernetes, es probable que ya te hayas topado con esto. Despliegas algo, o escalas un deployment, y de repente ves que algunos pods simplemente no mueren. Se quedan ahí, como fantasmas, ocupando recursos y generando incertidumbre. El status se clava en Terminating y no se mueve.

El reflejo: borrar a la fuerza

Lo primero que uno busca en Stack Overflow, o lo que te dice el colega más experimentado, es el comando mágico. El que te saca del apuro al instante:


kubectl delete pod <nombre-del-pod> --grace-period=0 --force --namespace <tu-namespace>

Y sí, funciona. El pod desaparece. Respiras tranquilo. Pero, ¿qué aprendiste? ¿Resolviste la causa de que se quedara pegado? Absolutamente no. Solo le dijiste a Kubernetes que lo ignorara y lo eliminara de su registro, sin preocuparse si la capa inferior (Docker, containerd, etc.) realmente lo había matado.

Esto me pasó a mí. Recuerdo una vez, estábamos en un cliente y un deployment tenía problemas para terminar pods viejos. El equipo de operaciones, acostumbrado a las soluciones rápidas, aplicaba el --force cada vez que pasaba. Yo les decía que eso no podía ser la solución definitiva, que algo más profundo estaba pasando. Me costó convencerlos de que investigáramos a fondo.

La verdad: buscando la raíz del problema

La pregunta original de Stack Overflow era clave: “¿Cuál podría ser la razón de este problema?”. No era “¿Cómo lo borro a la fuerza?”. Y eso es lo que tenemos que priorizar. Cuando un pod no termina, generalmente es porque el contenedor subyacente no puede liberar algún recurso o proceso. Está busy, como dicen en inglés.

Las causas pueden ser variadas, pero un culpable común es lo que se conoce como un "docker mount leaking into some other namespace". En términos simples, el contenedor está usando un recurso (un archivo, un dispositivo, un socket) que no está liberando correctamente al momento de intentar terminar. Docker (o el runtime que uses) no puede matar el proceso porque este recurso aún está en uso, y Kubernetes se queda esperando la señal de que el contenedor murió.

Para investigar esto, la solución no está en Kubernetes, sino en el nodo donde reside el pod. Necesitas entrar al host y ver qué está pasando a nivel de Docker o containerd.

Aquí es donde la segunda respuesta de Stack Overflow, la menos votada pero más valiosa, entra en juego:

  1. Identifica el nodo del pod: Usa kubectl get pod <nombre-del-pod> -o wide para ver en qué nodo está.
  2. Accede al nodo: Si usas Minikube, es minikube ssh. En un cluster real, es un SSH normal al worker node.
  3. Busca los contenedores "zombie": Una vez dentro del nodo, busca los contenedores que corresponden a tu pod.

# En el nodo del pod
docker container ps | grep <nombre-parcial-del-pod-o-imagen>

Probablemente verás que el contenedor sigue ahí, en un estado que no es el esperado. Si encuentras el ID del contenedor, puedes intentar detenerlo manualmente:


# En el nodo del pod
docker container stop <ID-del-contenedor>

Si esto funciona, el pod en Kubernetes debería desaparecer por fin. Pero si incluso docker container stop falla o se queda pegado, es una señal aún más clara de que algo está mal a un nivel más bajo, probablemente con un recurso que el proceso no está liberando.

¿Por qué la sobreingeniería se disfraza de solución simple?

A veces, la sobreingeniería no es añadir complejidad, sino ignorar la complejidad real. Creer que un --force es la solución universal es un ejemplo. No estás resolviendo el problema de tu aplicación, ni de cómo usa los recursos, ni de cómo tu contenedor fue construido. Solo estás pateando la lata para después.

En mi experiencia, estos problemas de pods pegados suelen indicar:

  • Problemas de shutdown graceful en la aplicación: Tu código no maneja bien la señal de terminación (SIGTERM), no cierra conexiones, ni libera archivos.
  • Montajes de volúmenes problemáticos: Especialmente si son NFS o FUSE, pueden causar bloqueos.
  • Bugs en el runtime del contenedor: Menos común, pero posible.

Yo prefiero la solución simple que funciona de verdad, no la que solo maquilla el síntoma. Entiendo que a veces el tiempo apremia, y un --force te saca del apuro. Pero ojo que si esto se vuelve un patrón, tienes un problema serio.

Lo que aprendí tarde (y ojalá hubiese sabido antes)

Cuando empecé con Kubernetes, yo era de los que usaban el --force sin pensar mucho. Era la solución mágica que me sacaba de apuros a las 2 AM cuando un despliegue crítico fallaba. Y me funcionaba, claro. Pero cada vez que lo hacía, estaba acumulando deuda técnica, una bomba de tiempo que podía explotar con un comportamiento errático o un consumo de recursos inesperado.

Me costó un par de bugs difíciles de replicar, que aparecían y desaparecían sin patrón aparente, para darme cuenta de que esos --force del pasado no eran soluciones, sino el inicio de otros problemas. Hubiera ahorrado muchas horas de dolor de cabeza si desde el principio hubiera dedicado tiempo a entender por qué el pod no terminaba, en lugar de simplemente forzar su desaparición. Al final, siempre es mejor invertir un poco más de tiempo en la investigación que en el constante apagado de incendios.

Jorge RequenaDeveloper full-stack · Chile