Images : multi-stage et poids
Une image qui embarque le compilateur, les sources et les devDependencies (dépendances de développement : tests, build, jamais utiles en prod), c'est trois problèmes :…
Prérequis (cursus dev) : conteneurs, Dockerfile, npm et dépendances.
Pourquoi
Une image qui embarque le compilateur, les sources et les devDependencies (dépendances de développement : tests, build, jamais utiles en prod), c'est trois problèmes : lourde à transférer, longue à déployer, pleine de failles connues. Le multi-stage sépare le chantier du livrable.
Concepts
- Couches (layers) : une image est un empilement de couches en cache. Si les premières ne changent pas, Docker les réutilise : le rebuild est quasi instantané.
- Alpine : une distribution Linux minuscule (~5 Mo). Base idéale quand on n'a besoin que d'un runtime : moins de code = moins de failles.
- Surface d'attaque : tout ce qui est exposé et exploitable. 900 Mo de tooling en moins = 900 Mo d'exploits potentiels en moins.
Exemple : le pattern
FROM node:24-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:24-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=build /app/dist ./dist
COPY --from=build /app/public ./public
CMD ["node", "dist/main.js"]
COPY package*.json avant le code : tant que les dépendances ne changent pas, la couche npm ci est réutilisée. npm cache clean : ne pas stocker le cache npm dans l'image.
Cas réel
API NestJS : image naïve ~1,1 Go (node complet + devDeps + sources), multi-stage Alpine ~180 Mo. Sur une petite machine avec un lien moyen : 30 secondes contre 5 minutes de déploiement.
Pièges
latestcomme base (node:alpine) : rebuild silencieux = version différente un mardi matin. Épingler (node:24-alpine)..dockerignoreoublié :node_modules,.git,.envpartent au daemon et peuvent fuir dans l'image.COPY . .avantnpm ci: invalide le cache à chaque modification de code, rebuild complet à chaque fois.
À retenir
Chantier et livrable séparés, dépendances copiées avant le code, versions épinglées, et on mesure (docker history, dive — un explorateur d'images qui montre ce que pèse chaque couche).