Introducción
Ahora puedes describir el estado deseado mediante manifiestos y crear Pods y Deployments. La siguiente habilidad esencial es entender qué hacer cuando Kubernetes no puede hacer realidad ese estado deseado.
En este laboratorio trabajarás con dos Deployments pequeños: uno correcto y otro que contiene intencionadamente un error tipográfico en la etiqueta de imagen. Seguirás un proceso repetible que va desde los síntomas generales hasta las pruebas concretas, repararás el manifiesto en lugar de modificar únicamente el objeto activo y, después, inspeccionarás la aplicación recuperada mediante registros y comandos ejecutados dentro de su contenedor.
El objetivo no es memorizar todos los fallos posibles, sino desarrollar un hábito de resolución de problemas sereno: observar, acotar, examinar las pruebas, reparar el estado deseado y verificar la recuperación.
Crear un fallo controlado
Inicio del entorno: Este laboratorio inicia un clúster de Kubernetes completo. La configuración del plano de control, el nodo y los componentes de red suele tardar 2–3 minutos. Espera pacientemente a que el entorno termine de cargarse antes de comenzar.
La resolución de problemas real comienza con un síntoma. En este paso desplegarás una carga de trabajo correcta y otra deliberadamente defectuosa para poder compararlas bajo las mismas condiciones del clúster.
Ve al espacio de trabajo preparado y muestra sus archivos. cd cambia el directorio actual; ls muestra los nombres que contiene. Los comandos aparecen en líneas separadas y se ejecutan en orden:
cd /home/labex/project/debug-lab
ls
Deberías ver healthy-web.yaml y broken-web.yaml. Ambos definen Deployments con una réplica, pero uno contiene un error de configuración sutil que diagnosticarás más adelante.
Aplica ambos manifiestos. kubectl apply envía el estado deseado al servidor de API, y cada opción -f indica un archivo de entrada. Un mismo comando puede aceptar varias opciones -f:
kubectl apply -f healthy-web.yaml -f broken-web.yaml
Espera primero a que finalice correctamente el Deployment conocido como válido:
kubectl rollout status deployment/healthy-web --timeout=60s
El mensaje deployment "healthy-web" successfully rolled out establece una referencia útil: el clúster puede programar Pods y ejecutar la imagen de NGINX almacenada en caché.
Ahora concede al otro Deployment un breve margen para completar el despliegue:
kubectl rollout status deployment/broken-web --timeout=15s || true
El tiempo de espera es esperado. || true indica al intérprete de comandos que continúe, porque este fallo es una evidencia del ejercicio y no un motivo para detener el laboratorio.
Compara el resumen de los Deployments:
kubectl get deployments
healthy-web debería mostrar 1/1 listo, mientras que broken-web debería mostrar 0/1. Así has establecido que el problema es específico de una carga de trabajo y no un fallo total del clúster.
Acotar el problema con resúmenes de recursos
En este paso empezarás con una visión general antes de profundizar en los detalles. Los controladores de Kubernetes crean una cadena de objetos, por lo que un problema en un Deployment suele hacerse visible primero en su ReplicaSet y en su Pod.
Muestra juntos los tipos de objetos relacionados. Las comas permiten que una sola solicitud kubectl get consulte varios tipos de recursos, mientras que -o wide añade columnas útiles, como la información del nodo y de la IP:
kubectl get deployments,replicasets,pods -o wide
Lee la salida de arriba abajo:
- Un Deployment informa del número deseado y disponible de réplicas.
- Un ReplicaSet lleva ese número deseado de réplicas hasta los Pods.
- Un Pod informa de la disponibilidad del contenedor y de un motivo de estado resumido.
Filtra la vista para mostrar únicamente la aplicación defectuosa mediante su etiqueta:
kubectl get pods -l app=broken-web -o wide
El nombre del Pod contiene un sufijo generado automáticamente, por lo que las etiquetas son más seguras que copiar un nombre cambiante en los scripts.
Solicita solo los campos relevantes en esta etapa. -o custom-columns='...' crea una tabla a partir de campos explícitos del objeto. Cada entrada tiene un encabezado, como NAME, seguido de la ruta del campo JSON que proporciona su valor. La barra invertida final une las dos líneas mostradas del intérprete en un único comando:
kubectl get pods -l app=broken-web \
-o custom-columns='NAME:.metadata.name,READY:.status.containerStatuses[0].ready,WAITING_REASON:.status.containerStatuses[0].state.waiting.reason,NODE:.spec.nodeName'
Al principio, el motivo de espera puede ser ErrImagePull y después cambiar a ImagePullBackOff. Ambos indican que el contenedor nunca se inició porque Kubernetes no pudo obtener su imagen. Esto es más preciso que limitarse a decir «el Pod está caído».
Inspeccionar el Pod con describe
En este paso usarás describe para averiguar por qué el contenedor está esperando. El resumen te indicó qué está mal; ahora recopilarás la explicación.
Guarda el nombre generado del Pod en una variable del intérprete de comandos. $(...) es una sustitución de comandos: el intérprete ejecuta el comando interno de kubectl y asigna su salida a BROKEN_POD. JSONPath selecciona el nombre del primer Pod coincidente y echo muestra el valor almacenado:
BROKEN_POD=$(kubectl get pods -l app=broken-web -o jsonpath='{.items[0].metadata.name}')
echo "$BROKEN_POD"
Describe ese Pod:
kubectl describe pod "$BROKEN_POD"
describe combina campos útiles con los eventos recientes. Concéntrate en tres áreas:
- Containers → Image muestra la imagen exacta solicitada.
- State → Waiting → Reason describe el estado actual del contenedor.
- Events registra los intentos del kubelet y los mensajes de error.
En este escenario, el mensaje del evento indica que no se encuentra la etiqueta 1.27-alpine-missing. El clúster está haciendo exactamente lo que solicita el manifiesto; el propio estado deseado es incorrecto.
Confirma directamente la imagen mediante JSONPath:
kubectl get pod "$BROKEN_POD" -o jsonpath='Image: {.spec.containers[0].image}{"\n"}'
JSONPath resulta útil cuando una salida extensa en YAML o de describe contiene más información de la necesaria. Aquí permite aislar el campo que finalmente debe repararse.
Leer los eventos como una línea temporal
En este paso leerás los eventos como una línea temporal de la actividad de Kubernetes. Los eventos son registros de diagnóstico de corta duración que ayudan a explicar la programación, la descarga de imágenes, el inicio de contenedores, los reinicios y muchas otras transiciones de estado.
Muestra los eventos recientes del espacio de nombres en orden cronológico. --sort-by ordena los objetos según el campo de metadatos indicado; las comillas mantienen la ruta del campo con formato JSON como un único argumento:
kubectl get events --sort-by='.metadata.creationTimestamp'
Las últimas filas suelen ser las más recientes. Busca entradas cuya columna OBJECT haga referencia al Pod defectuoso y cuyo REASON incluya valores como Pulling, Failed o BackOff.
Puedes reducir el ruido filtrando los eventos por el nombre generado del Pod. --field-selector filtra campos de objetos en el servidor, no etiquetas. La coma indica que deben cumplirse ambas condiciones, y las barras invertidas permiten continuar un mismo comando en varias líneas legibles:
BROKEN_POD=$(kubectl get pods -l app=broken-web -o jsonpath='{.items[0].metadata.name}')
kubectl get events \
--field-selector involvedObject.kind=Pod,involvedObject.name="$BROKEN_POD" \
--sort-by='.metadata.creationTimestamp'
Considera get, describe y events como vistas complementarias:
getlocaliza rápidamente el objeto que no está sano.describecombina la configuración, el estado y los eventos relacionados de un objeto.eventsproporciona una vista ordenada por tiempo que puede revelar intentos repetidos.
Las entradas repetidas de BackOff no significan que Kubernetes haya abandonado el Pod. Indican que está espaciando los nuevos intentos de descarga después de varios fallos.
Reparar el estado deseado y verificar la recuperación
En este paso repararás el estado deseado y verificarás la recuperación. Ya tienes pruebas suficientes para actuar: el manifiesto solicita una etiqueta de imagen inexistente. Repara primero el manifiesto guardado y después aplícalo, para que el archivo y el clúster activo sigan siendo coherentes.
Muestra las líneas de imagen de ambos manifiestos para compararlas. grep busca texto, -n antepone a cada coincidencia su número de línea y el comando busca en ambos nombres de archivo:
grep -n 'image:' healthy-web.yaml broken-web.yaml
El manifiesto correcto usa nginx:1.27-alpine; el manifiesto defectuoso añade el sufijo inexistente -missing.
Reemplaza únicamente ese sufijo. sed realiza una sustitución de texto con el formato s/old/new/; -i modifica directamente el archivo indicado en lugar de limitarse a mostrar el texto cambiado:
sed -i 's/nginx:1.27-alpine-missing/nginx:1.27-alpine/' broken-web.yaml
Valida localmente el archivo reparado:
kubectl apply --dry-run=client -f broken-web.yaml
Previsualiza la diferencia entre el archivo y el objeto activo:
kubectl diff -f broken-web.yaml || true
kubectl diff finaliza con el código 1 cuando encuentra diferencias, por lo que || true permite continuar con la secuencia de aprendizaje. En la diferencia, una línea que comienza por - contiene la imagen anterior y una línea que comienza por + contiene la imagen reparada.
Aplica la reparación y espera a que se recupere:
kubectl apply -f broken-web.yaml
kubectl rollout status deployment/broken-web --timeout=60s
Confirma que ambos Deployments están ahora en buen estado:
kubectl get deployments
Ambos deberían indicar 1/1 listo. Kubernetes creó un ReplicaSet y un Pod nuevos a partir de la plantilla de Pod corregida; no fue necesario reparar manualmente el Pod fallido.
Leer los registros de la aplicación
En este paso usarás los registros de la aplicación como una nueva fuente de pruebas, ahora que el contenedor se inicia. kubectl logs recupera los flujos de salida estándar y de error estándar del contenedor.
Selecciona el nuevo Pod sano gestionado por broken-web. Esto repite la sustitución de comandos y JSONPath utilizados anteriormente. --field-selector=status.phase=Running añade un requisito evaluado en el servidor para garantizar que el Pod seleccionado esté en ejecución:
WEB_POD=$(kubectl get pods -l app=broken-web \
--field-selector=status.phase=Running \
-o jsonpath='{.items[0].metadata.name}')
echo "$WEB_POD"
Es posible que NGINX todavía no tenga ninguna entrada en el registro de acceso porque nadie ha solicitado una página. Genera una solicitud desde dentro del Pod. En kubectl exec POD -- COMMAND, -- separa las opciones de kubectl del comando que se ejecutará dentro del contenedor. wget -qO- descarga silenciosamente y escribe la página en la salida estándar; la tubería | pasa esa salida a head, que muestra únicamente el principio:
kubectl exec "$WEB_POD" -- wget -qO- http://127.0.0.1 | head
El HTML comienza con <!DOCTYPE html>, lo que demuestra que NGINX respondió localmente en el puerto 80.
Ahora lee los registros recientes. --tail=10 limita la salida a las diez líneas más recientes para que los mensajes de inicio no oculten la entrada de solicitud relevante:
kubectl logs "$WEB_POD" --tail=10
Busca una solicitud HTTP que contenga GET / HTTP/1.1 y un código de respuesta 200. Los registros son especialmente útiles cuando el contenedor se ejecuta, pero la aplicación se comporta de forma incorrecta. Normalmente no sirven para diagnosticar un fallo al descargar la imagen, porque el contenedor nunca llegó a iniciarse.
Inspeccionar desde dentro del contenedor
En este paso inspeccionarás la aplicación recuperada desde dentro de su contenedor. kubectl exec ejecuta un comando en un contenedor que ya está en ejecución y permite comprobar su sistema de archivos, procesos, entorno, configuración de DNS o comportamiento de red local.
Reutiliza el nombre del Pod en ejecución:
WEB_POD=$(kubectl get pods -l app=broken-web \
--field-selector=status.phase=Running \
-o jsonpath='{.items[0].metadata.name}')
Solicita el nombre de host del contenedor:
kubectl exec "$WEB_POD" -- hostname
La salida coincide con el nombre del Pod porque Kubernetes establece el nombre de host del Pod de forma predeterminada.
Comprueba la sintaxis de configuración de NGINX dentro del contenedor:
kubectl exec "$WEB_POD" -- nginx -t
Los mensajes syntax is ok y test is successful muestran que la configuración de la aplicación es válida internamente.
Por último, realiza una comprobación compacta de salud desde dentro hacia fuera. >/dev/null descarta el HTML descargado y && ejecuta echo únicamente si wget tiene éxito. Por tanto, el mensaje de éxito aparece solo después de recibir una respuesta HTTP:
kubectl exec "$WEB_POD" -- wget -qO- http://127.0.0.1 >/dev/null && echo "NGINX responded inside the Pod"
Usa exec con criterio. Requiere un contenedor en ejecución, por lo que no habría podido diagnosticar el fallo anterior al descargar la imagen. La cadena de evidencias para este incidente fue:
get -> describe -> events -> repair manifest -> rollout status -> logs -> exec
Cada fallo puede detenerse en un peldaño distinto, pero avanzar desde resúmenes económicos hacia inspecciones más profundas mantiene la resolución de problemas centrada.
Resumen
Has practicado un ciclo completo de depuración para principiantes en Kubernetes v1.35. Comparaste cargas de trabajo sanas y no sanas, acotaste el problema mediante etiquetas y campos concisos, utilizaste describe y los eventos para identificar una etiqueta de imagen no válida, reparaste la fuente declarativa de verdad y verificaste la recuperación mediante el estado del despliegue, los registros y comandos ejecutados dentro del contenedor.
La lección central es elegir pruebas que correspondan a la etapa actual del ciclo de vida de la carga de trabajo. Cuando un contenedor aún no se ha iniciado, inspecciona el estado y los eventos. Una vez que está en ejecución, los registros y exec pueden revelar el comportamiento a nivel de aplicación. En el siguiente desafío tendrás que aplicar este flujo de trabajo de manera independiente.


