¿Qué son los Docker Multi-Stage Builds?

Multi-stage Docker construye son una característica introducida en Docker 17.05 que permite utilizar múltiples declaraciones dentro de un solo Dockerfile. Cada instrucción comienza una nueva etapa, que puede tener su propia imagen base, dependencias y comandos. Exclusivamente los objetos pueden ser copiados de una etapa a otra, mientras que la imagen final sólo retiene lo que es estrictamente necesario para ejecutar la cadena de script.

La idea central es separar el entorno de construcción del entorno de tiempo de ejecución. En una construcción típica de una sola etapa, un desarrollador instala todas las herramientas de construcción (por ejemplo, compiladores, gestores de paquetes, marcos de prueba) en la misma imagen que se utilizará para la producción. Que bloca la imagen y aumenta la superficie de ataque. Multi-stage construye resolver esto mediante una imagen gruesa y rica en función para la compilación y luego copiar sólo el resultado runiLT2

Beneficios de los Construidos de Multietapa

Las ventajas de adoptar construcciones multietapa van más allá de la reducción de tamaño simple, tienen un profundo impacto en la seguridad, la sostenibilidad y la velocidad de despliegue.

1. Tamaño reducido de la imagen

Descarte dependencias de tiempo de construcción, las construcciones de varias etapas suelen reducir las imágenes en un 50% al 90%. Por ejemplo, una aplicación Node.js construida usando la imagen completa (más de 300MB) puede ser reducida a menos de 20 MB copiando solamente la carpeta construida en una base . Este ahorro de almacenamiento se traduce directamente a tiempos de extracción más rápidos, menos costos de banda

2. Mejora de la seguridad

Cada paquete o herramienta instalado en una imagen contenedor es una vulnerabilidad potencial. Las construcciones multietapa le permiten excluir compiladores, depuradores y bibliotecas de desarrollo de la imagen final, reduciendo significativamente la superficie de ataque. Incluso puede utilizar imágenes como o para la etapa de ejecución, que contienen sólo el mínimo de la aplicación binario.

3. Proceso de construcción racionalizado

Todos los pasos de construcción se definen en un solo Dockerfile, haciendo que el proceso se conserve y sea fácil de ver. Los oleoductos CI/CD se benefician de un único punto de entrada: el Dockerfile. No hay necesidad de mantener scripts de construcción separados o pasos de limpieza manual.

4. Reproductibilidad y coherencia mejoradas

Debido a que todo el edificio se captura en un Dockerfile, cualquier desarrollador o sistema puede reproducir exactamente las mismas capas. El uso de etiquetas de versión específicas para las imágenes de base garantiza aún más las construcciones consistentes en entornos.

Construyendo un Dockerfile de múltiples etapas: Paso a paso

Este recorrido cubre la creación de un Dockerfile multietapa de producción para una aplicación Node.js y React. Los mismos principios se aplican a cualquier idioma compilado.

1. Planifique sus etapas

Antes de escribir código, mapear las etapas que necesita. Un típico edificio multietapa tiene al menos dos etapas:

  • Equipo de construcción] – instala todas las herramientas de construcción, instala dependencias y ejecuta el comando de construcción.
  • Escalera de tiempo] – utiliza una imagen base mínima, copia sólo los artefactos construidos de la etapa del constructor, y define el comportamiento de tiempo de ejecución.

Para proyectos complejos puede añadir etapas intermedias para pruebas, análisis estático o compresión de activos.

2. Escribe la etapa del constructor

Comience con una imagen base que incluye la cadena de herramientas requerida. Use etapas nombradas con para referirse más adelante. Para Node.js:

FROM node:14-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

Puntos clave:

  • Use para una instalación de dependencia determinista y rápida.
  • Mantenga comandos como capas separadas cuando sea posible para aprovechar el caché.
  • Instala herramientas de construcción (como TipoScript, webpack) en esta etapa solamente.

3. Agregue una etapa de prueba intermedia (opcional)

Para hacer cumplir la calidad del código, agregue una etapa que se ejecutan pruebas. Esta etapa puede reutilizar la imagen del constructor o instalar herramientas adicionales. Debido a que no es la etapa final, los fallos de prueba no estarán presentes en la imagen final.

FROM builder AS test
RUN npm run test

Puede ejecutar esta etapa en su tubería de CI con para atrapar fallas temprano sin construir toda la imagen final.

4. Definir la etapa de ejecución

Para una aplicación React, la imagen de tiempo de ejecución puede ser un servidor Nginx. Para una API de backend, puede ser una imagen de base destros o un Alpine mínimo con el tiempo de ejecución Node.js. Copiar sólo los artefactos esenciales usando .

FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Si necesita el tiempo de ejecución Node.js, evite copiar del constructor; en lugar de reinstalar las dependencias de producción en el tiempo de ejecución:

FROM node:14-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/server.js"]

5. Construir y probar la imagen

Construir la imagen final utilizando el comando estándar:

docker build -t myapp:latest .

Para verificar el tamaño, ejecute y compare contra una construcción de una sola etapa. Ejecute el contenedor y confirme la aplicación responde correctamente:

docker run -d -p 8080:80 myapp:latest
curl http://localhost:8080

Las mejores prácticas para los constructores multietapa

  • Usar etiquetas de imagen de base específicas – evite para evitar sorpresas. Preferir o .
  • Optimizar el caché de capa] – copiar y antes del resto del código fuente para que la capa sólo se invalide cuando las dependencias cambian.
  • Construcción de la palancaKit] – permite a BuildKit con para construcciones más rápidas, encaje en línea y mejor paralelismo.
  • Crear múltiples etapas finales para diferentes entornos – por ejemplo, una etapa de desarrollo con herramientas depuradoras y una etapa de producción con una imagen de base endurecida.
  • Use para el desarrollo construye ] – en el desarrollo se puede detener en la etapa para obtener mapas de carga y fuente en vivo, luego reconstruir con para la producción.
  • Mantener secretos fuera de imágenes – utilizar la bandera de Docker BuildKit si necesita pasar credenciales durante la construcción; nunca incluirlos en la imagen final.

Patrones comunes y casos de uso

Idiomas Compilados (Go, Rust, C++)

Para los binarios estáticos, la etapa de tiempo de ejecución puede utilizar (imagen base vacía). Sólo el binario y tal vez un archivo de configuración se copian. Ejemplo para Go:

FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .

FROM scratch
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["/myapp"]

Aplicaciones de Python

Utilice una etapa de construcción con para instalar dependencias y compilar cualquier extensión C, a continuación, copiar sólo los paquetes instalados en una etapa de tiempo de ejecución:

FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
COPY . .

FROM python:3.11-slim
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app /app
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]

Frontend con API Server

Construya frontend y backend en un Dockerfile. Utilice etapas de construcción separadas para cada uno, luego copiar ambos artefactos en una sola imagen de tiempo de ejecución:

FROM node:14-alpine AS frontend-builder
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ .
RUN npm run build

FROM node:14-alpine AS api-builder
WORKDIR /app
COPY api/package*.json ./
RUN npm ci
COPY api/ .
RUN npm run build

FROM node:14-alpine
WORKDIR /app
COPY --from=frontend-builder /app/build ./public
COPY --from=api-builder /app/dist ./dist
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/server.js"]

Solución de problemas de los edificios de múltiples etapas

  • Layer caching no funciona – asegura ] las dependencias de orden antes del código fuente. Use para excluir archivos innecesarios.
  • El artefacto no encontrado] – verifica los caminos en la declaración . La etapa del constructor debe producir la salida en la ubicación especificada. Use para depurar.
  • ]Financiación secreta] – nunca copiar directorios enteros que puedan contener o . Copiar explícitamente sólo los archivos necesarios.
  • Ergeir las imágenes finales a pesar de las múltiples etapas] – comprobar si estás copiando accidentalmente o toda la fuente. Usar para ver los tamaños de las capas.

Conclusión

Multi-stage Docker construye son una piedra angular de la contenedorización moderna. Le permiten enviar imágenes magras y seguras manteniendo el proceso de construcción simple y documentado en un solo Dockerfile. Al separar las preocupaciones entre la construcción y el tiempo de ejecución, puede reducir drásticamente el tamaño de la imagen, mejorar la seguridad y simplificar los conductos CI/CD. Las técnicas mostradas aquí aplican a casi cualquier pila - ya sea que usted está construyendo Node.js, Java implementación de inicio

Para más detalles, consulte la documentación de construcción multietapa oficial Docker] y la Guía de mejores prácticas de Dockerfile. También se pueden obtener ejemplos reales en la documentación de la Biblioteca Docker.