Exercice 03 : Réduire la taille d'une image avec les multi-stage builds
🎯 Objectifs
À la fin de cet exercice, vous serez capable de :
- ✅ Nommer un stage avec
FROM ... AS builder - ✅ Copier des artefacts d'un stage vers l'autre avec
COPY --from=builder - ✅ Produire une image de production basée sur
node:alpinesans les outils de build - ✅ Comparer la taille des images avec
docker images - ✅ Expliquer pourquoi les outils de build ne doivent pas être dans l'image finale
Durée estimée : 20 min | Difficulté : ⭐⭐⭐⭐☆
📖 Contexte
Un Dockerfile classique inclut compilateurs, gestionnaires de paquets et fichiers source dans l'image finale. Un multi-stage build sépare la compilation de l'exécution : seul le binaire ou le bundle final est copié dans une image minimale. Pour une application Node.js, cela peut réduire la taille de 900 Mo à moins de 100 Mo.
📋 Énoncé
Packagez une application Node.js Express d'abord avec un Dockerfile classique (single-stage), puis avec un Dockerfile multi-stage. Comparez les tailles obtenues et vérifiez que les deux images produisent le même résultat.
🧭 Déroulement
Tâche 1 : Créer l'application Node.js
Créez un dossier node-multistage/ avec les fichiers suivants :
package.json
{
"name": "demo-app",
"version": "1.0.0",
"scripts": { "start": "node index.js" },
"dependencies": { "express": "^4.19.0" },
"devDependencies": { "esbuild": "^0.21.0" }
}index.js
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Multi-stage build OK\n'));
app.listen(3000);Indice :
esbuildest intentionnellement endevDependencies- il ne doit pas se retrouver dans l'image de production.
Vérification : node index.js fonctionne localement (si Node est installé).
Tâche 2 : Dockerfile single-stage (référence)
Créez Dockerfile.single basé sur node:20 qui installe toutes les dépendances (y compris dev) et démarre l'application.
Indice :
npm installinstalle aussi lesdevDependenciespar défaut.
Vérification : docker build -f Dockerfile.single -t node-single . && docker images node-single affiche une taille supérieure à 1 Go.
Tâche 3 : Dockerfile multi-stage
Créez Dockerfile.multi avec deux stages :
- Stage
builderbasé surnode:20: installe les dépendances de production uniquement (npm ci --omit=dev) - Stage final basé sur
node:20-alpine: copienode_modulesetindex.jsdepuisbuilder
Indice :
COPY --from=builder /app/node_modules ./node_modulescopie le dossier depuis le stage nommé.
Vérification : docker build -f Dockerfile.multi -t node-multi . && docker images node-multi affiche une taille inférieure à 150 Mo.
Tâche 4 : Comparer les tailles
Affichez les deux images côte à côte et calculez le ratio de réduction.
Indice :
docker images | grep node-filtre les deux images.
Vérification : L'image node-multi est au moins 8x plus légère que node-single.
🗂️ Mini-Projet
Complétez les points suivants :
node-singleest construite et fonctionne sur le port 3000node-multiest construite et fonctionne sur le port 3000docker imagesconfirme quenode-multiest significativement plus petitedocker run -p 3000:3000 node-multiretourneMulti-stage build OKvia curldocker run node-multi sh -c "ls node_modules | grep esbuild"ne retourne rien (esbuild absent)