🐳 El comienzo de la dieta de imágenes Docker: Desentrañando el árbol genealógico con docker history

A veces, lanzamos una aplicación aparentemente ligera y, al verificar el tamaño de la imagen, ¡supera fácilmente 1 GB! Nos quedamos perplejos, pensando: "¿Pero qué le he puesto?". En esos momentos, lo que necesitamos es desentrañar el 'árbol genealógico' de la imagen.

dieta-de-capas-docker

"¿Qué has comido para crecer tanto?"

Las imágenes Docker son como una cebolla con capas superpuestas. El comando docker history es como una radiografía que nos permite pelar cada una de estas capas para encontrar al 'culpable'.

Su uso básico es muy sencillo.

# Uso básico
docker history [opciones] <nombre_imagen:etiqueta>

# Ejemplo: Ver el historial de mi aplicación
docker history my-app:latest

Al ejecutar el comando, se mostrará un listado completo desde la capa más reciente de la imagen hasta la imagen base, en orden inverso.

IMAGE          CREATED          CREATED BY                                      SIZE
a6215f271958   5 minutes ago    /bin/sh -c #(nop)  CMD ["/bin/sh"]               0B
<missing>      7 weeks ago      /bin/sh -c #(nop) ADD file:f28242cf608f6...     7.81MB

Presta especial atención al campo SIZE. ¿Ves cientos de MB donde debería haber 0B? ¡Ese es el objetivo de nuestra dieta! Con la experiencia, te darás cuenta de que hay lugares que "huelen raro".

**💡 Consejo útil: --no-trunc**

La salida predeterminada trunca los comandos si son demasiado largos. Al añadir la opción --no-trunc, podrás ver el comando completo sin truncar, lo cual es esencial para un análisis preciso.

docker history --no-trunc my-app:latest


Caso práctico: "El culpable fue chown"

Permítanme contarles una historia real que me sucedió. Estaba construyendo un proyecto con archivos de 150MB, pero la imagen resultante superaba los 300MB, un fenómeno extraño. El culpable fueron dos líneas de Dockerfile que parecían bastante inofensivas.

[Método ineficiente: Creación de 2 capas]

# 1. Copiar los archivos (se copian con propiedad de root por defecto)
COPY . .

# 2. Cambiar la propiedad por seguridad (ejecutado como comando separado)
RUN chown -R appuser:appgroup /app

Después de construirlo y verificar con docker history, obtuve este resultado:

IMAGE          CREATED BY                                        SIZE
<layer_id_2>   /bin/sh -c chown -R appuser:appgroup /app         150MB  <-- (¡Punto problemático!)
<layer_id_1>   /bin/sh -c #(nop) COPY dir:abc in /app            150MB

Aquí es donde se revela el lado 'aterrador' de las capas Docker. Cuando se copian 150MB de archivos en el paso 1, se crea una capa. Pero si en el paso 2 se ejecuta chown, Docker 'piensa': "¿Oh? La información del archivo (propiedad) ha cambiado. ¡Entonces debo crear otra capa con el estado modificado!". Así, copia los mismos 150MB y apila una nueva capa.

En resumen, el contenido era idéntico, pero al tener diferentes permisos de propiedad, los archivos se almacenaron por duplicado, duplicando el tamaño de la imagen.


¡La solución es una dieta de una sola línea!

La solución es sencilla: especificar la propiedad desde el principio al copiar los archivos, unificando así las capas.

[Método eficiente: Creación de 1 capa]

# ¡Especifica la propiedad al mismo tiempo que copias!
COPY --chown=appuser:appgroup . .

Si modificamos el Dockerfile de esta manera y volvemos a ejecutar docker history, el resultado es espectacular.

IMAGE          CREATED BY                                               SIZE
<layer_id_1>   /bin/sh -c #(nop) COPY --chown=appuser... dir:abc       150MB

¿Lo ves? Se ha creado una única capa y el tamaño de la imagen ha vuelto a ser de 150MB, ¡mucho más esbelto! Simplemente uniendo dos líneas de comando en una, el tamaño se redujo a la mitad.


Conclusión: ¡Siempre revisa el 'historial' después de construir!

No olvides que las imágenes Docker se construyen con una capa por cada línea de comando.

Así como pruebas tu código después de escribirlo, acostúmbrate a ejecutar docker history --no-trunc después de cada compilación. A medida que te hagas preguntas como "¿Por qué este apt-get es tan pesado?" o "¿Por qué se dividió esta capa innecesariamente?", pronto estarás construyendo sistemas mucho más ligeros y eficientes.

¡Porque las capas innecesarias son el enemigo de tu sistema!


¿Te ha sido útil? Si es así, ¡por favor, dale a 'me gusta'!

También puedes leer artículos relacionados.

Artículos relacionados

Comprendiendo a fondo la memoria compartida de Docker (shm_size e ipc)

Docker: Comunicación entre contenedores a través de puertos de host sin compartir red

Copia de volúmenes Docker: ¿Por qué es necesario hacerlo así?