Les pubs vous déplaisent ? Aller Sans pub Auj.

Constructions à plusieurs étapes de Docker Réduisez votre image sans compromettre le déploiement

Mis à jour le

Une présentation pratique des builds Docker à plusieurs étapes — les tailles réelles des images avant et après, des exemples de fichiers Docker pour Node.js et Python, et les pièges qui font tomber chaque équipe au moins une fois.

Constructions à plusieurs étapes de Docker : Réduire votre image sans compromettre le déploiement 1
ANNONCE · Supprimer ?

Votre image Node.js est de 1,1 Go. Vous avez ajouté .dockerignore, supprimé les dépendances de développement, essayé node:slim — cela n’a presque pas bougé. La solution réelle, c’est les builds en plusieurs étapes. Si vous n’avez pas encore passé à cette méthode, vous envoyez votre compilateur TypeScript en production.

Les builds en plusieurs étapes ont été présents dans Docker depuis la version 17.05 (2017). Ils sont simplement sous-utilisés. Voici une walkthrough réelle : quels sont les changements, quelle est la différence de taille, et les trois pièges qui frappent les équipes lors de la première migration.

Le problème de l’étape unique

La plupart des fichiers Docker commencent comme ça :

FROM node:20

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

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

Construire et vérifier avec docker images: ~1,1 Go. Vous envoyez l’image complète de Node 20 avec npm, votre chaîne d’outils TypeScript, toutes les dépendances de développement et votre arborescence complète de source. Rien de cela ne s’exécute en production — l’application a besoin uniquement du résultat compilé dist/ et d’un petit nombre de packages en temps d’exécution.

Builds en plusieurs étapes : la solution

Chaque FROM instruction démarre une nouvelle étape avec un système de fichiers propre. Nommez les étapes avec AS, puis utilisez COPY --from=stagename pour extraire des fichiers spécifiques vers la prochaine étape. Les étapes intermédiaires ne sont pas incluses dans l’image finale — elles sont des artefacts de construction, supprimées après la COPY est terminée.

Voici la même application sous forme de build en plusieurs étapes :

# ---- 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 ligne critique : COPY --from=builder /app/dist ./dist. Cela extrait le résultat compilé de l’étape de construction vers l’image de runtime basée sur Alpine. Le compilateur TypeScript, les fichiers sources et les dépendances de développement n’ont jamais touché la couche finale. seulement Résultat :

~160 Mo au lieu de 1,1 Go. Cela représente une réduction d’environ 85% pour une application typique Node — et c’est le même artefact compilé, simplement sans les structures autour. Ajouter une étape de test

Vous pouvez ajouter une étape de test entre la construction et le runtime pour exécuter votre ensemble de tests. Si les tests échouent, la construction s’arrête avant la création de l’image de runtime. Si les tests passent, vous passez complètement à l’étape de test lors de la construction en production.

Dans CI, vous ciblez explicitement l’étape de test :

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"]

. Pour les images de production, vous construisez sans cible et Docker exécute toutes les étapes dans l’ordre, s’arrêtant à la dernière docker build --target tester .. L’étape de test s’exécute, mais son système de fichiers est supprimé — les tests agissent comme un contrôle, pas comme un payload. FROMPython : même idée, exécution légèrement différente

Les builds en plusieurs étapes en Python suivent le même modèle. La principale différence : pip installe les packages sous

lorsque vous utilisez /root/.local , donc vous copiez ce dossier dans l’image de runtime légère. --userimage de base : ~1 Go.

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 avec uniquement les dépendances installées : ~180 à 250 Mo selon ce qui se trouve dans requirements.txt. Les fichiers compilés viennent de gratuit puisqu’ils sont situés à côté du code source. python:3.12-slim Trois pièges qui attrapent tout le monde au moins une fois .pyc 1. Copier les fichiers inappropriés

L’erreur la plus fréquente : vous

. Vous avez simplement copié tout — fichiers sources, fixtures de tests, node_modules, etc. — dans votre image de runtime minimale. Elle est maintenant plus grande que la version à une étape.

Soyez explicite sur ce que vous copiez. Copiez uniquement le dossier ou les fichiers que le point d’entrée de production a besoin. Pour la plupart des applications Node : le résultat compilé ( COPY --from=builder /app ./ au lieu de COPY --from=builder /app/dist ./dist) et éventuellement les actifs statiques. Pour Python : les packages installés et le code de l’application, pas requirements.txt, pas les tests, pas les notebooks.

2. Fuite de secrets dans les couches de constructiondist/Si vous passez des secrets en argument de construction (par exemple,

suivi de leur utilisation dans une

commande), ce secret est visible dans toutes les couches suivantes — même dans un build en plusieurs étapes. ARG NPM_TOKEN affichera cela. RUN L’approche correcte est Docker BuildKit’s docker history myimage Le secret est monté uniquement au moment d’exécution de cette couche — il ne se committe jamais dans l’historique de l’image. Construisez avec :

L’approche économique que les gens utilisent — supprimer le secret dans la même --mount=type=secret:

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

couche — n’aide pas vraiment dans les builds en plusieurs étapes, mais l’approche de Docker BuildKit est plus propre quel que soit le cas. docker build --secret id=npm_token,src=.npmrc .

3. Oublier .dockerignore RUN Les builds en plusieurs étapes réduisent la taille de votre image finale, mais

dans l’étape de construction envoie toujours tout votre contexte au daemon Docker. Sans un

, cela inclut COPY . . , les fixtures de test, les fichiers locaux .dockerignoreet tous les secrets stockés en clair dans des fichiers. L’étape de construction voit tout cela. .git/, node_modules/Minimum .env pour tout projet Node :

la même journée où vous ajoutez le .dockerignore . La taille du contexte de construction apparaît dans la première ligne de

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

Ajouter .dockerignore sortie ( Dockerfile) — si ce nombre est étrangement élevé, vérifiez ce qui est inclus. docker build Outils utiles pour le travail de DockerfileSending build context to Docker daemon X MBSi vous souhaitez un point de départ avant d’écrire votre propre fichier, le

sur IO Tools vous scaffoldera un Dockerfile en plusieurs étapes pour les stacks courants. Une fois que vous avez un fichier écrit, exécutez-le à travers le

pour détecter les erreurs courantes avant qu’elles ne touchent CI — des choses comme manque de Générateur de Dockerfile , utilisation de Linter et formateur Dockerfile tags ou exécution en tant que root. WORKDIRL’essentiel latest Les builds en plusieurs étapes sont une modification à deux étapes : ajouter une étape de construction nommée, copier le résultat compilé dans une image minimale. La réduction de taille est presque toujours worthwhile — 80 à 90% est typique pour les applications Node et Python. Les principaux pièges sont d’être trop large avec

, de laisser fuir des secrets en argument de construction, et d’oublier

. Corrigez ces points et vous avez une image de production réellement adaptée à la production. COPY --from, fuite de secrets en tant que paramètres de construction, et saut .dockerignore. Corrigez ces points et vous obtenez une image de production réellement adaptée à la production.

Envie d'une expérience sans pub ? Passez à la version sans pub

Installez nos extensions

Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide

Sur Extension Chrome Sur Extension de bord Sur Extension Firefox Sur Extension de l'opéra

Le Tableau de Bord Est Arrivé !

Tableau de Bord est une façon amusante de suivre vos jeux, toutes les données sont stockées dans votre navigateur. D'autres fonctionnalités arrivent bientôt !

ANNONCE · Supprimer ?
ANNONCE · Supprimer ?
ANNONCE · Supprimer ?

Coin des nouvelles avec points forts techniques

Impliquez-vous

Aidez-nous à continuer à fournir des outils gratuits et précieux

Offre-moi un café
ANNONCE · Supprimer ?