Mira la lección en vídeo
Accede al vídeo completo de esta lección y a más contenido exclusivo con el Plan Plus.
Desbloquear Plan PlusQué es el multi stage
Los multi-stage builds representan una técnica fundamental en Docker que permite utilizar múltiples instrucciones FROM
dentro de un mismo Dockerfile. Esta característica, introducida en Docker 17.05, resuelve uno de los problemas más comunes en el desarrollo de aplicaciones: crear imágenes de producción ligeras y eficientes eliminando dependencias y archivos innecesarios del build.
La idea central de un multi-stage build es separar el proceso de construcción en diferentes etapas o stages. Cada stage puede usar una imagen base diferente y cumplir una función específica dentro del proceso de build. Esto permite, por ejemplo, compilar una aplicación en un stage con todas las herramientas de desarrollo necesarias, y luego copiar únicamente el binario resultante a un stage final que usa una imagen base mínima.
Anatomía básica de un multi-stage build
Un Dockerfile con multi-stage build contiene múltiples instrucciones FROM, donde cada una inicia un nuevo stage:
# Stage 1: Build stage
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Stage 2: Production stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["node", "index.js"]
En este ejemplo, el primer stage (builder
) utiliza la imagen completa de Node.js para instalar dependencias, mientras que el segundo stage usa una imagen Alpine más ligera y copia solo los node_modules
necesarios desde el stage anterior.
Ventajas principales del multi-stage
La principal ventaja de los multi-stage builds es la reducción significativa del tamaño de la imagen final. Las herramientas de compilación, dependencias de desarrollo, archivos temporales y cache quedan en stages intermedios que no forman parte de la imagen final.
Separación de responsabilidades es otro beneficio clave. Cada stage puede optimizarse para su propósito específico: compilación, testing, producción, etc. Esto hace que el Dockerfile sea más legible y mantenible.
La seguridad también mejora considerablemente, ya que la imagen final no contiene herramientas de desarrollo que podrían representar vectores de ataque. Solo incluye los archivos y dependencias estrictamente necesarios para ejecutar la aplicación.
Ejemplo práctico con Go
Los multi-stage builds brillan especialmente con lenguajes compilados como Go:
# Build stage
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .
# Production stage
FROM alpine:3.18
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]
En este caso, el stage de build usa una imagen de Go completa (~800MB) para compilar la aplicación, pero el stage final usa Alpine (~5MB) y contiene únicamente el binario compilado. El resultado es una imagen de producción de aproximadamente 15-20MB en lugar de los 800MB originales.
Named stages y referencias
Docker permite nombrar los stages usando la sintaxis AS nombre
, lo que hace el Dockerfile más legible y permite referenciar stages específicos. Los nombres de stages deben ser descriptivos y reflejar su propósito:
FROM node:18 AS dependencies
# Instalar dependencias
FROM node:18 AS builder
# Compilar aplicación
FROM nginx:alpine AS production
# Servir aplicación
Esta nomenclatura facilita el mantenimiento y hace explícito el propósito de cada etapa del build, especialmente en Dockerfiles complejos con múltiples stages.
COPY --from y Named stages
Guarda tu progreso
Inicia sesión para no perder tu progreso y accede a miles de tutoriales, ejercicios prácticos y nuestro asistente de IA.
Más de 25.000 desarrolladores ya confían en CertiDevs
La instrucción COPY --from es el mecanismo fundamental que permite transferir archivos entre diferentes stages de un multi-stage build. Esta funcionalidad va más allá de una simple copia de archivos, ya que permite seleccionar específicamente qué contenido trasladar desde stages anteriores, manteniendo la imagen final optimizada.
Sintaxis y funcionamiento de COPY --from
La sintaxis básica de COPY --from permite referenciar un stage anterior mediante su índice numérico o su nombre:
# Referencia por índice (0 es el primer stage)
COPY --from=0 /app/build ./build
# Referencia por nombre de stage
COPY --from=builder /app/dist ./dist
El índice numérico comienza en 0 para el primer FROM, pero usar nombres es la práctica recomendada por su claridad y mantenibilidad. Los nombres de stages proporcionan contexto inmediato sobre el propósito de cada etapa.
Casos de uso avanzados con COPY --from
La flexibilidad de COPY --from permite patrones de build sofisticados. Un ejemplo común es crear stages especializados para diferentes tipos de assets:
# Stage para dependencias de frontend
FROM node:18 AS frontend-deps
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
# Stage para build de frontend
FROM frontend-deps AS frontend-builder
COPY frontend/ ./
RUN npm run build
# Stage para dependencias de backend
FROM golang:1.21 AS backend-builder
WORKDIR /app
COPY backend/go.mod backend/go.sum ./
RUN go mod download
COPY backend/ ./
RUN go build -o api .
# Stage final que combina ambos builds
FROM nginx:alpine
COPY --from=frontend-builder /app/dist /usr/share/nginx/html
COPY --from=backend-builder /app/api /usr/local/bin/
COPY nginx.conf /etc/nginx/nginx.conf
En este ejemplo, dos líneas de build independientes (frontend y backend) se combinan en una imagen final que contiene tanto la aplicación web estática como el API compilado.
Named stages y organización de builds complejos
Los named stages transforman Dockerfiles complejos en documentos autodescriptivos. Los nombres deben seguir convenciones claras que reflejen la función específica de cada stage:
FROM node:18 AS package-installer
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18 AS test-runner
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm test
FROM package-installer AS app-builder
COPY . .
RUN npm run build
FROM nginx:alpine AS production-server
COPY --from=app-builder /app/build /usr/share/nginx/html
Esta estructura permite reutilizar stages (como package-installer
) y crear ramificaciones lógicas donde diferentes stages pueden derivar de un ancestro común.
Copiado selectivo y optimización
Una ventaja clave de COPY --from es la capacidad de copiar únicamente los archivos necesarios, no directorios completos. Esto es especialmente útil cuando se necesitan archivos específicos de diferentes ubicaciones:
FROM golang:1.21 AS tools-builder
WORKDIR /tools
RUN go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
RUN go install github.com/swaggo/swag/cmd/swag@latest
FROM golang:1.21 AS app-builder
WORKDIR /app
# Copiar solo las herramientas compiladas, no todo el GOPATH
COPY --from=tools-builder /go/bin/golangci-lint /usr/local/bin/
COPY --from=tools-builder /go/bin/swag /usr/local/bin/
COPY . .
RUN golangci-lint run
RUN swag init
RUN go build -o myapp .
FROM alpine:3.18
RUN apk --no-cache add ca-certificates
COPY --from=app-builder /app/myapp /usr/local/bin/
CMD ["myapp"]
Referencias a imágenes externas
COPY --from también permite referenciar imágenes externas directamente, sin necesidad de definirlas como stages en el Dockerfile actual:
FROM alpine:3.18
# Copiar un binario desde una imagen oficial
COPY --from=docker/buildx-bin /buildx /usr/local/bin/
# Copiar certificados desde una imagen específica
COPY --from=certificates-image:latest /etc/ssl/certs /etc/ssl/certs
COPY app.js .
CMD ["node", "app.js"]
Este patrón es útil para incorporar herramientas o assets desde imágenes especializadas sin incluir toda la imagen base en el build.
Buenas prácticas para named stages
Los nombres de stages deben seguir una nomenclatura consistente que facilite la comprensión del flujo de build:
*-installer
: Para stages que instalan dependencias*-builder
: Para stages que compilan o procesan código*-tester
: Para stages que ejecutan pruebasproduction-*
: Para stages finales de producción
FROM node:18 AS deps-installer
# Instalar dependencias
FROM deps-installer AS code-builder
# Compilar aplicación
FROM code-builder AS unit-tester
# Ejecutar pruebas
FROM nginx:alpine AS production-web
COPY --from=code-builder /app/build /usr/share/nginx/html
Esta convención hace que el propósito de cada stage sea inmediatamente evidente y facilita el mantenimiento de Dockerfiles complejos con múltiples desarrolladores.
Aprendizajes de esta lección de Docker
- Comprender qué es un multi-stage build y su propósito en Docker.
- Aprender a estructurar un Dockerfile con múltiples instrucciones FROM y nombrar stages.
- Entender cómo usar COPY --from para transferir archivos entre stages.
- Identificar las ventajas de multi-stage builds en tamaño, seguridad y mantenimiento.
- Aplicar multi-stage builds en ejemplos prácticos con lenguajes compilados como Go.
Completa este curso de Docker y certifícate
Únete a nuestra plataforma de cursos de programación y accede a miles de tutoriales, ejercicios prácticos, proyectos reales y nuestro asistente de IA personalizado para acelerar tu aprendizaje.
Asistente IA
Resuelve dudas al instante
Ejercicios
Practica con proyectos reales
Certificados
Valida tus conocimientos
Más de 25.000 desarrolladores ya se han certificado con CertiDevs