Un développeur junior a réduit la taille d'une image Docker Python de 1,2 Go à 85 Mo, faisant passer le pipeline CI de 11 minutes à 90 secondes. Des images plus petites se téléchargent plus rapidement, coûtent moins cher en stockage et exposent moins de failles de sécurité.
Pourquoi la taille de l'image est importante
Chaque fois qu'un conteneur est récupéré (pulled), le registre transfère l'image entière. Une couche de 85 Mo arrive en quelques secondes ; une couche de 1,2 Go peut prendre plusieurs minutes sur un réseau modeste. Les agents de build doivent également télécharger et mettre en cache l'image complète, ce qui gonfle le temps de CI et les factures de stockage cloud. Chaque paquet supplémentaire est une vulnérabilité potentielle, donc réduire la base réduit la surface d'attaque.
D'où vient l'encombrement
- Les outils de build tels que gcc restent dans l'image finale s'ils sont installés dans la même étape que l'exécution de l'application.
- Les caches des gestionnaires de paquets (par ex. les caches
aptoupip) occupent de l'espace sur le disque et ne sont jamais nettoyés par défaut. - Chaque instruction
RUNcrée une nouvelle couche en lecture seule ; la duplication de fichiers entre les couches s'accumule. - Les images de base volumineuses comme
ubuntu:latestsont livrées avec un OS complet, bien plus que ce dont un runtime Python minimal a besoin.
La réduction en trois étapes
| Étape | Image de base | Approche de build | Taille résultante |
|---|---|---|---|
| 1 | Python standard (complet) | Étape unique, tous les outils présents | 1,18 Go |
| 2 | python:slim |
Multi-stage : builder avec gcc, l'étape finale ne copie que les paquets compilés | 210 Mo |
| 3 | python:alpine |
Multi-stage sur Alpine Linux, qui est lui-même minuscule | 85 Mo |
Étape 1 – la référence
En partant de l'image Python par défaut, le développeur a obtenu un artefact de 1,18 Go. L'image contenait toute la pile Debian, les en-têtes de développement et le cache pip.
Étape 2 – slim avec un builder
Le passage à python:slim a réduit l'empreinte de l'OS, mais les outils de build sont restés. L'ajout d'une étape de builder a permis d'installer, de compiler, puis de supprimer gcc, make et les autres dépendances de compilation. L'étape finale a utilisé COPY --from=builder pour ne récupérer que les wheels compilés et les fichiers d'exécution, faisant tomber la taille à 210 Mo.
Étape 3 – Alpine l'emporte
Alpine Linux repose sur musl libc et busybox. La répétition du modèle multi-stage sur Alpine a produit une image de 85 Mo — une réduction de 93 % par rapport à l'originale. Le développeur a noté que Kubernetes récupérait l'image en quelques secondes et que le job de CI se terminait en 90 secondes.
Impact concret
- Coûts de stockage réduits – Le stockage du registre diminue.
- Sécurité améliorée – Moins de paquets signifie moins de CVE à surveiller. L'image Alpine ne contient que le runtime Python et le code de l'application.
- CI plus rapide – Le temps d'exécution du pipeline est passé de 11 minutes à 90 secondes.
Conseils pratiques pour réduire votre Dockerfile
- Évitez les tags
:latest; choisissez des variantes:slimou:alpinequi correspondent à vos besoins. - Utilisez des builds multi-étapes : une étape builder dédiée à la compilation, et une étape runtime qui ne reçoit que les artefacts dont vous avez réellement besoin.
- Copiez de manière sélective avec
COPY --from=builder /path/to/installed /path/in/final. - Ordonnez les commandes de sorte que l'installation des dépendances s'effectue avant la copie du code source ; cela maximise la mise en cache des couches.
- Nettoyez explicitement les caches, par ex.
rm -rf /var/lib/apt/lists/* ~/.cache/pip.
Si vous adoptez Alpine, ajoutez le paquet nss lorsque votre application rencontre des problèmes de résolution DNS. Lors de l'installation avec pip, préfixez votre PATH par /root/.local/bin afin que les scripts installés localement soient trouvés lors de l'exécution.
Mises en garde
La bibliothèque musl libc d'Alpine peut entrer en conflit avec les wheels binaires compilés pour glibc, provoquant des erreurs d'exécution. Dans ces cas, recompilez les wheels à l'intérieur du builder Alpine ou revenez à une base slim. Le paquet nss supplémentaire est un faible prix à payer pour la fiabilité du DNS.
Prochaines étapes
- Analysez vos images existantes pour identifier les couches volumineuses qui pourraient faire l'objet d'une réécriture en multi-stage.
- Surveillez les logs de CI pour les temps de téléchargement (upload/download) afin de détecter l'encombrement des images.
- Gardez un œil sur les rapports de vulnérabilité pour la distribution de base que vous choisissez.
La leçon est claire : un Dockerfile discipliné, une base légère et une étape de builder peuvent réduire une image Python de plus d'un ordre de grandeur, offrant des gains de vitesse et de coût tangibles sans sacrifier les fonctionnalités.
