Exploration et réduction des couches d’une image Docker avec Dive

La technologie de conteneurisation a bouleversé l’industrie du logiciel, en effet les conteneurs résolvent de nombreux problèmes dont faisait face l’industrie. Pour en apprendre plus, allez voir l’article sur la conteneurisation et si vous voulez dockeriser une application déjà existante allez voir l’article sur comment conteneuriser son application legacy. 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. Nous présentons dans cet article une utilisation de Dive pour réduire la taille de vos images Docker. Mais avant nous allons définir ce qu’est une image Docker.

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.

 

Dockerfile

 

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ésents localement avant de les télécharger. 

couches

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 d’une part 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 :

Points à savoir sur les images docker

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 un 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 le couche précédents 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 un 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 ultra léger – la taille de l’image fait 8 Mo – simple et sécurisé qui permet de créer des images très légère.

Il est aussi important de ne pas déplacer des fichiers. Lorsqu’un fichier est déplacé à un emplacement 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 cette 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é.

 

Layers

 

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.

 

Layers command

 

En ne sélectionnant que les fichiers ajoutés par un couche et en filtrant les noms de fichiers par lists, nous pouvons voir à droite les fichiers que la commande apt a ajouté. 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.

 

Layers size

 

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:

 

Current Layers contents

 

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.
Julien Lin

Julien Lin

Julien est Site Reliability Engineer (SRE) chez Padok. Julien est un vrai passionné d'orchestration de containers notamment Kubernetes.

Qu'en pensez-vous ? Laissez vos commentaires ici !