¿Odias los anuncios? Ir Sin publicidad Hoy

Construcciones multietapa de Docker Reduzca el tamaño de su imagen sin romper el despliegue

Actualizado en

Una guía práctica de construcciones multi-etapa en Docker — tamaños reales antes/después de las imágenes, ejemplos de archivos Docker funcionales para Node.js y Python, y los errores que provocan cada equipo al menos una vez.

Construcción en múltiples etapas con Docker: Reduce el tamaño de tu imagen sin romper el despliegue  1
ANUNCIO · ¿ELIMINAR?

La imagen de Node.js mide 1,1 GB. Ha añadido .dockerignore, eliminó dependencias de desarrollo, intentó node:slim — apenas cambió. La solución real es las construcciones multietapa. Si aún no has cambiado, estás enviando al entorno de producción el compilador de TypeScript.

Las construcciones multietapa han estado disponibles en Docker desde la versión 17.05 (2017). Aunque están disponibles, son poco utilizadas. A continuación, una guía práctica: qué cambia, cuánto se reduce el tamaño y los tres errores comunes que afectan a los equipos en la primera migración.

El problema de la etapa única

La mayoría de los Dockerfiles comienzan así:

FROM node:20

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

EXPOSE 3000
CMD ["node", "dist/server.js"]

Construye y verifica con docker images: ~1,1 GB. Estás enviando la imagen completa de Node 20 con npm, tu cadena de herramientas de TypeScript, todas las dependencias de desarrollo y tu árbol de fuentes. Nada de eso se ejecuta en producción — la aplicación solo necesita la salida compilada y un conjunto reducido de paquetes de ejecución. dist/ .

Construcciones multietapa: la solución

Cada FROM instrucción inicia una nueva etapa con un sistema de archivos limpio. Nombra las etapas con AS, luego utiliza COPY --from=stagename para extraer archivos específicos a la siguiente etapa. Las etapas intermedias no llegan a la imagen final — son artefactos de construcción, descartados tras la COPY finalizada.

Aquí está la misma aplicación como una construcción multietapa adecuada:

# ---- Build stage ----
FROM node:20 AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build


# ---- Runtime stage ----
FROM node:20-alpine AS runtime

WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD ["node", "dist/server.js"]

La línea crítica: COPY --from=builder /app/dist ./dist. Esa línea extrae la salida compilada desde la etapa de construcción hacia la imagen de ejecución basada en Alpine. El compilador de TypeScript, los archivos de fuente y las dependencias de desarrollo nunca tocan la capa final. Los nombres de las cookies son sensibles a mayúsculas y minúsculas Resultado:

~160 MB en lugar de 1,1 GB. Eso representa una reducción de aproximadamente 85% para una aplicación típica de Node — y es el mismo artefacto compilado, solo sin la estructura adicional. Añadir una etapa de pruebas

Puedes añadir una etapa de pruebas entre la construcción y la ejecución que ejecute tu conjunto de pruebas. Si las pruebas fallan, el proceso de construcción se detiene antes de crear la imagen de ejecución. Si las pruebas pasan, se omite completamente la etapa de pruebas al construir para producción.

En el entorno de CI, se dirige explícitamente a la etapa de pruebas:

FROM node:20 AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build


FROM builder AS tester

RUN npm test


FROM node:20-alpine AS runtime

WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=builder /app/dist ./dist

EXPOSE 3000
CMD ["node", "dist/server.js"]

. Para las imágenes de producción, se construye sin objetivo y Docker ejecuta todas las etapas en orden, deteniéndose en la última docker build --target tester .. La etapa de pruebas se ejecuta, pero su sistema de archivos se descarta — las pruebas actúan como una puerta, no como carga. FROMPython: misma idea, ejecución ligeramente diferente

Las construcciones multietapa de Python siguen el mismo patrón. La diferencia principal: pip instala paquetes bajo

cuando se utiliza /root/.local , por lo que se copia ese directorio en la imagen de ejecución ligera. --userimagen base: ~1 GB.

FROM python:3.12 AS builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
COPY . .


FROM python:3.12-slim AS runtime

WORKDIR /app
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app .

ENV PATH=/root/.local/bin:$PATH

CMD ["python", "main.py"]

python:3.12 con solo paquetes instalados: ~180–250 MB dependiendo de lo que esté en requirements.txt. Los archivos compilados vienen gratis ya que se encuentran junto al código fuente. python:3.12-slim Tres errores comunes que capturan a todos al menos una vez .pyc 1. Copiar archivos incorrectos

El error más común: usted

. Solo copió todo — archivos de fuente, fijos de prueba, node_modules, etc. — hacia su imagen de ejecución mínima. Ahora es más grande que la versión de una sola etapa.

Sea explícito sobre qué archivos está copiando. Copie solo el directorio o archivos que realmente necesita el punto de entrada de producción. Para la mayoría de las aplicaciones de Node: la salida compilada ( COPY --from=builder /app ./ en lugar de COPY --from=builder /app/dist ./dist) y opcionalmente cualquier recurso estático. Para Python: los paquetes instalados y el código de la aplicación, no requirements.txt, no las pruebas, no los cuadernos.

2. Secreto de construcción que se revela en capasdist/Si pasas secretos como argumentos de construcción (por ejemplo,

seguido de su uso en un

comando), ese secreto es visible en todas las capas siguientes — incluso en una construcción multietapa. ARG NPM_TOKEN mostrará. RUN La solución correcta es Docker BuildKit’s docker history myimage El secreto se monta solo en el tiempo de ejecución de esa capa — nunca se comite en la historia de la imagen. Construye con:

La solución rápida que usan las personas — eliminar el secreto en la misma --mount=type=secret:

RUN --mount=type=secret,id=npm_token     NPM_TOKEN=$(cat /run/secrets/npm_token) npm ci

capa — no ayuda realmente en construcciones multietapa, pero el enfoque de BuildKit es más limpio independientemente. docker build --secret id=npm_token,src=.npmrc .

3. Olvidar .dockerignore RUN Las construcciones multietapa reducen el tamaño de tu imagen final, pero

en la etapa de construcción aún envía todo tu contexto al demonio de Docker. Sin un

, eso incluye COPY . . , fijos de prueba, archivos locales .dockerignorey cualquier secreto que almacenes en archivos en texto plano. La etapa de construcción ve todo eso. .git/, node_modules/Mínimo .env para cualquier proyecto de Node: el mismo día que añadas el

. El tamaño del contexto de construcción aparece en la primera línea de .dockerignore salida (

.git
node_modules
dist
.env
*.log
coverage
.nyc_output

Añadir .dockerignore ) — si ese número es sorprendentemente grande, revisa qué está siendo incluido. DockerfileHerramientas útiles para el trabajo con Dockerfile docker build Si deseas un punto de partida antes de escribir tu propio, elSending build context to Docker daemon X MBen IO Tools generará un Dockerfile multietapa para pilares comunes. Una vez que tengas algo escrito, ejecútalo a través del

para detectar errores comunes antes de que lleguen a CI — como faltas de

, uso de Generador de Dockerfile etiquetas o ejecutar como root de forma innecesaria. Linter y Formateador de Dockerfile La conclusión WORKDIRLas construcciones multietapa son un cambio en dos pasos: añade una etapa de construcción nombrada, copia la salida compilada a una imagen mínima fresca. La reducción de tamaño es casi siempre justificada — entre 80 y 90% es típica para aplicaciones de Node y Python. Los principales errores comunes son ser demasiado amplio con latest , revelar secretos como argumentos de construcción y omitir

. Corrige esos errores y tendrás una imagen de producción realmente optimizada para el entorno de producción.

Construcciones multietapa de Docker: Reduzca el tamaño de su imagen sin romper el despliegue 2 COPY --fromConstrucciones multietapa de Docker: Reduzca el tamaño de su imagen sin romper el despliegue 1 .dockerignore. Corrige eso y tendrás una imagen de producción que realmente está diseñada para producción.

¿Quieres eliminar publicidad? Adiós publicidad hoy

Instalar extensiones

Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas

añadir Extensión de Chrome añadir Extensión de borde añadir Extensión de Firefox añadir Extensión de Opera

¡El marcador ha llegado!

Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!

ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?

Noticias Aspectos técnicos clave

Involucrarse

Ayúdanos a seguir brindando valiosas herramientas gratuitas

Invítame a un café
ANUNCIO · ¿ELIMINAR?