Resumen



Al construir imágenes de Docker, a menudo se incrementa el tamaño de manera no intencionada. La mayoría de las veces, esto se debe a capas creadas innecesariamente. En este artículo, compartiré mi experiencia de optimización al usar el comando docker history para verificar la 'genealogía' de una imagen y así lograr una imagen más liviana.

Con este comando, puedes identificar exactamente qué está haciendo que la imagen sea pesada, y crear imágenes más eficientes.


docker history: Ver la genealogía de la imagen

docker history es un comando que muestra cómo se creó una imagen específica y su historial de componentes. Puedes verificar qué capas se construyeron a partir de cada comando en el Dockerfile, así como el momento en que se crearon y su tamaño.

La forma básica de usarlo es muy sencilla.

docker history [opciones] <nombre de imagen:etiqueta>

Por ejemplo, el comando para verificar el historial de la imagen local my-app:latest es el siguiente.

docker history my-app:latest

En los resultados, verás las capas de la imagen desde la más reciente (cima) hasta la imagen base (más antigua) en orden.

IMAGE          CREATED         CREATED BY                                      SIZE
a6215f271958   hace 5 minutos   /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B
<missing>      hace 7 semanas     /bin/sh -c #(nop) ADD file:f28242cf608f6...   7.81MB
  • CREATED BY: El comando del Dockerfile que creó esta capa

  • SIZE: El tamaño ocupado por esta capa

Consejo útil: Ver el comando completo con --no-trunc

La salida predeterminada de docker history puede truncarse a la mitad si el comando en la columna CREATED BY es demasiado largo. En este caso, usar la opción --no-trunc te permitirá ver el comando completo sin cortes, lo que es esencial para un análisis exacto.

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

Por qué es importante analizar capas: Experiencia real de optimización



Las imágenes de Docker se crean siguiendo la regla de que cada línea de comando en el Dockerfile genera una capa. Cada capa representa un 'cambio' por encima de la capa anterior.

El problema es que dividir innecesariamente las capas puede hacer que el tamaño de la imagen aumente drásticamente.

Caso: Trampa de COPY y RUN chown

Al crear un Dockerfile, a menudo copio archivos de proyectos al contenedor (COPY) y luego cambio la propiedad de esos archivos a un usuario específico (por ejemplo, appuser) (RUN chown).

Método ineficiente: 2 capas

Originalmente, escribí el Dockerfile de la siguiente manera.

# 1. Copiar los archivos (se copian como root)
COPY . .

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

Al verificar el historial de la imagen construida con docker history, vi que se crearon dos capas.

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

Aquí surge un problema serio.

  1. Con el comando COPY . ., se añadieron archivos de 150MB a capa 1.

  2. El comando RUN chown copió los archivos de 150MB de la capa 1 y solo cambió la información de propiedad, guardándola como nueva en capa 2.

El contenido de los archivos es el mismo, pero uno está almacenado como propiedad de root y otro como propiedad de appuser, en capas diferentes. Como resultado, el tamaño total de la imagen es de 300MB (150MB + 150MB).

Método eficiente: 1 capa

Este problema se puede resolver fácilmente utilizando la opción --chown del comando COPY.

# 1. Copia y asigna la propiedad al mismo tiempo
COPY --chown=appuser:appgroup . .

Después de modificar el Dockerfile de esta manera, volví a verificar con docker history.

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

Se creó solo una capa y el tamaño total de la imagen se redujo a 150MB. Al combinar solo dos comandos en uno, el tamaño de la imagen se redujo a casi la mitad.


Conclusión

docker history no solo se utiliza para ver el historial de creación de una imagen, sino que es una herramienta clave para la optimización de imágenes.

Después de modificar un Dockerfile, es recomendable ejecutar habitualmente docker history --no-trunc para verificar que las capas se crearon como se pretendía y que no hay capas ocupando espacio innecesariamente. Esta pequeña costumbre puede resultar en la creación de imágenes ligeras y eficientes.