Constructions à plusieurs étapes de Docker Réduisez votre image sans compromettre le déploiement
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.
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.
Vous aimerez peut-être aussi
Installez nos extensions
Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide
恵 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 !
Outils essentiels
Tout voir Nouveautés
Tout voirMise à jour: Notre dernier outil was added on Juin 26, 2026
