Multi-Stage Builds: Building Efficient Docker Images
Docker ha revolucionado la forma en que desplegamos y gestionamos aplicaciones. Una de las innovaciones más significativas en Docker es el concepto de construcciones de múltiples etapas, que permite a los desarrolladores crear imágenes de Docker optimizadas y eficientes con un tamaño mínimo y un tiempo de construcción mejorado. En este artículo, exploraremos los entresijos de las construcciones de múltiples etapas, sus ventajas y las mejores prácticas para asegurarnos de que obtengas el máximo provecho de esta potente característica.
Understanding Docker Images and Layers
Antes de profundizar en las builds multi-etapa, es esencial comprender cómo funcionan las imágenes de Docker. Una imagen de Docker es una plantilla de solo lectura que contiene todo lo necesario para ejecutar una aplicación, incluyendo código, bibliotecas y herramientas del sistema. Las imágenes están compuestas por capas, donde cada capa representa un conjunto de cambios realizados sobre la imagen base. Las capas se apilan unas sobre otras, y Docker utiliza un mecanismo de copia al escribir (copy-on-write) para gestionar estas capas de manera eficiente.
Cada capa se almacena en caché después de ser creada, lo que significa que al reconstruir una imagen, Docker puede omitir las capas no modificadas, lo que puede acelerar el proceso de construcción. Sin embargo, a medida que las aplicaciones se vuelven más complejas, las imágenes de Docker pueden aumentar de tamaño, provocando tiempos de despliegue más lentos y un mayor uso de recursos.
El Problema con las Construcciones Tradicionales de Docker
En las compilaciones tradicionales de Docker, los desarrolladores suelen incluir todas las herramientas y dependencias necesarias durante el proceso de compilación en la imagen final. Por ejemplo, al compilar una aplicación en Go, la imagen podría contener el compilador de Go, herramientas de build y bibliotecas. Este enfoque da como resultado:
- Larger Image SizeLa imagen final incluye herramientas de compilación innecesarias, inflando el tamaño.
- Security Risks: Including build tools and dependencies increases the attack surface of the image.
- Tiempos de despliegue más largosEl despliegue de un sistema de IA puede llevar mucho tiempo, especialmente si el sistema es complejo o si hay muchos datos que procesar. Esto puede ser un problema para las empresas que necesitan implementar sistemas de IA rápidamente para mantenerse competitivas.Hay varias razones por las que el despliegue de un sistema de IA puede llevar mucho tiempo. Una razón es que los sistemas de IA a menudo requieren grandes cantidades de datos para entrenarlos. Este proceso de entrenamiento puede llevar mucho tiempo, especialmente si los datos son complejos o si hay muchos datos que procesar.Otra razón por la que el despliegue de un sistema de IA puede llevar mucho tiempo es que los sistemas de IA a menudo requieren mucha potencia de cómputo para ejecutarse. Esto puede ser un problema para las empresas que no tienen acceso a la potencia de cómputo necesaria.Finalmente, el despliegue de un sistema de IA puede llevar mucho tiempo porque los sistemas de IA a menudo requieren mucha experiencia para implementarlos. Esto puede ser un problema para las empresas que no tienen acceso a la experiencia necesaria.Hay varias cosas que las empresas pueden hacer para reducir el tiempo de despliegue de un sistema de IA. Una cosa que las empresas pueden hacer es utilizar plataformas de IA que estén diseñadas para ser fáciles de usar. Estas plataformas pueden ayudar a las empresas a implementar sistemas de IA rápidamente sin necesidad de tener mucha experiencia.Otra cosa que las empresas pueden hacer es utilizar servicios de IA que estén alojados en la nube. Estos servicios pueden ayudar a las empresas a implementar sistemas de IA rápidamente sin necesidad de tener acceso a la potencia de cómputo necesaria.Finalmente, las empresas pueden utilizar servicios de IA que estén diseñados para ser escalables. Estos servicios pueden ayudar a las empresas a implementar sistemas de IA rápidamente sin necesidad de tener acceso a la experiencia necesaria.En general, el despliegue de un sistema de IA puede llevar mucho tiempo. Sin embargo, hay varias cosas que las empresas pueden hacer para reducir el tiempo de despliegue. Al utilizar plataformas de IA fáciles de usar, servicios de IA alojados en la nube y servicios de IA escalables, las empresas pueden implementar sistemas de IA rápidamente y mantenerse competitivas.Las imágenes más grandes tardan más en transferirse a los entornos de producción.
Para abordar estos problemas, Docker introdujo las compilaciones de múltiples etapas, lo que le permite separar el entorno de compilación del entorno de tiempo de ejecución final.
What Are Multi-Stage Builds?
Las compilaciones multietapa permiten utilizar múltiples FROM statements in the same Dockerfile to create separate build environments. Each stage can have its own base image, which means you can use more extensive images for building and lighter images for production. The final image can then copy only the necessary artifacts from the intermediate stages, significantly reducing the image size.
Aquí está la sintaxis básica de una compilación de múltiples etapas:
# Etapa 1: Constructor
FROM golang:1.16 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# Etapa 2: Imagen Final
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/myapp .
CMD ["./myapp"]En este ejemplo, tenemos dos etapas: la primera compila una aplicación Go, mientras que la segunda crea una imagen minimalista de Alpine que ejecuta la aplicación. La imagen final contiene únicamente el binario compilado, excluyendo el compilador de Go y cualquier otra herramienta de compilación.
Las ventajas de las construcciones de múltiples etapasLas construcciones de múltiples etapas son una característica poderosa en Docker que permite optimizar el proceso de construcción de imágenes de contenedores. Esta técnica ofrece varias ventajas significativas:1. Reducción del tamaño de la imagen final: Al utilizar múltiples etapas, es posible separar el proceso de construcción del entorno de ejecución. Esto permite eliminar dependencias y herramientas de compilación que no son necesarias en la imagen final, resultando en imágenes mucho más pequeñas y eficientes.2. Mejora de la seguridad: Al excluir herramientas de compilación y dependencias innecesarias de la imagen final, se reduce la superficie de ataque del contenedor. Esto disminuye el riesgo de vulnerabilidades de seguridad en el entorno de producción.3. Mayor claridad en el proceso de construcción: Las construcciones de múltiples etapas permiten organizar el proceso de construcción en etapas lógicas y separadas. Esto facilita la comprensión y el mantenimiento del Dockerfile, especialmente en proyectos complejos.4. Reutilización de artefactos: Es posible reutilizar artefactos generados en etapas anteriores en etapas posteriores, lo que puede acelerar el proceso de construcción y reducir la redundancia.5. Separación de entornos: Permite utilizar diferentes imágenes base para las etapas de compilación y ejecución, lo que brinda flexibilidad para elegir las herramientas y dependencias más adecuadas para cada etapa del proceso.6. Optimización del caché: Docker puede aprovechar el caché de manera más eficiente en construcciones de múltiples etapas, ya que los cambios en una etapa no afectan necesariamente a las etapas posteriores.7. Facilita la depuración: Al separar el proceso de compilación del entorno de ejecución, es más fácil identificar y solucionar problemas en etapas específicas del proceso de construcción.8. Mejora en la gestión de dependencias: Permite gestionar las dependencias de compilación y ejecución de manera independiente, lo que puede simplificar la actualización y el mantenimiento de las dependencias.9. Compatibilidad con diferentes lenguajes y frameworks: Las construcciones de múltiples etapas son particularmente útiles para proyectos que utilizan lenguajes de programación o frameworks que requieren herramientas de compilación específicas.10. Reducción de tiempos de despliegue: Al tener imágenes más pequeñas y optimizadas, los tiempos de descarga y despliegue de los contenedores se reducen significativamente.En resumen, las construcciones de múltiples etapas en Docker ofrecen una serie de ventajas que pueden mejorar significativamente la eficiencia, seguridad y mantenibilidad de las imágenes de contenedores. Estas ventajas hacen que esta técnica sea especialmente valiosa en entornos de producción y en proyectos de software a gran escala.
1. Tamaño de imagen reducido
By copying only the necessary artifacts from the build stage, you can significantly reduce the size of your final image. This reduction leads to faster deployments and less disk space usage.
2. Tiempos de compilación mejorados
Multi-stage builds allow you to cache intermediate layers effectively. When you change code in the source stage, Docker can reuse the unchanged layers, speeding up the build process.
3. Seguridad Mejorada
Al excluir las herramientas de compilación y las dependencias innecesarias de la imagen final, se reduce la superficie de ataque y se mejora la postura de seguridad de la aplicación.
4. Gestión Simplificada de Dockerfile
Con las builds multi-etapa, puedes mantener todas las instrucciones relacionadas con la construcción en un solo Dockerfile. Este enfoque facilita la gestión de tus configuraciones de Docker y reduce el riesgo de inconsistencias en múltiples Dockerfiles.
5. Language and Framework Agnostic
Multi-stage builds can be applied to any programming language or framework. Whether you’re building a Node.js application, a Java service, or a Python script, you can take advantage of this feature to optimize your Docker images.
Mejores prácticas para construcciones de varias etapas
Aunque las compilaciones de múltiples etapas ofrecen numerosas ventajas, seguir las mejores prácticas puede ayudarte a maximizar su efectividad:
1. Use Specific Base Images
Choose base images that are optimized for your use case. For example, use alpine para imágenes de producción ligeras o debian for images needing more extensive libraries. This choice can significantly impact the final image size.
2. Minimiza las DependenciasEn el desarrollo de software, una dependencia es cualquier pieza de código que tu programa necesita para funcionar pero que no forma parte de tu base de código principal. Esto puede incluir bibliotecas, marcos de trabajo, sistemas operativos, hardware específico, etc. Minimizar las dependencias es una práctica crucial para crear software más robusto, mantenible y portátil.¿Por qué minimizar las dependencias?1. Reducción de riesgos: Cada dependencia adicional introduce un punto potencial de fallo. Si una biblioteca de terceros deja de ser mantenida o tiene una vulnerabilidad de seguridad, tu software también se ve afectado.2. Facilidad de mantenimiento: Cuantas menos dependencias tengas, menos actualizaciones y parches tendrás que gestionar. Esto reduce la carga de trabajo a largo plazo.3. Portabilidad: El software con menos dependencias es generalmente más fácil de portar a diferentes plataformas o entornos.4. Tamaño del paquete: Menos dependencias significan un paquete de software más pequeño, lo que puede ser crucial para aplicaciones web o móviles.5. Control: Al minimizar las dependencias, tienes más control sobre el comportamiento y el rendimiento de tu software.Estrategias para minimizar dependencias:1. Implementación interna: Siempre que sea posible, implementa la funcionalidad tú mismo en lugar de depender de bibliotecas externas. Esto te da un control total sobre el código.2. Usa dependencias ligeras: Cuando necesites una biblioteca externa, opta por las más pequeñas y especializadas en lugar de las grandes y monolíticas.3. Estándares y protocolos: Utiliza estándares y protocolos abiertos en lugar de APIs propietarias siempre que sea posible.4. Inyección de dependencias: Utiliza patrones de diseño como la inyección de dependencias para hacer que tu código sea más modular y fácil de probar.5. Versionamiento cuidadoso: Cuando uses dependencias, sé conservador con las actualizaciones y prueba exhaustivamente antes de actualizar a nuevas versiones.6. Alternativas nativas: Antes de añadir una dependencia, considera si el lenguaje o framework que estás usando ya proporciona funcionalidad similar de forma nativa.7. Evaluación regular: Revisa periódicamente tus dependencias para asegurarte de que siguen siendo necesarias y están actualizadas.Ejemplo práctico:Imagina que estás desarrollando una aplicación web y necesitas realizar solicitudes HTTP. En lugar de añadir una biblioteca completa como Axios, podrías usar la API Fetch nativa del navegador, que está disponible en la mayoría de los navegadores modernos y reduce significativamente tu dependencia externa.Conclusión:Minimizar las dependencias es una práctica esencial en el desarrollo de software moderno. No solo hace que tu código sea más robusto y fácil de mantener, sino que también te da más control sobre tu producto final. Sin embargo, es importante encontrar un equilibrio: a veces, añadir una dependencia bien mantenida y ampliamente utilizada puede ahorrar tiempo y esfuerzo a largo plazo. La clave está en tomar decisiones informadas y revisar regularmente tus dependencias para asegurarte de que siguen siendo la mejor opción para tu proyecto.
Only include dependencies that are necessary for your application to run. Review your Dockerfile and ensure that you are not unintentionally including development dependencies in the final image.
3. Mantener separadas las etapas de compilación
Organiza tu Dockerfile para mantener las etapas de construcción distintas. Esta claridad ayuda a mantener el Dockerfile y comprender el proceso de construcción. Agrupa tareas similares para mejorar la legibilidad.
4. Leverage Build Arguments
Use build arguments to customize your build process based on the environment (development, testing, production). Build arguments allow you to pass variables to your build process, enabling you to avoid hardcoding values in your Dockerfile.
ARG NODE_ENV=production
FROM node:14 AS builder
WORKDIR /app
COPY package.json .
RUN npm install --only=$NODE_ENV
COPY . .
RUN npm run build5. Optimize COPY Instructions
Utilice rutas específicas en su COPIA statements to avoid copying unnecessary files. The more specific you are, the smaller your image size will be. For example, instead of copying everything from your source directory:
COPIAR . .Consider copying only what’s needed:
COPIA src/ ./src
COPIA package.json ./6. Limpiar después de la compilación
Si tu proceso de build genera archivos temporales o artefactos innecesarios, asegúrate de limpiarlos en la etapa de build. Puedes usar... CORRE commands to remove unneeded files to keep the image size small.
Ejecutar npm install && npm cache clean --force7. Multi-Stage Testing
También puedes incorporar pruebas dentro de tus compilaciones de múltiples etapas. Crea una etapa separada para ejecutar pruebas y asegurarte de que tu aplicación funciona como se espera antes de pasar a la imagen final.
# Etapa 1: Construcción
FROM node:14 AS constructor
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
# Etapa 2: Pruebas
FROM constructor AS pruebas
RUN npm test
# Etapa 3: Imagen Final
FROM alpine:latest
WORKDIR /app
COPY --from=constructor /app .
CMD ["node", "src/index.js"]Debugging Multi-Stage Builds
Depurar compilaciones de varias etapas puede ser desafiante, especialmente cuando surgen problemas. Aquí hay algunos consejos para ayudarte a solucionar problemas:
1. Utilice Contenedores Intermedios
If you encounter errors during the build process, you can run an intermediate container from any stage of your Dockerfile. To do this, build the image up to the desired stage and then run a container based on that stage:
docker build --target builder -t myapp:builder .
docker run -it myapp:builder /bin/sh2. Registros de Salida
Incorpora el registro de eventos (logging) en tu proceso de compilación para capturar la salida de tus scripts y comandos. Puedes usar CORRE Comandos para registrar la salida en un archivo o en la consola con el fin de diagnosticar problemas:
EJECUTAR npm run build && echo "Compilación completada" || echo "Compilación fallida"3. Inspect Layers
You can inspect the layers of your image using the docker historyMuestra el historial de una imagen. comando. Este comando muestra el tamaño y los comandos asociados con cada capa, lo que te ayuda a identificar posibles problemas:
docker historial myapp4. Test Incrementally
Al realizar cambios en tu Dockerfile, prueba de forma incremental para aislar problemas. Comienza con una construcción simple y añade gradualmente complejidad, asegurándote de que cada adición funcione como se espera.
Conclusión
Las construcciones multietapa son una función poderosa de Docker que puede ayudarte a crear imágenes eficientes, seguras y optimizadas para tus aplicaciones. Al separar el entorno de construcción del entorno de ejecución final, puedes reducir el tamaño de la imagen, mejorar los tiempos de construcción y mejorar la seguridad.
Siguiendo las mejores prácticas descritas en este artículo, podrá aprovechar al máximo los builds multietapa para optimizar sus flujos de trabajo de Docker y garantizar que sus aplicaciones se implementen sin problemas en diversos entornos. A medida que domine esta función, encontrará nuevas formas de aplicarla en sus proyectos, lo que conducirá a un proceso de desarrollo más eficiente y efectivo.
Whether you are a seasoned Docker user or just getting started, multi-stage builds can significantly enhance your Docker experience and give you a competitive edge in the ever-evolving software development landscape.
Publicaciones relacionadas:
- 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.
- Errores comunes en la optimización de imágenes Docker y cómo evitarlosDocker ha revolucionado la forma en que desarrollamos, desplegamos y ejecutamos aplicaciones. Sin embargo, a pesar de sus ventajas, muchos desarrolladores y equipos de DevOps cometen errores comunes al optimizar sus imágenes Docker. Estos errores pueden llevar a imágenes infladas, vulnerabilidades de seguridad y tiempos de construcción más largos. En este artículo, exploraremos algunos de estos errores comunes y proporcionaremos consejos sobre cómo evitarlos.1. Usar imágenes base grandesUno de los errores más comunes es usar imágenes base grandes. Por ejemplo, usar una imagen completa de Ubuntu cuando solo necesitas ejecutar una aplicación Node.js. Esto resulta en una imagen mucho más grande de lo necesario.Cómo evitarlo: Utiliza imágenes base más pequeñas y específicas. Por ejemplo, en lugar de usar ubuntu:latest, considera usar node:alpine para aplicaciones Node.js. Alpine es una distribución Linux minimalista que es mucho más pequeña que Ubuntu.2. No limpiar después de la instalaciónCuando instalas paquetes o dependencias en tu imagen Docker, a menudo se dejan archivos temporales y cachés que aumentan el tamaño de la imagen.Cómo evitarlo: Limpia después de instalar paquetes. Por ejemplo, después de ejecutar apt-get install, ejecuta apt-get clean y rm -rf /var/lib/apt/lists/* para eliminar archivos temporales.3. No aprovechar las capas de DockerDocker utiliza un sistema de capas, lo que significa que cada instrucción en tu Dockerfile crea una nueva capa. Si no organizas tus instrucciones correctamente, puedes terminar con capas innecesarias.Cómo evitarlo: Agrupa instrucciones relacionadas juntas. Por ejemplo, en lugar de ejecutar apt-get update y apt-get install en líneas separadas, combínalos en una sola línea: RUN apt-get update && apt-get install -y package1 package2.4. No usar .dockerignoreAl igual que .gitignore, .dockerignore te permite especificar archivos y directorios que no deben incluirse en el contexto de construcción de Docker. No usarlo puede resultar en archivos innecesarios que se agregan a tu imagen.Cómo evitarlo: Crea un archivo .dockerignore en el directorio raíz de tu proyecto y especifica archivos y directorios que no deben incluirse en el contexto de construcción.5. No actualizar las imágenes baseUsar imágenes base desactualizadas puede llevar a vulnerabilidades de seguridad.Cómo evitarlo: Actualiza regularmente tus imágenes base. Considera usar herramientas como docker-compose para administrar y actualizar tus imágenes.6. No usar multi-stage buildsLos multi-stage builds te permiten usar múltiples imágenes base en una sola construcción de Docker. Esto es especialmente útil para aplicaciones que requieren compilar código fuente.Cómo evitarlo: Utiliza multi-stage builds para separar el entorno de compilación del entorno de ejecución. Esto resulta en una imagen final mucho más pequeña.7. No minimizar el número de capasCada instrucción en tu Dockerfile crea una nueva capa. Tener demasiadas capas puede hacer que tu imagen sea más grande y lenta de construir.Cómo evitarlo: Minimiza el número de capas combinando instrucciones relacionadas y eliminando capas innecesarias.8. No usar variables de entornoLas variables de entorno son una excelente manera de hacer que tus imágenes Docker sean más flexibles y reutilizables.Cómo evitarlo: Utiliza variables de entorno para configurar tu aplicación. Por ejemplo, en lugar de codificar una URL de base de datos, usa una variable de entorno como DB_URL.9. No probar tus imágenesNo probar tus imágenes Docker puede llevar a problemas inesperados en producción.Cómo evitarlo: Prueba tus imágenes a fondo antes de desplegarlas. Considera usar herramientas como Docker Compose para probar tus imágenes en un entorno similar a producción.10. No monitorear tus imágenesUna vez que tus imágenes Docker están en producción, es importante monitorearlas para detectar problemas y vulnerabilidades.Cómo evitarlo: Utiliza herramientas de monitoreo como Prometheus y Grafana para monitorear tus contenedores Docker. Además, considera usar herramientas de escaneo de seguridad como Clair para escanear tus imágenes en busca de vulnerabilidades.En conclusión, optimizar imágenes Docker es crucial para construir aplicaciones eficientes, seguras y escalables. Al evitar estos errores comunes, puedes asegurarte de que tus imágenes Docker sean lo más pequeñas, rápidas y seguras posible.
- Estrategias de Optimización de Imágenes de Docker para Acelerar las Construcciones
- Desafíos y soluciones en la optimización de imágenes Docker
![Optimización de imágenes Docker con técnicas de construcción de múltiples etapasLas técnicas de construcción de múltiples etapas en Docker son una forma poderosa de optimizar el tamaño y la seguridad de las imágenes de contenedor. Esta técnica permite separar el proceso de construcción del entorno de ejecución, lo que resulta en imágenes finales más pequeñas y eficientes.¿Qué son las construcciones de múltiples etapas?Las construcciones de múltiples etapas permiten utilizar múltiples imágenes base en un solo Dockerfile. Cada etapa puede tener su propio conjunto de instrucciones y archivos, y solo los artefactos necesarios de las etapas anteriores se copian a la etapa final. Esto significa que no es necesario incluir herramientas de compilación, dependencias de desarrollo u otros archivos innecesarios en la imagen final.Beneficios de las construcciones de múltiples etapas1. Reducción del tamaño de la imagen: Al excluir archivos y herramientas innecesarios, las imágenes finales son significativamente más pequeñas.2. Mejora de la seguridad: Menos archivos en la imagen final significan una superficie de ataque reducida.3. Separación de preocupaciones: El proceso de construcción se mantiene separado del entorno de ejecución.4. Reutilización de artefactos: Los artefactos de compilación pueden reutilizarse en diferentes etapas sin tener que reconstruirlos.Ejemplo prácticoVeamos un ejemplo de cómo optimizar una imagen Docker para una aplicación Node.js:```dockerfile# Etapa 1: ConstrucciónFROM node:14-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ciCOPY . .RUN npm run build# Etapa 2: EjecuciónFROM node:14-alpine AS runtimeWORKDIR /appCOPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesEXPOSE 3000CMD ["node", "dist/index.js"]```En este ejemplo, utilizamos dos etapas:1. La primera etapa (builder) instala las dependencias y compila la aplicación.2. La segunda etapa (runtime) solo copia los archivos necesarios para ejecutar la aplicación.La imagen final solo contiene los archivos necesarios para ejecutar la aplicación, excluyendo las herramientas de desarrollo y los archivos de origen.Consejos adicionales para la optimización1. Utiliza imágenes base ligeras: Opta por imágenes como Alpine Linux cuando sea posible.2. Limpia los cachés y archivos temporales: Elimina archivos innecesarios después de la instalación de dependencias.3. Ordena las instrucciones COPY estratégicamente: Coloca las instrucciones COPY que cambian con menos frecuencia al final del Dockerfile para aprovechar mejor el cacheo.4. Utiliza etiquetas específicas de versión: Evita usar etiquetas como "latest" para garantizar la reproducibilidad.5. Considera el uso de herramientas de optimización: Herramientas como Docker Slim pueden ayudar a reducir aún más el tamaño de las imágenes.ConclusiónLas técnicas de construcción de múltiples etapas son una herramienta esencial para optimizar las imágenes Docker. Al separar el proceso de construcción del entorno de ejecución, podemos crear imágenes más pequeñas, seguras y eficientes. Al implementar estas técnicas junto con otras prácticas de optimización, podemos mejorar significativamente el rendimiento y la seguridad de nuestras aplicaciones en contenedores.](https://dockerpros.com/wp-content/uploads/2024/07/optimizing-docker-images-with-multi-stage-build-techniques_564.jpg)