Une image Docker de 2 Go en production, c’est lent à télécharger, coûteux à stocker et une surface d’attaque étendue. Les multi-stage builds résolvent ce problème structurellement.
Le problème des images naïves
# ❌ Image naïve — embarque tout l'environnement de build
FROM python:3.12
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
RUN python -m compileall .
CMD ["python", "app.py"]
# Taille résultante : ~1.2 Go
Cette image embarque pip, les en-têtes de compilation, les outils de développement — tout ce qui n’est pas nécessaire pour faire tourner l’application.
Multi-stage : séparer build et runtime
# ✅ Multi-stage build
# Étape 1 : build
FROM python:3.12 AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip install --prefix=/install -r requirements.txt
# Étape 2 : image finale minimaliste
FROM python:3.12-slim AS runtime
WORKDIR /app
# Copier seulement les dépendances installées
COPY --from=builder /install /usr/local
COPY src/ .
CMD ["python", "app.py"]
# Taille résultante : ~180 Mo
L’étape builder disparaît de l’image finale — seuls les artefacts explicitement copiés persistent.
Exemple Go : binaire statique dans scratch
FROM golang:1.22 AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o app .
# Image finale : absolument rien
FROM scratch
COPY --from=builder /build/app /app
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/app"]
# Taille résultante : ~12 Mo
Une image basée sur scratch ne contient rien d’autre que le binaire — surface d’attaque quasi nulle.
BuildKit et cache : accélérer les builds
# Monter le cache pip entre les builds
RUN --mount=type=cache,target=/root/.cache/pip \
pip install -r requirements.txt
Avec BuildKit, le cache est persistent entre les builds — les dépendances non modifiées ne sont jamais re-téléchargées.
Notre formation Docker couvre les Dockerfiles optimisés et les stratégies de build en production.