Un multi-stage build en Docker es una característica que permite crear imágenes de Docker más eficientes y optimizadas mediante el uso de múltiples etapas de construcción. Cada etapa puede utilizar una imagen base diferente y realizar tareas específicas, lo que permite separar el proceso de compilación del entorno de ejecución final.Las principales ventajas de los multi-stage builds son:1. Reducción del tamaño de la imagen final: Al separar las etapas de compilación y ejecución, se pueden eliminar archivos y dependencias innecesarios del entorno de ejecución, lo que resulta en imágenes más pequeñas y ligeras.2. Mejora de la seguridad: Al utilizar imágenes base específicas para cada etapa, se reduce la superficie de ataque y se minimiza el riesgo de incluir vulnerabilidades en la imagen final.3. Mayor flexibilidad: Los multi-stage builds permiten utilizar diferentes herramientas y dependencias en cada etapa, lo que facilita la creación de imágenes personalizadas para diferentes entornos y casos de uso.4. Reutilización de código: Las etapas intermedias pueden ser reutilizadas en múltiples imágenes, lo que reduce la duplicación de código y facilita el mantenimiento.Para crear un multi-stage build, se utilizan múltiples instrucciones `FROM` en el Dockerfile, cada una iniciando una nueva etapa. Las etapas pueden copiar artefactos de etapas anteriores utilizando la instrucción `COPY --from=`. La última etapa define la imagen final que se creará.Ejemplo de un Dockerfile con multi-stage build:```dockerfile # Etapa de compilación FROM golang:1.16 AS builder WORKDIR /app COPY . . RUN go build -o myapp .# Etapa de ejecución FROM alpine:latest RUN apk --no-cache add ca-certificates WORKDIR /root/ COPY --from=builder /app/myapp . CMD ["./myapp"] ```En este ejemplo, la primera etapa utiliza la imagen base `golang:1.16` para compilar la aplicación Go. La segunda etapa utiliza la imagen base `alpine:latest` y copia el binario compilado de la etapa anterior, creando una imagen final más pequeña y optimizada para la ejecución.Los multi-stage builds son una herramienta poderosa para crear imágenes de Docker eficientes y seguras, y son ampliamente utilizados en la industria para optimizar el proceso de construcción y despliegue de aplicaciones en contenedores.

A multi-stage build in Docker allows developers to use multiple FROM statements in a single Dockerfile. This technique optimizes image size by separating the build environment from the final product.
Índice
what-is-a-multi-stage-build-in-docker-2

Comprensión de las Construcciones Multi-Etapa en Docker

Docker ha revolucionado la forma en que pensamos sobre la construcción, envío y ejecución de aplicaciones. A medida que la demanda de aplicaciones ligeras, eficientes y fácilmente desplegables continúa aumentando, también lo hace la necesidad de técnicas avanzadas que agilicen el flujo de trabajo de desarrollo. Una de esas técnicas es la construcción de múltiples etapas, que juega un papel esencial en la optimización de imágenes Docker. Este artículo explicará qué son las construcciones de múltiples etapas, sus beneficios, cómo funcionan y las mejores prácticas para utilizarlas de manera efectiva.

Un Multi-Stage Build es una característica de Docker que permite crear imágenes más pequeñas y eficientes al dividir el proceso de construcción en varias etapas. Cada etapa puede utilizar una imagen base diferente y realizar tareas específicas, como compilar código fuente o instalar dependencias. Al final, solo se copia el resultado final de la última etapa a la imagen final, eliminando archivos innecesarios y reduciendo el tamaño total de la imagen.Esto es especialmente útil cuando se necesita compilar aplicaciones desde el código fuente, ya que se pueden utilizar herramientas de compilación pesadas en etapas intermedias sin que estas se incluyan en la imagen final. Por ejemplo, se puede utilizar una imagen con un compilador de Go en una etapa para compilar la aplicación, y luego copiar el binario resultante a una imagen base más ligera en la siguiente etapa.Los Multi-Stage Builds se definen en el Dockerfile utilizando múltiples instrucciones FROM, cada una iniciando una nueva etapa. Se puede copiar archivos entre etapas utilizando la instrucción COPY --from, especificando el nombre o el índice de la etapa de origen.

A multi-stage build is a feature in Docker that allows you to use multiple FROM declaraciones en un único Dockerfile. Esto permite la creación de imágenes optimizadas al separar el entorno de construcción del entorno de ejecución. Con un build multi-etapa, puedes compilar tu aplicación en una etapa y luego copiar solo los artefactos necesarios a la imagen final en otra etapa. Esto reduce el tamaño de la imagen final y solo incluye los archivos necesarios para ejecutar la aplicación, ayudando a mantener tus contenedores ligeros y eficientes.

This powerful feature was introduced in Docker 17.05 and has since become a popular practice among developers looking to enhance their Docker workflows.

¿Por qué utilizar construcciones de múltiples etapas?

1. Tamaño de imagen reducido

Una de las ventajas más significativas de las compilaciones de múltiples etapas es la reducción del tamaño de la imagen. Las compilaciones tradicionales de Docker a menudo incluyen dependencias de compilación y archivos innecesarios en la imagen final, lo que puede llevar a imágenes infladas. Con las compilaciones de múltiples etapas, puedes asegurarte de que solo los archivos necesarios para el tiempo de ejecución estén incluidos en la imagen final. Esto no solo ahorra espacio en disco, sino que también acelera el proceso de implementación al reducir el tiempo necesario para extraer la imagen de un registro.

2. Dockerfile simplificado

Multi-stage builds can simplify your Dockerfile by breaking it down into distinct stages. Each stage can have its own set of dependencies and configurations, which allows for better organization and clarity. Developers can easily see what is being built, how it is being built, and what is included in the final image.

3. Seguridad Mejorada

By minimizing the number of files and dependencies included in the final image, multi-stage builds can enhance security. A smaller attack surface means fewer potential vulnerabilities. Additionally, you can avoid including developer tools, build scripts, and other sensitive information in the production image.

4. Tiempos de compilación mejoradosEl tiempo de compilación es un factor crítico en el desarrollo de software, especialmente en proyectos grandes y complejos. Los desarrolladores pasan una cantidad significativa de tiempo esperando a que sus cambios se compilen y se prueben. Por lo tanto, cualquier mejora en los tiempos de compilación puede tener un impacto significativo en la productividad y la eficiencia del equipo de desarrollo.Existen varias estrategias y técnicas que pueden ayudar a mejorar los tiempos de compilación:1. Compilación incremental: Esta técnica permite que solo se vuelvan a compilar los archivos que han cambiado desde la última compilación, en lugar de volver a compilar todo el proyecto. Esto puede reducir significativamente el tiempo de compilación, especialmente en proyectos grandes.2. Paralelización: Al aprovechar múltiples núcleos de CPU, es posible compilar diferentes partes del proyecto simultáneamente, lo que puede reducir drásticamente el tiempo total de compilación.3. Optimización de dependencias: Reducir las dependencias innecesarias entre los módulos del proyecto puede ayudar a minimizar la cantidad de código que necesita ser recompilado cuando se realizan cambios.4. Uso de caché: Almacenar en caché los resultados de compilaciones anteriores puede acelerar significativamente las compilaciones posteriores, especialmente para cambios menores.5. Optimización del código: Escribir código más eficiente y modular puede ayudar a reducir el tiempo de compilación al minimizar la complejidad y las dependencias.6. Herramientas de compilación avanzadas: Utilizar herramientas de compilación modernas y optimizadas puede proporcionar mejoras significativas en los tiempos de compilación en comparación con las herramientas más antiguas.7. Compilación distribuida: En proyectos muy grandes, distribuir el proceso de compilación en múltiples máquinas puede ayudar a reducir el tiempo total de compilación.8. Perfilado y optimización: Identificar y optimizar las partes del proceso de compilación que consumen más tiempo puede llevar a mejoras significativas en el rendimiento general.9. Uso de compilación anticipada: Para lenguajes que lo admiten, la compilación anticipada de ciertas partes del código puede ayudar a reducir el tiempo de compilación en tiempo de ejecución.10. Gestión eficiente de recursos: Asegurarse de que el sistema de compilación tenga acceso a recursos adecuados (CPU, memoria, almacenamiento) puede ayudar a optimizar los tiempos de compilación.Al implementar estas estrategias, los equipos de desarrollo pueden lograr mejoras significativas en los tiempos de compilación, lo que a su vez puede conducir a un desarrollo más rápido, iteraciones más rápidas y una mayor productividad general.

Las compilaciones multi-etapa pueden acelerar los tiempos de build al permitirte almacenar en caché las capas intermedias. Docker almacena en caché cada capa de una imagen, por lo que si una capa no ha cambiado, Docker puede reutilizarla en builds posteriores. Al organizar efectivamente tu Dockerfile en etapas, puedes aprovechar este mecanismo de caché y reducir el tiempo dedicado a las compilaciones.

5. Flexibilidad en los entornos de compilación

Las compilaciones de múltiples etapas te permiten utilizar diferentes imágenes base para cada etapa. Por ejemplo, podrías usar una imagen más pesada con todas las dependencias de desarrollo para construir tu aplicación y una imagen mínima para el entorno de ejecución final. Esta flexibilidad te permite optimizar tus imágenes según las necesidades específicas de cada etapa.

Cómo funcionan las construcciones de múltiples etapasEn el capítulo anterior, creamos una imagen de Docker para una aplicación web de Python. El Dockerfile que usamos para construir la imagen se ve así:```dockerfile FROM python:3.9-slimRUN pip install Flask==2.0.1COPY app.py /app/EXPOSE 5000CMD ["python", "/app/app.py"] ```El problema con este Dockerfile es que cada vez que hacemos un cambio en el código fuente, tenemos que reconstruir toda la imagen. Esto puede ser lento, especialmente si la imagen es grande.Para solucionar este problema, podemos usar construcciones de múltiples etapas. Una construcción de múltiples etapas es un Dockerfile que tiene múltiples instrucciones FROM. Cada instrucción FROM comienza una nueva etapa de la construcción. La última etapa es la que se convierte en la imagen final.Aquí hay un ejemplo de un Dockerfile que usa construcciones de múltiples etapas:```dockerfile FROM python:3.9-slim AS builderRUN pip install Flask==2.0.1COPY app.py /app/FROM python:3.9-slim AS runnerCOPY --from=builder /app/app.py /app/EXPOSE 5000CMD ["python", "/app/app.py"] ```En este Dockerfile, la primera etapa se llama "builder". Esta etapa instala Flask y copia el código fuente en la imagen. La segunda etapa se llama "runner". Esta etapa copia el código fuente de la etapa "builder" y expone el puerto 5000.Cuando construimos esta imagen, Docker solo copia los archivos de la etapa "builder" a la etapa "runner". Esto significa que no tenemos que reconstruir toda la imagen cada vez que hacemos un cambio en el código fuente.Las construcciones de múltiples etapas son una herramienta poderosa que puede ayudarte a crear imágenes de Docker más eficientes. Si estás construyendo imágenes de Docker para aplicaciones grandes, te recomiendo que uses construcciones de múltiples etapas.

To understand how multi-stage builds work, let’s break down the process with an example. Consider a simple application written in Go. In a traditional Dockerfile, you might see something like this:

FROM golang:1.16 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .

FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]

Explicación del Ejemplo

  1. Primera Etapa (Etapa de Construcción)

    In the first stage, we use the official Go image (golang:1.16) como imagen base. Esta imagen contiene todas las herramientas necesarias para compilar aplicaciones Go. Establecemos el directorio de trabajo en /app, copie el código de la aplicación en el contenedor y ejecútelo. go build El comando para compilar la aplicación. El resultado es un ejecutable binario llamado myapp.

  2. Segunda Etapa (Etapa Final)

    In the second stage, we use a much smaller base image, alpine:latest, which is minimal and designed for running applications. We set the working directory to /app and use the COPY --from=builder comando para copiar solo el binario compilado de la primera etapa a esta imagen final.

  3. Ejecutando la aplicación

    Finalmente, especificamos el comando para ejecutar nuestra aplicación utilizando el Símbolo del sistema directive. The resulting image is significantly smaller since it only contains the myapp binario y el entorno de ejecución mínimo.

Multi-Stage Build with Multiple Stages

También puedes crear compilaciones de varias etapas más complejas que involucren varias etapas. Por ejemplo, es posible que desees ejecutar pruebas en una etapa determinada antes de proceder a la imagen final. Aquí tienes un ejemplo de un Dockerfile de varias etapas que incluye una etapa de prueba:

FROM golang:1.16 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp .

FROM golang:1.16 AS test
WORKDIR /app
COPY --from=builder /app/myapp .
RUN go test ./...

FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]

En este caso, hemos añadido una etapa de prueba que utiliza la imagen de Go nuevamente. Las pruebas se ejecutarán contra el binario construido en la primera etapa. Si las pruebas pasan, la etapa final copiará el binario en la imagen de Alpine.

Mejores prácticas para construcciones de varias etapas

Para aprovechar al máximo los builds multietapa, considere las siguientes buenas prácticas:

1. Use Specific Tags for Base Images

Al especificar imágenes base, usa etiquetas específicas en lugar de la etiqueta `latest`. latest. Using specific tags helps ensure that your builds are reproducible and do not break due to unexpected changes in the base image.

2. Mantén las etapas enfocadas

Each stage should have a single responsibility. For example, one stage should be dedicated to building the application, while another should handle testing or packaging. This makes your Dockerfile easier to maintain and understand.

3. Optimize for Caching

Take advantage of Docker’s caching mechanism by ordering your commands strategically. Place commands that change infrequently at the top, allowing Docker to cache those layers and speed up subsequent builds.

4. Minimiza las capas

Aunque las compilaciones de múltiples etapas pueden ayudar a reducir el tamaño de la imagen, ten cuidado con el número de capas que creas. Cada comando en un Dockerfile crea una nueva capa, así que considera combinar comandos cuando sea apropiado para minimizar el número de capas.

5. Limpieza de artefactos de compilación

If you have any temporary files or build artifacts that are not needed in the final image, make sure to clean them up in the final stage. This further reduces the size of the image and enhances security.

6. Aprovechar las variables de entorno

You can use environment variables to configure your application at runtime. By defining variables in the final stage, you can keep your build stages clean and focused on their specific tasks.

Conclusión

Multi-stage builds are a powerful feature in Docker that enables developers to create optimized, efficient, and secure images. By leveraging this technique, you can significantly reduce image sizes, improve build times, and keep your Dockerfiles organized and manageable. As containerization continues to gain traction, understanding and implementing multi-stage builds will be an essential skill for developers looking to streamline their workflows and enhance their applications.

By following best practices and using multi-stage builds effectively, you can ensure that your Docker images are not only lightweight but also secure and performant, making your applications ready for deployment in today’s fast-paced development environment.