Votre image Docker fait 1 Go alors qu’elle pourrait en faire 50 Mo ? Ce guide vous accompagne pas à pas pour réduire la taille de vos images de 50 à 90%. Nous commencerons par comprendre pourquoi c’est crucial, puis nous appliquerons les techniques dans l’ordre d’impact : du plus efficace au plus fin.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Pourquoi optimiser : impact sur les coûts, la sécurité et les performances de déploiement
- Choisir son image de base : scratch, distroless, Alpine, Chainguard — quel choix pour quel usage ?
- Multi-stage build : séparer build et runtime pour exclure les outils de compilation
- Optimisations fines : .dockerignore, nettoyage des caches, réduction des couches
Pourquoi optimiser la taille de vos images ?
Section intitulée « Pourquoi optimiser la taille de vos images ? »Avant de plonger dans les techniques, comprenons pourquoi la taille des images est un enjeu critique. Une image de 1 Go au lieu de 50 Mo a des conséquences bien réelles.
Impact sur les coûts
Section intitulée « Impact sur les coûts »| Métrique | Image 1 Go | Image 50 Mo | Économie |
|---|---|---|---|
| Stockage registry (100 images) | 100 Go | 5 Go | 95% |
| Bande passante déploiement | 1 Go/nœud | 50 Mo/nœud | 95% |
| Temps de pull (100 Mbps) | ~80 sec | ~4 sec | 95% |
Sur un cluster Kubernetes de 50 nœuds avec des déploiements fréquents, ces chiffres se traduisent en milliers d’euros de coûts cloud évités.
Impact sur la sécurité
Section intitulée « Impact sur la sécurité »Une image volumineuse contient généralement :
- Des shells (
bash,sh) permettant l’exécution de commandes malveillantes - Des gestionnaires de paquets (
apt,yum) pour installer des backdoors - Des outils réseau (
curl,wget) pour exfiltrer des données
En production, vous n’avez besoin de rien de tout cela.
Impact sur les performances
Section intitulée « Impact sur les performances »| Phase | Image volumineuse | Image optimisée |
|---|---|---|
| Pull initial | Lent | ⚡ Rapide |
| Scaling (nouveaux pods) | Attente du pull | Quasi-instantané |
| Rollback | Lent si ancienne image évincée | Rapide |
| CI/CD pipeline | Build + push longs | Cycles courts |
Identifier la taille de votre image actuelle
Section intitulée « Identifier la taille de votre image actuelle »Avant d’optimiser, mesurez ! Utilisez ces commandes pour diagnostiquer :
# Taille des images localesdocker images --format "table {{.Repository}}:{{.Tag}} {{.Size}}"
# Détail des couches d'une imagedocker history <image>:<tag>
# Analyse interactive avec Divedive <image>:<tag>Maintenant que vous comprenez les enjeux, passons aux techniques d’optimisation, dans l’ordre d’impact.
Choisissez la bonne image de base
Section intitulée « Choisissez la bonne image de base »Le choix de l’image de base impacte directement la taille et la sécurité de vos conteneurs. Une image standard Debian peut contenir des centaines de CVE, alors qu’une image Chainguard en a généralement zéro.
Comparatif des images de base
Section intitulée « Comparatif des images de base »| Image | Taille | CVE typiques | Shell | Libc | Cas d’usage |
|---|---|---|---|---|---|
scratch | 0 Mo | 0 | ❌ | ❌ | Binaires statiques Go/Rust |
cgr.dev/chainguard/static | ~2 Mo | 0 | ❌ | ❌ | Binaires statiques + certificats |
gcr.io/distroless/static | ~2 Mo | 0-5 | ❌ | ❌ | Binaires statiques Google |
alpine:3.20 | ~7 Mo | 0-10 | ✅ | musl | Usage général léger |
cgr.dev/chainguard/wolfi-base | ~12 Mo | 0 | ❌ | glibc | Apps nécessitant glibc |
gcr.io/distroless/base | ~20 Mo | 0-10 | ❌ | glibc | Apps avec libc dynamique |
debian:bookworm-slim | ~75 Mo | 50-150 | ✅ | glibc | Compatibilité maximale |
ubuntu:24.04 | ~78 Mo | 50-200 | ✅ | glibc | Environnement familier |
L’image scratch : le minimum absolu
Section intitulée « L’image scratch : le minimum absolu »scratch est une image totalement vide (0 octet). Elle convient uniquement
aux binaires compilés statiquement qui n’ont pas besoin de libc :
# Pour Go avec compilation statiqueFROM golang:1.22-alpine AS builderWORKDIR /appCOPY . .RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /app/myapp
FROM scratchCOPY --from=builder /app/myapp /myappCOPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ENTRYPOINT ["/myapp"]Attention : sans certificats SSL, vos appels HTTPS échoueront. Copiez-les
depuis le builder ou utilisez distroless/static qui les inclut.
Images distroless : sécurité sans compromis
Section intitulée « Images distroless : sécurité sans compromis »Les images distroless (Google) et Chainguard ne contiennent ni shell,
ni gestionnaire de paquets. Un attaquant qui compromet votre conteneur ne peut
pas exécuter bash, wget ou installer d’outils.
# Application Java avec distrolessFROM eclipse-temurin:21-jdk AS builderWORKDIR /appCOPY . .RUN ./mvnw package -DskipTests
FROM gcr.io/distroless/java21-debian12COPY --from=builder /app/target/*.jar /app.jarENTRYPOINT ["java", "-jar", "/app.jar"]Pour déboguer en développement, utilisez le tag :debug qui ajoute un shell
BusyBox : gcr.io/distroless/java21-debian12:debug.
Alpine Linux : léger mais avec des pièges
Section intitulée « Alpine Linux : léger mais avec des pièges »Alpine utilise musl libc au lieu de glibc, ce qui peut causer des problèmes de compatibilité :
Exemple d’image Alpine optimisée :
FROM alpine:3.20RUN apk --no-cache add curl ca-certificatesChainguard Wolfi : le meilleur des deux mondes
Section intitulée « Chainguard Wolfi : le meilleur des deux mondes »Wolfi est une distribution créée par Chainguard spécifiquement pour les conteneurs. Elle combine :
- glibc pour la compatibilité maximale
- Mises à jour de sécurité quotidiennes
- 0 CVE garanti à la publication
- Construction avec apko (déclaratif, reproductible)
# Application Python avec ChainguardFROM cgr.dev/chainguard/python:latest-dev AS builderWORKDIR /appCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt --target=/app/deps
FROM cgr.dev/chainguard/python:latestWORKDIR /appCOPY --from=builder /app/deps /app/depsCOPY . .ENV PYTHONPATH=/app/depsENTRYPOINT ["python", "app.py"]Guide de choix par langage
Section intitulée « Guide de choix par langage »| Langage | Image recommandée | Pourquoi |
|---|---|---|
| Go | scratch ou distroless/static | Binaire statique, 0 dépendance |
| Rust | scratch ou distroless/static | Compilation statique avec musl |
| Java | distroless/java21 ou chainguard/jre | JRE minimal, pas de shell |
| Python | chainguard/python ou python:3.12-slim | glibc pour les extensions natives |
| Node.js | chainguard/node ou node:20-slim | Évite les problèmes musl |
| .NET | mcr.microsoft.com/dotnet/runtime | Images Microsoft optimisées |
Utilisez le multi-stage build
Section intitulée « Utilisez le multi-stage build »Le multi-stage est une fonctionnalité introduite avec Docker 17.05 qui
permet de décrire plusieurs étapes dans un même Dockerfile. Chaque stage
commence par une instruction FROM.
Principe en 3 stages :
- Stage base : environnement commun (OS + dépendances runtime)
- Stage builder : compilation, téléchargement des dépendances, build
- Stage production : copie sélective uniquement du résultat final
Syntaxe clé :
- Nommez vos stages avec
AS <nom>:FROM alpine:3.18 AS builder - Copiez entre stages avec
COPY --from=<nom>:COPY --from=builder /app/dist /app
Exemple : Création d’une image Ansible-Lint
Section intitulée « Exemple : Création d’une image Ansible-Lint »Une image non Optimisée
Section intitulée « Une image non Optimisée »FROM alpine:3.10.2
RUN apk update && apk upgradeRUN apk add --no-cache python3 opensslRUN apk add --no-cache --virtual .build-deps python3-dev gcc ca-certificates libffi-dev openssl-dev build-baseRUN pip3 install --no-cache-dir --upgrade pip ansibleRUN apk del .build-depsSi vous ne maitrisez pas le gestionnaire de paquets apk, je vous recommande de lire mon guide sur apk pour mieux comprendre son fonctionnement.
On contrôle la taille de ‘image
docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEansible 0.1 5e43ab54b9a0 56 seconds ago 393MBLa même Optimisée
Section intitulée « La même Optimisée »FROM alpine:3.10.2 as baseRUN apk update && apk --no-cache upgrade && apk add --no-cache python3 openssl
FROM base as builderRUN apk add --no-cache --virtual .build-deps python3-dev gcc ca-certificates libffi-dev openssl-dev build-baseRUN python3 -m venv /opt/venv Make sure we use the virtualenv:ENV PATH="/opt/venv/bin:$PATH"RUN pip3 install --no-cache-dir ansible
FROM base
COPY --from=builder /opt/venv /opt/venvENV PATH="/opt/venv/bin:$PATH"On contrôle :
docker images
REPOSITORY TAG IMAGE ID CREATED SIZEansible 0.2 304de2e8b235 51 seconds ago 165MBOn voit que l’image ne fait plus que 165MB contre 393MB pour la version non optimisée.
Cette approche est applicable à d’autres langages et plateformes, permettant d’optimiser les images de conteneurs pour la production, peu importe que vous utilisiez Docker, Podman ou un autre moteur de conteneurisation, voir un orchestrateur tel que Kubernetes.
Utilisez .dockerignore
Section intitulée « Utilisez .dockerignore »Un fichier .dockerignore joue un rôle important dans l’optimisation de vos
images de conteneurs en excluant les fichiers et répertoires inutiles lors de la
construction de l’image. Tout comme un fichier .gitignore, il empêche
l’inclusion de fichiers temporaires, de configurations locales, ou de
dépendances non essentielles dans l’image finale, ce qui permet de réduire sa
taille de manière significative.
Par exemple, si votre projet contient des fichiers comme .env, node_modules,
ou des dossiers de test, vous pouvez les exclure facilement avec un
.dockerignore bien configuré :
Exemple :
# ignore all markdown files (md) beside all README*.md other than README-secret.md*.md!README*.mdREADME-secret.mdCela garantit que ces fichiers ne seront pas copiés dans le contexte de construction, réduisant ainsi la taille de l’image et évitant les risques liés à la fuite d’informations sensibles. En ne copiant que les fichiers nécessaires, votre image devient non seulement plus légère, mais aussi plus sécurisée.
Optimisez vos installations de paquets
Section intitulée « Optimisez vos installations de paquets »Une fois votre image de base choisie et votre multi-stage configuré, affinez les installations de paquets pour grappiller les derniers Mo.
Évitez les paquets inutiles
Section intitulée « Évitez les paquets inutiles »Chaque paquet installé ajoute du poids et des vulnérabilités potentielles. N’installez que le strict nécessaire pour l’exécution :
Sur Debian/Ubuntu : --no-install-recommends
Section intitulée « Sur Debian/Ubuntu : --no-install-recommends »Par défaut, apt-get installe les paquets “recommandés” qui ne sont pas
toujours nécessaires. Bloquez ce comportement :
RUN apt-get update && apt-get install -y --no-install-recommends nginx \ && rm -rf /var/lib/apt/lists/*Important : supprimez toujours /var/lib/apt/lists/* dans le même RUN
pour ne pas conserver les 30-50 Mo de listes de paquets.
Sur Alpine : --no-cache et --virtual
Section intitulée « Sur Alpine : --no-cache et --virtual »# --no-cache évite de stocker l'index des paquetsRUN apk add --no-cache curl ca-certificates
# --virtual pour les dépendances de build temporairesRUN apk add --no-cache --virtual .build-deps gcc make musl-dev \ && make \ && apk del .build-depsL’option --virtual crée un méta-paquet que vous pouvez supprimer en une
commande, emportant toutes ses dépendances.
Limitez le nombre de couches
Section intitulée « Limitez le nombre de couches »Chaque instruction RUN, COPY, ou ADD dans un fichier de construction comme
un Dockerfile crée une nouvelle couche dans l’image de conteneur. Plus vous avez
de couches, plus l’image devient volumineuse et complexe. Pour réduire la taille
de l’image, il est donc essentiel de combiner les commandes là où c’est
possible.
Par exemple, au lieu de séparer les commandes RUN en plusieurs lignes, vous
pouvez les combiner en une seule instruction :
RUN apt-get update && apt-get install -y --no-install-recommends curl \ && apt-get clean && rm -rf /var/lib/apt/lists/*Dans cet exemple, les commandes sont combinées en une seule instruction RUN,
ce qui crée une seule couche au lieu de plusieurs. Cette pratique permet non
seulement de réduire la taille finale de l’image, mais aussi de simplifier sa
gestion et son analyse.
Une autre bonne pratique consiste à supprimer les fichiers temporaires ou les caches à la fin de la commande combinée pour s’assurer qu’ils ne sont pas inclus dans l’image finale. Ainsi, en regroupant les commandes et en nettoyant après chaque installation, vous obtenez une image de conteneur plus légère, ce qui améliore la vitesse de déploiement et réduit l’utilisation des ressources, peu importe le moteur de conteneur utilisé (Docker, Podman, etc.).
Cette technique est essentielle pour maintenir des images efficaces et éviter l’accumulation de données inutiles au fil des modifications apportées à vos conteneurs.
Analysez vos images
Section intitulée « Analysez vos images »Analyser vos images de conteneurs est une étape importante pour identifier les opportunités d’optimisation. Des outils comme Dive vous permettent de visualiser chaque couche de votre image et de comprendre exactement ce qui contribue à sa taille. Dive vous aide à repérer les fichiers ou les couches redondantes, à voir où l’espace est gaspillé et à prendre des décisions éclairées pour réduire l’image.
Par exemple, après avoir construit une image, vous pouvez exécuter Dive pour analyser les couches :
dive <nom_de_l_image>Dive affichera une vue interactive où chaque couche est détaillée, avec la possibilité de voir quels fichiers ont été ajoutés ou modifiés à chaque étape. Cela vous permet d’identifier les couches inutiles ou surdimensionnées, qui peuvent être consolidées ou retirées dans une prochaine version de votre Dockerfile.

En appliquant ces analyses, vous pouvez affiner votre processus de construction d’images pour obtenir des conteneurs plus légers et performants. Ces optimisations contribuent directement à des déploiements plus rapides et à une utilisation plus efficace des ressources dans vos environnements de production.
À retenir
Section intitulée « À retenir »Techniques d’optimisation
Section intitulée « Techniques d’optimisation »- Multi-stage build : LA technique la plus efficace, réduction de 50-80%
- —no-install-recommends : évite les dépendances inutiles sur Debian/Ubuntu
- —no-cache sur Alpine : ne conserve pas le cache apk
- Combinez les RUN : moins de couches = image plus légère
- .dockerignore : exclut node_modules, .git, fichiers de test
- Analysez avec Dive : visualisez chaque couche pour optimiser
Choix de l’image de base
Section intitulée « Choix de l’image de base »| Priorité | Image | Taille | Sécurité |
|---|---|---|---|
| 🥇 Sécurité max | Chainguard/Wolfi | ~2-12 Mo | 0 CVE |
| 🥈 Équilibre | distroless | ~2-20 Mo | 0-10 CVE |
| 🥉 Compatibilité | Alpine | ~7 Mo | 0-10 CVE (musl) |
| 4️⃣ Débutant | Debian slim | ~75 Mo | 50-150 CVE |
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications