Cómo usar el comando docker debug para depurar contenedores e imágenes

DockerDockerBeginner
Practicar Ahora

💡 Este tutorial está traducido por IA desde la versión en inglés. Para ver la versión original, puedes hacer clic aquí

Introducción

En este laboratorio, exploraremos cómo depurar eficazmente contenedores e imágenes de Docker utilizando el comando docker debug y otras técnicas relacionadas. Comenzaremos abordando el desafío de depurar contenedores ligeros (slim) que carecen de shell, demostrando cómo ejecutar comandos directamente dentro de su entorno.

A continuación, aprenderemos cómo depurar una imagen ligera (slim) directamente antes de que se ejecute como contenedor. También cubriremos cómo modificar archivos dentro de un contenedor en ejecución con fines de depuración y cómo gestionar el kit de herramientas de depuración utilizando los comandos install y uninstall. Finalmente, obtendremos una comprensión más profunda de los puntos de entrada (entry points) de los contenedores mediante el uso del comando entrypoint.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker(("Docker")) -.-> docker/VolumeOperationsGroup(["Volume Operations"]) docker(("Docker")) -.-> docker/DockerfileGroup(["Dockerfile"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ContainerOperationsGroup -.-> docker/rm("Remove Container") docker/ContainerOperationsGroup -.-> docker/exec("Execute Command in Container") docker/VolumeOperationsGroup -.-> docker/cp("Copy Data Between Host and Container") docker/DockerfileGroup -.-> docker/build("Build Image from Dockerfile") subgraph Lab Skills docker/run -.-> lab-555138{{"Cómo usar el comando docker debug para depurar contenedores e imágenes"}} docker/rm -.-> lab-555138{{"Cómo usar el comando docker debug para depurar contenedores e imágenes"}} docker/exec -.-> lab-555138{{"Cómo usar el comando docker debug para depurar contenedores e imágenes"}} docker/cp -.-> lab-555138{{"Cómo usar el comando docker debug para depurar contenedores e imágenes"}} docker/build -.-> lab-555138{{"Cómo usar el comando docker debug para depurar contenedores e imágenes"}} end

Depuración de un contenedor ligero (slim) sin shell

En este paso, aprenderemos cómo depurar un contenedor ligero (slim) que no tiene un shell instalado. Los contenedores ligeros se utilizan frecuentemente para reducir el tamaño de la imagen y la superficie de ataque, pero pueden ser difíciles de depurar cuando algo falla.

Primero, ejecutemos un contenedor ligero simple que imprime un mensaje y luego finaliza. Usaremos la imagen alpine, que es una distribución de Linux muy pequeña.

docker run alpine echo "Hello from Alpine!"

Deberías ver la salida Hello from Alpine! en tu terminal. Esto confirma que el contenedor se ejecutó correctamente.

Ahora, intentemos ejecutar un comando dentro de este contenedor usando docker exec. Intentaremos ejecutar /bin/sh, que es un shell común.

docker run -d --name slim-container alpine sleep 3600
docker exec -it slim-container /bin/sh

Probablemente verás un mensaje de error indicando que /bin/sh no se encontró. Esto ocurre porque la imagen alpine, en su configuración predeterminada, no incluye un shell como bash o sh. Esta es una característica común de los contenedores ligeros.

Para depurar un contenedor sin shell, podemos usar el comando docker exec para ejecutar un comando específico dentro del entorno del contenedor. Sin embargo, como no hay shell, debemos ejecutar el comando directamente.

Intentemos listar los archivos en el directorio raíz del contenedor. Sabemos que el comando ls generalmente está disponible incluso en entornos mínimos.

docker exec -it slim-container ls /

Deberías ver una lista de directorios y archivos en la raíz del sistema de archivos del contenedor, como bin, etc, lib, etc. Esto demuestra que aún podemos ejecutar comandos directamente dentro del contenedor sin necesidad de un shell.

Finalmente, limpiemos el contenedor que creamos.

docker stop slim-container
docker rm slim-container

Este paso nos mostró cómo interactuar con un contenedor ligero que carece de shell, ejecutando comandos directamente mediante docker exec. En los siguientes pasos, exploraremos otras técnicas de depuración.

Depuración directa de una imagen ligera (slim)

En el paso anterior, aprendimos a interactuar con un contenedor ligero en ejecución. Sin embargo, a veces es necesario inspeccionar el contenido de una imagen ligera antes de ejecutarla como contenedor, o cuando el contenedor falla al iniciar. En este paso, exploraremos cómo depurar directamente una imagen ligera.

Docker proporciona el comando docker run con la capacidad de sobrescribir el entrypoint y comando predeterminados de una imagen. Esto nos permite ejecutar un comando diferente dentro de un contenedor temporal creado a partir de la imagen, dándonos una forma de inspeccionar su contenido.

Usemos nuevamente la imagen alpine. Sabemos que es una imagen ligera y no incluye shell por defecto. Podemos usar docker run para ejecutar directamente un comando como ls / sobre la imagen.

docker run --rm alpine ls /

El flag --rm asegura que el contenedor temporal se elimine automáticamente después de que finalice el comando. Deberías ver el mismo resultado que cuando ejecutamos ls / en el contenedor en ejecución en el paso anterior. Esto confirma que podemos inspeccionar directamente el sistema de archivos de la imagen.

Ahora, verifiquemos si existe un comando específico dentro de la imagen. Por ejemplo, busquemos el comando ping.

docker run --rm alpine which ping

Probablemente verás un mensaje de error como which: not found. Esto indica que el comando ping no está presente en la imagen alpine por defecto. Esta es otra característica de las imágenes ligeras - suelen incluir solo las herramientas mínimas indispensables.

Probemos con un comando que sabemos que existe, como cat.

docker run --rm alpine which cat

Esta vez deberías ver la salida /bin/cat, confirmando que el comando cat está disponible en la imagen.

Esta técnica de usar docker run --rm <image> <command> es muy útil para:

  • Verificar rápidamente el contenido de una imagen
  • Confirmar la presencia de archivos o comandos específicos
  • Comprender la estructura de la imagen
    Sin necesidad de ejecutar un contenedor de larga duración o construir una nueva imagen.

Modificación de archivos en un contenedor en ejecución

En este paso, aprenderemos cómo modificar archivos dentro de un contenedor en ejecución. Esto puede ser útil para propósitos de depuración, como cambiar archivos de configuración o agregar scripts temporales a un contenedor que ya está en funcionamiento.

Comenzaremos ejecutando un contenedor simple basado en la imagen ubuntu, que es más completa que alpine e incluye un shell y utilidades comunes.

docker run -d --name my-ubuntu ubuntu sleep 3600

Este comando ejecuta un contenedor Ubuntu en modo desacoplado (-d) y lo mantiene en ejecución durante una hora usando el comando sleep 3600. Hemos nombrado el contenedor my-ubuntu para facilitar su referencia.

Ahora, usemos docker exec para obtener un shell dentro del contenedor en ejecución.

docker exec -it my-ubuntu /bin/bash

Ahora deberías estar dentro del shell bash del contenedor my-ubuntu. El prompt cambiará para reflejar que estás dentro del contenedor.

Dentro del contenedor, creemos un nuevo archivo en el directorio /tmp.

echo "This is a test file." > /tmp/test_file.txt

Ahora, verifiquemos que el archivo fue creado y contiene el contenido correcto.

cat /tmp/test_file.txt

Deberías ver la salida This is a test file.. Esto confirma que pudimos crear y escribir en un archivo dentro del contenedor en ejecución.

Para salir del shell del contenedor, simplemente escribe exit.

exit

Ahora estás de vuelta en la terminal de tu VM LabEx.

También podemos copiar archivos hacia y desde un contenedor en ejecución usando el comando docker cp. Creemos un archivo en nuestra VM LabEx y copiémoslo al contenedor.

Primero, crea un archivo llamado local_file.txt en tu directorio ~/project.

echo "This file is from the host." > ~/project/local_file.txt

Ahora, copia este archivo al directorio /tmp del contenedor my-ubuntu.

docker cp ~/project/local_file.txt my-ubuntu:/tmp/

El formato para docker cp es docker cp <ruta_origen> <nombre_contenedor>:<ruta_destino> o docker cp <nombre_contenedor>:<ruta_origen> <ruta_destino>.

Verifiquemos que el archivo fue copiado al contenedor. Vuelve al shell del contenedor.

docker exec -it my-ubuntu /bin/bash

Dentro del contenedor, verifica la presencia de local_file.txt en /tmp.

ls /tmp/

Deberías ver local_file.txt listado junto con test_file.txt.

Ahora, veamos el contenido de local_file.txt dentro del contenedor.

cat /tmp/local_file.txt

Deberías ver la salida This file is from the host..

Sal del shell del contenedor nuevamente.

exit

Finalmente, limpiemos el contenedor.

docker stop my-ubuntu
docker rm my-ubuntu

Este paso demostró cómo modificar archivos dentro de un contenedor en ejecución usando docker exec para obtener un shell y comandos Linux estándar, y cómo copiar archivos entre el host y el contenedor usando docker cp.

Gestión del kit de herramientas de depuración con instalación y desinstalación

En este paso, exploraremos cómo agregar y eliminar herramientas de depuración dentro de un contenedor en ejecución. Si bien generalmente se recomienda mantener las imágenes de contenedores de producción mínimas, a veces es necesario instalar herramientas temporales con fines de depuración.

Utilizaremos nuevamente la imagen ubuntu, ya que tiene un gestor de paquetes (apt) que facilita la instalación de software.

Primero, ejecutemos un nuevo contenedor Ubuntu en modo desacoplado.

docker run -d --name debug-ubuntu ubuntu sleep 3600

Ahora, obtengamos un shell dentro del contenedor.

docker exec -it debug-ubuntu /bin/bash

Dentro del contenedor, intentemos usar un comando que no está instalado por defecto, como ping.

ping google.com

Probablemente verás un error de "comando no encontrado".

Para instalar ping y otras utilidades de red, podemos usar el gestor de paquetes apt. Primero, es una buena práctica actualizar la lista de paquetes.

apt update

Este comando obtiene la información más reciente sobre los paquetes disponibles desde los repositorios.

Ahora, instalemos el paquete iputils-ping, que proporciona el comando ping.

apt install -y iputils-ping

El flag -y confirma automáticamente la instalación sin solicitar confirmación.

Una vez completada la instalación, deberías poder usar el comando ping.

ping -c 4 google.com

Deberías ver la salida del comando ping, lo que indica que ahora está disponible y funciona dentro del contenedor.

Cuando hayas terminado de depurar, es recomendable eliminar las herramientas instaladas para mantener el contenedor limpio y reducir su tamaño si decides confirmarlo como una nueva imagen (aunque modificar contenedores en ejecución para producción generalmente no se recomienda).

Para eliminar el paquete iputils-ping, usa apt remove.

apt remove -y iputils-ping

Puedes verificar que ping ya no está disponible.

ping google.com

Deberías ver nuevamente el error "comando no encontrado".

Sal del shell del contenedor.

exit

Finalmente, limpia el contenedor.

docker stop debug-ubuntu
docker rm debug-ubuntu

Este paso demostró cómo instalar y desinstalar temporalmente herramientas de depuración dentro de un contenedor en ejecución usando su gestor de paquetes. Esta es una técnica poderosa para solucionar problemas en contenedores donde las herramientas necesarias no están incluidas en la imagen base.

Comprendiendo los puntos de entrada de contenedores con el comando entrypoint

En este paso, aprenderemos sobre la instrucción ENTRYPOINT en un Dockerfile y cómo afecta la ejecución de un contenedor. El ENTRYPOINT define el comando que se ejecutará cuando inicie un contenedor. Se usa frecuentemente para establecer el ejecutable principal del contenedor.

Creemos un Dockerfile simple que utilice ENTRYPOINT. En tu directorio ~/project, crea un archivo llamado Dockerfile con el siguiente contenido:

FROM alpine
ENTRYPOINT ["echo", "Hello from the entrypoint!"]
CMD ["default", "command"]

Este Dockerfile usa la imagen alpine como base. El ENTRYPOINT está configurado como ["echo", "Hello from the entrypoint!"]. El CMD está configurado como ["default", "command"]. Cuando ambos ENTRYPOINT y CMD están especificados, los argumentos de CMD se pasan como argumentos al comando ENTRYPOINT.

Ahora, construyamos una imagen a partir de este Dockerfile.

docker build -t my-entrypoint-image ~/project

Este comando construye una imagen llamada my-entrypoint-image desde el Dockerfile en el directorio ~/project.

Ejecutemos un contenedor desde esta imagen sin proporcionar ningún comando adicional.

docker run my-entrypoint-image

Deberías ver la salida Hello from the entrypoint! default command. Esto muestra que el comando ENTRYPOINT (echo) se ejecutó, y los argumentos de CMD (default command) se le pasaron.

Ahora ejecutemos el contenedor proporcionando un comando diferente en la línea docker run. Cuando proporcionas un comando en la línea docker run, este sobrescribe la instrucción CMD en el Dockerfile, pero el ENTRYPOINT sigue ejecutándose con el comando proporcionado como argumentos.

docker run my-entrypoint-image "override command"

Deberías ver la salida Hello from the entrypoint! override command. Esto demuestra que el ENTRYPOINT aún se ejecutó, pero los argumentos del comando docker run (override command) reemplazaron los argumentos de CMD.

¿Qué pasa si quieres ignorar completamente el ENTRYPOINT y ejecutar un comando diferente? Puedes usar el flag --entrypoint con docker run.

docker run --entrypoint /bin/echo my-entrypoint-image "Running a different command"

Deberías ver la salida Running a different command. En este caso, el flag --entrypoint sobrescribió el ENTRYPOINT especificado en el Dockerfile, y el comando proporcionado (/bin/echo) se ejecutó con los argumentos (Running a different command).

Entender ENTRYPOINT y CMD es crucial para construir y depurar imágenes Docker. ENTRYPOINT define el ejecutable principal, mientras que CMD proporciona argumentos predeterminados a ese ejecutable o un comando predeterminado si no se establece ENTRYPOINT.

Resumen

En este laboratorio, aprendimos cómo depurar contenedores e imágenes Docker utilizando el comando docker debug y técnicas relacionadas. Comenzamos explorando cómo depurar un contenedor minimalista que carece de shell, demostrando que aún podemos ejecutar comandos directamente dentro del entorno del contenedor usando docker exec, incluso sin un shell tradicional como bash o sh. Esta es una técnica crucial para solucionar problemas en imágenes de contenedores minimalistas.

Aunque el contenido proporcionado solo cubre el primer paso, la estructura general del laboratorio indica que los pasos posteriores profundizarían en:

  • Depurar imágenes minimalistas directamente
  • Modificar archivos dentro de contenedores en ejecución
  • Gestionar el kit de herramientas de depuración con comandos de instalación y desinstalación
  • Comprender los puntos de entrada de contenedores usando el comando entrypoint

Estos pasos mejorarían aún más nuestra capacidad para diagnosticar y resolver problemas en aplicaciones e imágenes Dockerizadas.