Contenido del curso

Debugging de errores comunes en Kubernetes

Resumen

Cuando despliegas aplicaciones en Kubernetes, los errores son parte del día a día. La buena noticia es que con un puñado de comandos como kubectl describe, kubectl logs y kubectl exec puedes resolver la mayoría de fallas en clusters productivos sin volverte loco. Esta guía está pensada para personas DevOps, SRE y desarrolladores que despliegan microservicios en EKS y necesitan un flujo claro de troubleshooting Kubernetes.

A lo largo del recorrido vas a ver cuatro errores reales que aparecen una y otra vez: ImagePullBackOff, errores de configuración por secretos mal nombrados, OOMKilled por límites de recursos mal calculados y problemas de conectividad de red hacia una base de datos RDS.

¿Cómo se diagnostica un error ImagePullBackOff en Kubernetes?

El primer pod del namespace backend aparece con el estado ImagePullBackOff, una señal clásica de que el kubelet no pudo descargar la imagen del contenedor [02:10].

Para confirmarlo usas kubectl describe pod <nombre> -n backend y revisas la sección de Events. Ahí el kubelet te dice exactamente qué pasó: la imagen k8s-backend:v2 no existe en el registry, porque la única versión publicada es v1.

¿Qué significa ImagePullBackOff? Es el error que aparece cuando Kubernetes intenta descargar una imagen del registry y falla repetidamente. Suele deberse a un tag inexistente, un registry privado sin credenciales o un nombre de imagen mal escrito.

La solución es directa: editar el manifiesto YAML del backend, corregir el tag a v1 y volver a aplicar con kubectl apply -f k8s/backend.yaml -n backend.

¿Por qué siempre debo especificar el namespace al aplicar un YAML?

Un detalle fácil de pasar por alto: si no incluyes -n backend en el apply, los recursos caen en el namespace default y parece que nada cambió [05:30]. Por eso conviene ser explícito en el comando o configurar un contexto por defecto que apunte al namespace correcto.

¿Cómo soluciono un error de configuración por un secret mal referenciado?

Después de corregir la imagen, el pod cambia de estado y ahora muestra CreateContainerConfigError. Vuelves a ejecutar kubectl describe pod y los eventos te dicen que el contenedor descargó la imagen, pero al iniciar no encontró el secret mysql-secret [07:45].

Al listar los secretos con kubectl get secrets -n backend descubres que el secret existe, pero se llama mysql, sin el sufijo -secret. Es un typo en el manifiesto.

Editas el YAML, reemplazas las cuatro ocurrencias de mysql-secret por mysql, aplicas de nuevo y el pod por fin entra en estado Running. Errores así son comunes en clusters productivos y por eso muchos equipos automatizan la generación de manifiestos con herramientas como Helm o Kustomize.

¿Por qué un pod entra en CrashLoopBackOff con OOMKilled?

La aplicación responde, pero el endpoint /getmyinfo devuelve vacío y al rato el pod cae en CrashLoopBackOff. El describe revela un nuevo culpable: OOMKilled, es decir, Out of Memory Killed.

En la sección de Limits y Requests del manifiesto ves valores ridículamente bajos: 5000m de CPU y 16 MB de memoria, y además los límites son iguales a los requests, sin margen para crecer.

¿Qué es OOMKilled en Kubernetes? Es la señal que envía el sistema operativo cuando un contenedor consume más memoria de la asignada en sus limits. Kubernetes lo mata y lo reinicia, generando ciclos de CrashLoopBackOff.

La corrección consiste en darle aire al pod:

  • Requests: 50m de CPU y 256 MB de memoria como punto de arranque.
  • Limits: 100m de CPU y 512 MB de memoria para permitir crecimiento.
  • Mantener una diferencia entre requests y limits para absorber picos.

Con esos valores el pod arranca limpio y deja de reiniciarse [13:20].

¿Cómo verifico la conectividad desde un pod hacia una base de datos RDS?

El pod ya corre, pero la API sigue respondiendo vacía y los logs no muestran errores. Toca entrar al contenedor con kubectl exec -it <pod> -n backend -- sh. Como la imagen está basada en Alpine, no trae bash, así que usas sh directamente.

Dentro del pod instalas el cliente de MySQL y revisas las variables de entorno con env | grep DB para extraer DB_USER, DB_HOST y DB_NAME. Al intentar conectarte con mysql -u $DB_USER -h $DB_HOST $DB_NAME -p, la conexión se queda colgada [17:50].

¿Qué tengo que revisar en los security groups de AWS?

El problema no está en Kubernetes sino en la red de AWS. El security group de la instancia RDS solo permitía tráfico desde una IP específica, no desde el security group de los nodos del cluster EKS.

La solución pasa por editar las reglas de entrada de la base de datos:

  1. Identificar el security group de los nodos del cluster (no el del control plane).
  2. Eliminar la regla con la IP fija.
  3. Agregar una regla que permita el tráfico entrante desde el security group de los nodos.

La propagación tarda unos segundos. Al reintentar la conexión y ejecutar SELECT * FROM user_info;, los datos aparecen y la API empieza a responder con información real.

Comandos clave para hacer troubleshooting en Kubernetes

De todo el recorrido salen los comandos que conviene tener a la mano cuando algo se rompe en producción.

  • kubectl describe pod <nombre> -n <namespace> para leer eventos y configuración.
  • kubectl logs <pod> -n <namespace> para ver la salida de la aplicación.
  • kubectl exec -it <pod> -n <namespace> -- sh para entrar al contenedor y depurar desde dentro.
  • kubectl get events -n <namespace> para ver el historial de eventos del cluster.
  • kubectl apply -f <archivo>.yaml -n <namespace> para aplicar cambios sin olvidar el namespace.

Cada error que viste tiene un patrón claro: lee los eventos, valida el manifiesto, revisa los recursos asignados y cuando todo lo demás falla, entra al pod y prueba la conectividad manualmente. ¿Cuál de estos errores te ha tocado resolver últimamente? Cuéntalo en los comentarios.

      Debugging de errores comunes en Kubernetes