Publié le 7 octobre 2020, mis à jour le 6 décembre 2023.
La technologie de conteneurisation a bouleversé l’industrie du logiciel. Ces conteneurs exécutent des images qui définissent l’environnement d’exécution du conteneur et sont constituées de couches. Dive est un outil d’exploration d’image Docker permettant de voir le contenu des couches de l’image.
Qu’est-ce qu’une image Docker ?
D’après la documentation de Docker : une image Docker est une collection ordonnée de changements d’un système de fichier et des paramètres d’exécution correspondant à son utilisation à l’exécution. Un ensemble atomique de changements sur le système de fichier est une couche. Une image Docker peut être vue comme une pile de couches dont chaque couche dépend de tous les précédents.
Chaque couche représente donc un ensemble de changement que l’on fait au système de ficher de base. Ces changements sont commis par les instructions présentes dans le Dockerfile de l’image. Lorsque l’on récupère une image Docker depuis un répertoire, l’image Docker se télécharge couche par couche.
Cette décomposition en couche des images Docker permet de partager les différents couches entre celles-ci et d’économiser de l’espace de stockage et en volume de téléchargement : en effet pour des images qui partagent les mêmes couches de base, ces couches ne sont pas dupliquées ni au niveau stockage ni au niveau du téléchargement, Docker vérifie que les couches ne sont pas présentes localement avant de les télécharger.
Pourquoi réduire la taille d’une image Docker ?
Dans un cluster, il arrive que plusieurs conteneurs exécutent la même image Docker pour tenir la charge, en particulier dans une architecture microservices. La taille d’une image Docker joue sur les performances de votre cluster : utiliser de nombreuses images Docker requiert de la place mémoire, car il s’agit de les stocker afin de les rendre accessibles à l’ensemble des nœuds du cluster.
Réduire la taille des images permet de réduire la mémoire disque utilisée, et dans le cas où le stockage est payant comme dans le cloud public, de faire des économies. D’autre part, la taille des images influe sur le temps de chargement de conteneur pour son exécution, une image de 5 Go prend plus de temps qu’une image de 500 Mo.
Points à savoir à propos des images Docker
Avant de pouvoir réduire la taille des images Docker, certains points sont à prendre en considération à propos des couches Docker et de leur fonctionnement :
- Une couche est dépendante de toutes celles sur lesquelles elle s’appuie. Considérons deux images Docker issues des deux Dockerfiles ci-dessous le Dockerfile 1 et le Dockerfile 2. Lorsqu’on lit les deux Dockerfiles, les images produites semblent identiques, mais ce n’est pas le cas du point de vue des couches des images.
Dockerfile 1
Dockerfile 2
Observons le schéma suivant :
L’ordre des deux dernières instructions est différent entre les deux images Docker résultant donc de deux couches différentes.
- Si un fichier a été ajouté dans une couche alors sa taille sera prise en compte dans la taille totale de l’image finale. Même si l’on cherche à supprimer le fichier dans une couche suivante, le fichier est enregistré dans la couche précédente et par conséquent contribue à la taille de l’image Docker.
Comment réduire les images Docker ?
Pour réduire la taille des images Docker, il est primordial de ne pas ajouter des données inutiles et de supprimer les fichiers qui ne sont plus utiles lorsque ceux-ci ont été ajoutés. Un fichier inutile produit/introduit au niveau d’une couche doit être supprimé dans cette couche. Typiquement, les fichiers produits par apt-get update se trouvant dans le dossier /var/lib/apt/lists.
Comme il n’est pas possible de supprimer un fichier qui a été ajouté dans une couche antérieure, le choix de l’image Docker de base est important. Une recommandation est d’utiliser les versions des images utilisant Alpine linux comme système d’exploitation. Alpine linux est un système d’exploitation ultraléger – la taille de l’image fait 8 Mo – simple et sécurisé qui permet de créer des images très légères.
Il est aussi important de ne pas déplacer des fichiers. Lorsqu’un fichier est déplacé à un endroit différent de son emplacement d’origine, il est d’abord copié à son nouvel emplacement puis supprimé de son ancien emplacement. Le fichier déplacé est donc présent dans deux couches : dans la couche où il a été ajouté et dans la couche où il a été déplacé.
Il ne faut pas déplacer ou copier des fichiers ajoutés dans une couche précédente. Placez le fichier directement à la bonne place et utilisez les liens symboliques, si nécessaire.
Pour prendre pleinement avantage de la décomposition en couche, une autre manière de réduire la taille des images Docker est de considérer un ensemble d’images. En effet, plus les images partagent une large base de couches plus petit est la taille de cet ensemble d’image Docker.
L’utilisation de Dive : tutoriel
Dive est un outil open source pour explorer les couches d’une image Docker. Dive permet aussi de tracer les changements entre les couches que ce soit des ajouts, modification ou suppression de fichiers. Il permet aussi d’estimer l’efficacité d’une image et d’une intégration à une pipeline de CI. Plusieurs méthodes d’utilisation sont disponibles, par exemple, en tant que binaire ou en tant qu’image Docker :
Nous proposons ici un cas d’utilisation illustrant certains des points soulevés précédemment.
Considérons l’image Docker suivant :
Ce Dockerfile installe deux commandes qui sont fortune et cowsay et supprime les fichiers de log se trouvant dans /var/log/.
Dive propose une interface graphique composée de deux parties : celle de gauche donnant des informations sur les couches et à droite des informations sur les modifications que les couches ont apportées au système de fichier. Les fichiers sont répartis en 4 états : ajouté, supprimé, modifié et non modifié.
Nous pouvons voir que dans les détails de l’image que les certains fichiers de log supprimés sont comptés dans le la taille totale de l’image.
En ne sélectionnant que les fichiers ajoutés par une couche et en filtrant les noms de fichiers par lists, nous pouvons voir à droite les fichiers que la commande apt a ajoutés. La commande apt update a ajouté 30 MB de fichiers inutiles.
Si l’on change le Dockerfile pour réduire la taille de l’image, on obtient le fichier suivant :
Dans ce Dockerfile il n’y a plus qu’une seule couche dans laquelle la liste des répertoires est mise à jour puis l’installation de fortune et cowsay se fait et enfin la suppression des différents fichiers de /var/lib/apt/lists/ se fait.
La taille de l’image est passée de 137 MB à 106 MB ! Les 30 MB de fichiers ajoutés par apt update ont bien été supprimés.
Comme mentionné précédemment, prendre une image Docker de base plus petite peut radicalement réduire la taille de l’image totale. Prendre une image basée sur alpine est la première chose à laquelle penser lorsque l’on souhaite réduire la taille de son image. Voici la version alpine du Dockerfile:
Pour conclure cet article, Dive est un très bon outil pour explorer les couches d’une image Docker. Il permet d’observer les modifications faites dans un Dockerfile sur système de fichier de base. Pour réduire la taille d’une image quelques règles simples à respecter :
- un fichier inutile produit/introduit au niveau d’une couche doit être supprimé dans cette couche
- Il ne faut pas déplacer ou copier des fichiers ajoutés dans une couche précédente mais dans le cas nécessaire les liens symboliques sont une alternative