Optimiser la taille des images de container
Mise à jour :
Optimiser la taille des images de conteneurs est devenu une priorité pour les équipes DevOps cherchant à améliorer les performances de leurs applications, que ce soit dans des environnements Kuberntes, avec Podman, ou sous LXC. Une image de conteneur bien optimisée accélère non seulement les déploiements, mais réduit aussi l’utilisation des ressources, tant au niveau du stockage que de la mémoire. De plus, des images plus petites limitent la surface d’attaque, contribuant ainsi à renforcer la sécurité des applications.
Ce guide explore les stratégies universelles pour réduire la taille des images, indépendamment du moteur de conteneur utilisé.
Prérequis
Avant de vous lancer dans l’optimisation des images de conteneurs, il est indispensable de maîtriser la syntaxe des Dockerfile. Un Dockerfile bien structuré est la base pour créer des images optimisées. Pour acquérir une compréhension approfondie de la création et de l’organisation des Dockerfile, je vous recommande de consulter mon billet de blog détaillé sur le sujet. Il couvre les concepts essentiels et les meilleures pratiques pour écrire des Dockerfile efficaces et maintenables.
Vous pouvez lire cet article ici : Écrire un Dockerfile.
Évitez d’installer des outils inutiles
L’une des clés pour optimiser la taille de vos images de conteneurs est de
limiter l’installation d’outils superflus. Chaque paquet installé ajoute non
seulement du poids à l’image, mais peut aussi introduire des vulnérabilités. Par
exemple, éviter d’inclure des utilitaires de débogage comme netcat
ou curl
dans vos images de production, à moins qu’ils ne soient absolument nécessaires.
Une bonne pratique consiste à restreindre les installations aux seuls composants
indispensables à l’exécution de l’application, en utilisant des commandes
spécifiques pour gérer les dépendances.
Sur Alpine Linux, la commande apk
permet de créer des paquets virtuels
temporaires grâce à l’option --virtual
. Cela permet de regrouper plusieurs
dépendances sous un même nom pour les supprimer plus facilement après leur
utilisation. Par exemple :
Ce processus garantit que les outils de construction, souvent volumineux, sont retirés de l’image finale, minimisant ainsi son empreinte.
En résumé, moins votre image contiendra d’outils non essentiels, plus elle sera légère et sécurisée. Cette approche s’applique quel que soit le moteur de conteneur utilisé, qu’il s’agisse de Docker, Podman ou LXC.
Utilisation de l’option --no-install-recommends
Lorsque vous installez des paquets dans une image de conteneur, il est courant
que le gestionnaire de paquets ajoute des dépendances supplémentaires jugées
« recommandées », qui ne sont pas toujours nécessaires pour votre application.
Cela peut entraîner une augmentation significative de la taille de l’image. Pour
éviter cela, l’utilisation de l’option --no-install-recommends
sur des
distributions comme Debian ou Ubuntu est essentielle. Cette option garantit que
seules les dépendances strictement nécessaires sont installées, excluant ainsi
les paquets recommandés qui ne sont pas obligatoires.
Par exemple, lors de l’installation d’un serveur web comme Nginx dans une image
Debian, la commande sans l’option --no-install-recommends
pourrait installer
des paquets supplémentaires non requis, ce qui gonflera inutilement la taille de
l’image. Voici comment cette option peut être utilisée dans un Dockerfile
:
Dans cet exemple, non seulement on installe Nginx sans les recommandations superflues, mais on nettoie également les listes de paquets pour réduire encore davantage la taille de l’image.
Pour les distributions basées sur Alpine, bien que la syntaxe soit différente,
le concept reste le même. Utilisez l’option --no-cache
pour éviter de
conserver les caches d’installation qui augmentent inutilement la taille finale
de l’image.
Ainsi, quelle que soit la distribution utilisée pour créer votre image de conteneur, l’emploi de cette approche garantit que vous ne transportez que le strict nécessaire, contribuant à une image plus légère et plus efficace.
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 :
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.
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 :
Cela 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.
Privilégiez les images de base légères
L’une des méthodes les plus efficaces pour réduire la taille de vos images de conteneurs est de commencer par une image de base légère. Les distributions minimalistes comme Alpine Linux ou Wolfi-OS sont conçues pour fournir un environnement fonctionnel tout en restant extrêmement compactes. Par exemple, une image de base Alpine pèse environ 5,6 Mo, tandis qu’une image Ubuntu standard peut atteindre 80 Mo ou plus.
DISTRIBUTION / | VERSION / | TAILLE / |
---|---|---|
Debian | bullseye-slim | 80MB |
OracleLinux | 8 | 246MB |
Ubuntu | 21.04 | 80 MB |
Alpine | 3.14 | 5.6MB |
Alpine Linux est particulièrement populaire pour la construction d’images Docker en raison de sa simplicité et de sa sécurité renforcée. Contrairement à des images plus complètes comme celles basées sur Debian ou Ubuntu, Alpine se concentre sur l’essentiel, en utilisant une bibliothèque C légère, musl, et BusyBox, une suite d’outils Unix réduits, optimisés pour la petite taille. Voici un exemple de démarrage avec Alpine dans un Dockerfile :
Ce simple fichier construit une image de base Alpine avec curl
installé, le
tout dans un espace minimal. De plus, Alpine vous permet d’installer uniquement
les packages nécessaires, avec une gestion fine des dépendances grâce à apk
,
ce qui vous aide à éviter le gonflement de l’image avec des bibliothèques
inutilisées.
En fonction de vos besoins, vous pouvez également envisager d’utiliser Wolfi-OS, une distribution encore plus légère, ou d’autres alternatives minimalistes.
6. Utiliser le plus souvent possible le multi stage
Le multi-stage est une fonctionnalité intéressante introduite avec la
version 17.05 de Docker
. Il est possible de décrire plusieurs étapes dans un
même fichier Dockerfile
, Chaque stage commençant par une instruction FROM
.
Je vous conseille de nommer chaque stage en ajoutant AS <nom du stage>
, cela
permet d’y faire référence dans un autre stage. Il est possible de copier une
partie du système de fichier d’un stage avec l’instruction COPY
en utilisant
le paramètre --from=<nom du stage>
. La première application possible est de
construire l’image en trois stages :
- Le premier décrit la partie commune des deux autres
- Le second permet de construire votre application
- Le troisième permet de ne copier que le résultat de la construction du second.
Par exemple pour les images python utilisant
pip
, qui consomme énormément de place lors de la compilation des packages, il est possible de garder le résultat de la compilation en utilisant un environnement virtuel.
Un exemple : Création d’une image Ansible-Lint
Une image non Optimisée
On contrôle la taille de ‘image
La même Optimisée
On contrôle :
On 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.
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 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.
Conclusion
Optimiser la taille des images de conteneurs est une démarche indispensable pour améliorer l’efficacité de vos déploiements, réduire les temps de démarrage et diminuer l’utilisation des ressources. En appliquant les techniques décrites, telles que la réduction des couches, l’utilisation d’images de base légères, le multi-stage build et l’analyse approfondie avec des outils comme Dive, vous pouvez créer des images plus petites, plus rapides et plus sécurisées. Peu importe le moteur de conteneur utilisé, ces pratiques permettent d’obtenir des résultats optimaux dans vos environnements de production.