- Implementación de construcciones multi-etapa para separar el entorno de compilación del de ejecución.
- Reducción drástica del peso de la imagen mediante el uso de distribuciones ligeras como Alpine o Distroless.
- Mejora de la postura de seguridad al minimizar la superficie de ataque y eliminar herramientas innecesarias.
- Optimización del ciclo de vida del despliegue mediante la gestión eficiente de capas y el uso de herramientas de análisis.

Seguramente te ha pasado que, al revisar tus contenedores, te encuentras con imágenes que pesan gigas enteros sin una razón clara. No es solo una cuestión de espacio en el disco; tener un tamaño excesivo en las imágenes provoca que los despliegues sean lentos como una tortuga y que la infraestructura consuma recursos de forma totalmente ineficiente.
Para solucionar este problema, no basta con borrar un par de archivos a mano. Necesitamos aplicar estrategias de ingeniería en el crear imágenes personalizadas Dockerfile para lograr que nuestros contenedores sean ligeros, rápidos y, sobre todo, seguros. A lo largo de este artículo, vamos a desglosar cómo pasar de una imagen pesada a una versión optimizada que funcione de lujo en producción.
El concepto de capas y cómo afectan al peso
Para entender la optimización, primero hay que pillar cómo funciona Docker por dentro. Las imágenes no son un bloque sólido, sino que están formadas por capas superpuestas. Cada instrucción que escribes en el Dockerfile, como un RUN, COPY o ADD, genera una capa nueva que se añade a la anterior.
El problema viene cuando añadimos herramientas, instalamos paquetes y luego los borramos en una instrucción distinta. Docker guarda la historia de cada capa, por lo que el espacio ocupado por esos archivos temporales sigue ahí, aunque ya no los veas en la versión final. Por eso, es fundamental combinar comandos en una sola línea (usando &&) para evitar la creación de capas redundantes.

La técnica de Multi-stage Builds: Dividir para vencer
El multi-stage build es, probablemente, el truco más potente para reducir el peso. Consiste básicamente en usar múltiples instrucciones FROM en un mismo archivo. Imagina que tienes una fase de «cocina» donde preparas todo y una fase de «emplatado» donde solo pones lo que el cliente va a comer.
- Etapa de construcción (Build Stage): Aquí usamos una imagen robusta con todo el arsenal: compiladores, SDKs, gestores de paquetes y herramientas de desarrollo. Es donde el código se transforma en un binario o se transpilan los archivos.
- Etapa de ejecución (Runtime Stage): En esta fase empezamos de cero con una imagen minimalista. Lo único que hacemos es copiar los artefactos ya compilados desde la etapa anterior. Todo el «ruido» de la compilación se queda fuera de la imagen final.
Esta técnica es oro puro para lenguajes compilados como Go o Rust, pero también sirve para Java (usando el JDK para build y el JRE para run) o incluso para TypeScript, donde solo necesitamos el código JavaScript resultante y las dependencias de producción, mandando el compilador de TS a la basura.
Imágenes base: De Ubuntu a Alpine y Distroless
Elegir la imagen base es como elegir los cimientos de una casa; si pones demasiada paja, el resultado será mediocre. En lugar de usar imágenes genéricas y pesadas como Ubuntu, es muy recomendable pasarse a Alpine Linux, que es una distribución ultra ligera orientada a la seguridad y la eficiencia.
Si queremos llevar la optimización al extremo, existen las imágenes Distroless, impulsadas por Google. Estas imágenes no tienen ni siquiera un shell (intérprete de comandos), lo que significa que solo contienen la aplicación y sus dependencias mínimas. Al eliminar el shell y las utilidades del sistema, no solo reducimos el peso al mínimo, sino que hacemos que sea casi imposible para un atacante ejecutar comandos dentro del contenedor.
Para casos aún más radicales, como ocurre con Go, podemos usar la imagen scratch. Es literalmente una imagen vacía, la base de todas las bases, lo que permite que el contenedor final ocupe apenas unos pocos megabytes.
Seguridad y eficiencia: Más allá del tamaño
No se trata solo de que la imagen sea pequeña para que el despliegue vuele. Existe una relación directa entre el peso y la seguridad: a más librerías instaladas, mayor es la superficie de ataque. Menos paquetes significan menos vulnerabilidades potenciales que tengan que ser parcheadas.
Otra buena práctica es evitar el uso del usuario root. Ejecutar la aplicación con un usuario sin privilegios evita que, en caso de que alguien logre entrar en el contenedor, tenga control total sobre el sistema. Además, no hay que olvidar el archivo .dockerignore, que es vital para evitar que archivos basura como la carpeta .git o los logs locales acaben dentro de la imagen por error.
Herramientas para analizar y optimizar
A veces es difícil saber dónde está el peso extra. Para eso existen herramientas como Dive, que nos permite hacer una «autopsia» de la imagen. Con Dive podemos navegar por cada capa y ver exactamente qué archivos se añadieron o modificaron, identificando el espacio desperdiciado y sugiriendo mejoras en el orden de las instrucciones.
Por otro lado, tenemos Docker Slim, que automatiza la limpieza de la imagen eliminando lo que no se usa, y BuildKit, que optimiza la velocidad de construcción mediante un cacheo mucho más inteligente y la ejecución de tareas en paralelo. Para cerrar el círculo de calidad, herramientas de escaneo como Trivy nos ayudan a detectar agujeros de seguridad antes de que la imagen llegue al registro.
Al combinar la segmentación de etapas, la elección de bases minimalistas y la limpieza exhaustiva de capas, conseguimos transformar contenedores elefantiásicos en unidades de despliegue ágiles, reduciendo drásticamente los costes de almacenamiento en la nube y mejorando la velocidad de respuesta de nuestras tuberías de CI/CD.
Redactor apasionado del mundo de los bytes y la tecnología en general. Me encanta compartir mis conocimientos a través de la escritura, y eso es lo que haré en este blog, mostrarte todo lo más interesante sobre gadgets, software, hardware, tendencias tecnológicas, y más. Mi objetivo es ayudarte a navegar por el mundo digital de forma sencilla y entretenida.

