L'Art des Images (Dockerfile)
Système de fichiers en couches et optimisation extrème
Si le conteneur est l'instance vivante, l'image est son ADN inerte. Oubliez la notion de gros ficher .iso. Une image Docker est construite comme un gâteau : une empilement de couches ("Layers") en lecture seule. Chaque ligne de votre Dockerfile crée une nouvelle couche.
Le paradigme des couches (Layers)
Comprendre le système UnionFS de Docker est le secret pour ne pas créer des images toxiques de 4Go qui mettraient 10 minutes à se déployer.
CMD ["node", "server.js"] (Couche d'exécution fantôme)COPY . . (Couche Source : ~2 Mo) Modifiée très souventRUN npm ci (Couche Dépendances : ~150 Mo) Modifiée rarementCOPY package.json (Couche Manifest : ~2 Ko)FROM node:18-alpine (Couche OS de Base : ~115 Mo) Intouchabledocker build, Docker analyse chaque instruction de haut en bas. S'il réalise que ni la ligne, ni les fichiers associés n'ont changé depuis le précédent build, il réutilise instantanément la couche du cache ("Using cache").🚨 Piège mortel : Si vous faites
COPY . . avant RUN npm install, le moindre changement dans votre code source invalidera le cache de la copie, ET forcera Docker à retélécharger intégralement toutes vos dépendances (~150 Mo) pour rien. Ordre crucial : Dependencies FIRST, Source code LAST.
Simulateur de Cache : Optimisation de Build
Cliquez sur la ligne n°5 de code source (COPY . .) pour simuler une modification logicielle classique. Ensuite, Réinitialisez, et essayez de simuler une modification sur le fichier package.json (ligne 3). Constatez l'impact cataclysmique sur le temps de build !
Build : 1.2s
Toutes les couches récupérées du cache.
Le fichier .dockerignore
Au tout début du processus de build, le Daemon Docker aspire la totalité de votre dossier projet (c'est le "Build Context"). Si vous oubliez d'exclure le tentaculaire dossier node_modules/ ou .git/, vous enverrez des gigaoctets au Daemon avant même que la création de l'image de commence.
node_modules/
npm-debug.log
.git/
.env # Ne JAAAAAMAIS bake un fichier .env contenant des secrets de prod dans une image !
ARG vs ENV : Les variables
Une confusion très courante concerne la différence entre les instructions ARG et ENV d'un Dockerfile.
Cheatsheet : Le dictionnaire Dockerfile
Le Chef d'Œuvre : Multi-Stage Build
Une image de production ne doit pas contenir les outils nécessaires à sa création (compilateurs C++, TypeScript, npm install...). Plus une image est petite :
- 🔒 Plus sa surface d'attaque sécuritaire est réduite.
- ⚡ Plus elle démarre vite et se télécharge vite sur vos serveurs.
# === STAGE 1 : BUILD (Le "Chantier") ===
# On utilise une image très lourde avec tous les outils (Alpine = Linux ultra léger)
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
# Installation globale (même des devDependencies pour pouvoir compiler le TS ou Webpack)
RUN npm ci
COPY . .
# On compile l'application (ex: creation du dossier /app/dist)
RUN npm run build
# === STAGE 2 : PRODUCTION (L'image finale) ===
# On repart d'une image vierge ! Le "Chantier" (Stage 1) sera jeté à la poubelle.
FROM node:18-alpine
WORKDIR /app
# On ne copie depuis le chantier QUE ce qui est vital pour l'exécution (le JS minifié)
COPY --from=builder /app/dist ./dist
COPY package*.json ./
# Installation pure prod (aucune devDependency)
RUN npm ci --only=production
# Sécurité : On refuse de tourner en "root" à l'intérieur du conteneur
USER node
EXPOSE 3000
CMD ["node", "./dist/server.js"]
L'Usine (Le Registre)
Une fois votre image construite, elle dort sur votre PC actuel. Il faut l'envoyer dans le Cloud (Docker Hub / AWS ECR / Github Packages) via la commande push.
# Construit et nomme l'image en lui donnant un TAG (version)
docker build -t hylst/mon-serveur-api:1.0.0 .
# Authentification cloud
docker login
# Envoi de l'image (Upload)
docker push hylst/mon-serveur-api:1.0.0