Voici le troisième volet de la formation Docker. Dans mon précédent article, nous avons vu en détail les commandes de base de Docker. Aujourd’hui nous allons nous intéresser de plus près à la gestion des images des conteneurs Docker : télécharger une image, afficher son historique, ajouter un tag, construire une image depuis un Dockerfile
, supprimer une image et faire un peu de ménage sur le disque. Suivez le guide.
Une architecture en couches
Docker utilise un modèle en couches – ou layers – pour les conteneurs. Pour en avoir une vague idée, pensez au fonctionnement de la commande diff
sous Linux. Une image de conteneur occupe relativement peu d’espace disque parce qu’elle ne garde que la trace des modifications apportées à une image. Ces modifications sont enregistrées dans une couche – ou un layer – à part.
À titre d’exemple, si toutes vos images sont basées sur une image Alpine Linux, les images nouvellement créées n’occuperont de l’espace disque que pour ce que vous avez ajouté à l’image Alpine de base.
Les couches d’une image sont en lecture seule. Chaque couche est un delta – ou une différence – de tous les changements par rapport à la couche sous-jacente.
Si vous êtes familiarisés avec le logiciel de gestion de versions Git, dites-vous que l’architecture en couches de Docker est organisée de manière similaire. Chaque fois que le code source est modifié, seul ce commit est enregistré directement, mais il renverra toujours à l’ensemble du code.
Cette manière de procéder permet non seulement de réduire l’espace de stockage utilisé. Elle accélère aussi considérablement la reconstruction des images après une modification mineure.
Télécharger une image
Jetons un œil sur les couches qui constituent une image. Pour commencer, téléchargez l’image du serveur web Nginx :
$ docker pull nginx Using default tag: latest latest: Pulling from library/nginx f7a1c6dad281: Pull complete 4d3e1d15534c: Pull complete 9ebb164bd1d8: Pull complete 59baa8b00c3c: Pull complete a41ae70ab6b4: Pull complete e3908122b958: Pull complete Digest: sha256:1c13bc6de5dfca749c377974146ac05256791ca2fe1979fc8e8278bf0121d285 Status: Downloaded newer image for nginx:latest docker.io/library/nginx:latest
La commande docker pull
télécharge l’image dont le nom est fourni en argument vers l’hôte local.
Une fois que l’image a été rapatriée, la commande docker images
(ou docker image ls
) permet de vérifier sa présence sur le système :
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest c1aabb73d233 12 days ago 7.33MB
nginx latest eb4a57159180 12 days ago 187MB
debian latest 49081a1edb0b 2 weeks ago 116MB
ubuntu latest 99284ca6cea0 3 weeks ago 77.8MB
almalinux latest 7ba003a70874 6 weeks ago 184MB
hello-world latest 9c7a54a9a43c 7 weeks ago 13.3kB
Sans trop rentrer dans les détails, la commande docker history
nous permet d’afficher la séquence de commandes qui ont été utilisées pour construire l’image :
$ docker history nginx IMAGE CREATED CREATED BY ... eb4a57159180 12 days ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… ... ... 12 days ago /bin/sh -c #(nop) STOPSIGNAL SIGQUIT ... ... 12 days ago /bin/sh -c #(nop) EXPOSE 80 ... ... 12 days ago /bin/sh -c #(nop) ENTRYPOINT ["/docker-entr… ... ... 12 days ago /bin/sh -c #(nop) COPY file:e57eef017a414ca7… ... ... 12 days ago /bin/sh -c #(nop) COPY file:36429cfeeb299f99… ... ... 12 days ago /bin/sh -c #(nop) COPY file:d4375883ed5db364… ... ... 12 days ago /bin/sh -c #(nop) COPY file:5c18272734349488… ... ... 12 days ago /bin/sh -c #(nop) COPY file:7b307b62e82255f0… ... ... 12 days ago /bin/sh -c set -x && groupadd --system -… ... ... 12 days ago /bin/sh -c #(nop) ENV PKG_RELEASE=1~bookworm ... ... 12 days ago /bin/sh -c #(nop) ENV NJS_VERSION=0.7.12 ... ... 12 days ago /bin/sh -c #(nop) ENV NGINX_VERSION=1.25.1 ... ... 12 days ago /bin/sh -c #(nop) LABEL maintainer=NGINX Do… ... ... 2 weeks ago /bin/sh -c #(nop) CMD ["bash"] ... ... 2 weeks ago /bin/sh -c #(nop) ADD file:ba1250b6ecd5dd09d… ...
Afficher l’identifiant complet d’une image
Ce qu’il faut retenir ici, c’est que le résultat de la commande docker history
affiche ligne par ligne chacune des couches successives avec – en abrégé – les commandes correspondantes pour les construire.
L’option --no-trunc
indique à Docker de ne pas tronquer l’affichage :
$ docker images --no-trunc
...
Cette fois-ci, Docker n’a pas raccourci les sommes de contrôle SHA256 pour chaque image. Autrement dit, nous pouvons voir le nom complet que Docker utilise effectivement pour se référer à l’image en interne, par exemple :
sha256:c919045c4c2b0b0007c606e763ed2c830c7b1d038ce878a3c0d6f5b81e6ab80b
Les tags des images Docker
Un tag est utilisé pour transmettre des informations utiles. Dans la plupart des cas, le tag vous donnera la version précise d’une image. En l’absence de tag, c’est le tag par défaut latest
qui sera utilisé :
TAG: latest
Pour créer un tag pour une image donnée, utilisez la commande docker tag
:
$ docker tag --help Usage: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG] Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
Admettons que nous comptons utiliser l’image Nginx pour héberger notre blog :
$ docker tag nginx:latest nginx:monblog_prod
La colonne IMAGE ID
de l’affichage de docker image ls
nous montre exactement la même somme de hachage (ou le même ID) eb4a57159180
pour les images nginx:latest
et nginx:monblog_prod
. Docker n’a pas utilisé 142 Mo d’espace disque supplémentaire pour refaire un tag à partir de l’image originale, mais il a simplement créé un alias vers l’original :
$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE alpine latest c1aabb73d233 12 days ago 7.33MB nginx latest eb4a57159180 12 days ago 187MB nginx monblog_prod eb4a57159180 12 days ago 187MB debian latest 49081a1edb0b 2 weeks ago 116MB ubuntu latest 99284ca6cea0 3 weeks ago 77.8MB almalinux latest 7ba003a70874 6 weeks ago 184MB hello-world latest 9c7a54a9a43c 7 weeks ago 13.3kB
Ne vous inquiétez pas si par mégarde vous supprimez l’image originale. La nouvelle image restera en place. Docker sait gérer intelligemment ce genre de cas de figure.
Les Dockerfiles
- Ouvrez la page d’accueil de Docker Hub et effectuez une recherche sur
nginx
. - Cliquez sur l’image officielle de Nginx.
- Sur la page de Nginx, repérez la section Supported tags and respective
Dockerfile
links. - Cliquez sur le tag en question (en l’occurrence
latest
) pour afficher leDockerfile
correspondant.
Voici une version simplifiée du Dockerfile
pour Nginx :
FROM debian:bookworm-slim LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>" ENV NGINX_VERSION 1.27.2 ENV NJS_VERSION 0.8.6 ENV PKG_RELEASE 1~bookworm RUN apt-get update \ && apt-get install -y nginx \ && apt-get clean RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log COPY index.html /var/www/html/ EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
Le Dockerfile
vous permet de regarder de près l’ensemble des commandes qui ont servi à construire l’image. Non content de cela, il vous permet également de reconstruire l’image en y apportant éventuellement quelques modifications.
L’instruction FROM
indique à Docker l’image de base qu’il faudra utiliser. Si vous exécutez une commande docker build
avec ce Dockerfile
, la ligne FROM
signifie qu’une couche sera créée au-dessus de l’image de base fournie en argument :
FROM debian:bookworm-slim
L’entrée LABEL
est l’endroit idéal pour fournir vos coordonnées de contact :
LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>"
Les instructions ENV
introduisent une série de variables d’environnement tout comme celles utilisées par le shell Bash :
ENV NGINX_VERSION 1.25.1 ENV NJS_VERSION 0.7.12 ENV PKG_RELEASE 1~bookworm
L’instruction RUN
indique à Docker d’exécuter une commande et contribuer ainsi une brique logicielle pour la construction de l’image. Certaines commandes devront être adaptées pour fonctionner correctement. Les gestionnaires de paquets, par exemple, ne pourront pas fonctionner en mode interactif :
RUN apt-get update \ && apt-get install -y nginx \ && apt-get clean RUN ln -sf /dev/stdout /var/log/nginx/access.log \ && ln -sf /dev/stderr /var/log/nginx/error.log
- Ici, on utilise la double esperluette
&&
pour concaténer les instructionsRUN
, ce qui évite la création d’un nouveau layer pour chaque commande individuelle. Le but de cette opération est de réduire le nombre de couches au-dessus de l’image de base. - Tout le travail du gestionnaire de paquets est effectué en une seule couche.
- La commande
apt-get clean
supprime les paquets téléchargés, ce qui permet de réduire la taille de l’image résultante.
La commande COPY
copie un fichier depuis l’hôte local vers l’image lors de l’opération de construction de l’image :
COPY index.html /var/www/html/
- L’instruction
COPY
est généralement utilisée pour copier des fichiers de configuration de taille modeste dans une image.
La ligne EXPOSE
commande à Docker d’ouvrir (ou exposer) le port 80 lorsqu’un conteneur est lancé depuis cette image :
EXPOSE 80
- Le port 80 est le port standard pour servir du trafic HTTP, ce qui est exactement ce que fait Nginx.
Enfin, l’instruction CMD
exécute le binaire Nginx depuis le conteneur. Dans notre cas de figure, deux options sont utilisées :
CMD ["nginx", "-g", "daemon off;"]
- La syntaxe en vigueur est un tableau (array) JSON, qui signifie JavaScript Object Notation.
- L’option
daemon off
fait tourner Nginx en avant-plan du conteneur. Sans cette précision, le conteneur s’arrêterait net juste après son lancement. - En règle générale, la plupart des applications nécessitent des modifications mineures lorsqu’elles sont conteneurisées.
Créez un répertoire ~/Test
et rangez-y le Dockerfile
. Il nous manque encore un fichier index.html
pour la page par défaut. Nous pouvons le créer comme ceci :
$ echo "<h1>Mon serveur Nginx</h1>" > ~/Test/index.html
À présent je peux lancer la construction de l’image en utilisant la commande docker build
:
$ ls
Dockerfile index.html
$ docker build -t mon_nginx .
Sending build context to Docker daemon 232.4kB
Step 1/10 : FROM debian:bookworm-slim
bookworm-slim: Pulling from library/debian
5b5fe70539cd: Already exists
Digest: sha256:d8f9d38c21495b04d1cca99805fbb383856e19794265684019bf193c3b7d67f9
Status: Downloaded newer image for debian:bookworm-slim
---> e7d7f06a08a8
...
Step 9/10 : EXPOSE 80
---> Running in a03c8b335626
Removing intermediate container a03c8b335626
---> ebe2fc397a2d
Step 10/10 : CMD ["nginx", "-g", "daemon off;"]
---> Running in 391069a6d410
Removing intermediate container 391069a6d410
---> 9e04f8bbb2dd
Successfully built 9e04f8bbb2dd
Successfully tagged mon_nginx:latest
- L’option
-t
me permet de spécifier un nom et/ou un tag pour l’image. - N’oubliez pas le point
.
qui dit à Docker d’utiliser leDockerfile
situé dans le répertoire courant.
Maintenant que nous avons l’image, nous pouvons l’utiliser pour lancer un conteneur :
$ docker run -dit mon_nginx 1a45be278e3e6a3008bdef4d20abd1749172dd45caf938caa736278dbd179846
Jetez un œil aux différentes couches (layers) qui constituent notre image :
$ docker history mon_nginx
Supprimer les images
À présent, faisons un peu de ménage sur notre système :
$ docker rmi nginx:monblog_prod Untagged: nginx:monblog_prod
Docker nous informe qu’il a supprimé le tag de l’image et non pas l’image elle-même, étant donné qu’il ne s’agissait que d’un alias.
$ docker rmi nginx:latest Untagged: nginx:latest Untagged: nginx@sha256:593dac25b7733ffb7afe1a72649a43e574778bf025ad60514ef40f6b5d606247 Deleted: sha256:eb4a57159180767450cb8426e6367f11b999653d8f185b5e3b78a9ca30c2c31d Deleted: sha256:387c6708d068d261ce5b1fe3e67323cbf64d8a37901f3d9742557f4abb830baf Deleted: sha256:2946620cb422511c62ba67d12b1c16bbf6b85e6ce42e93a4dace94b4a70160b3 Deleted: sha256:f2545115e362a40e5b3fe057ad159aa9824f40a0e9341f4743b4d0c4f5322435 Deleted: sha256:9b3ff8c6f07faac480afaeecc0388a387f8cf92832de656a2d35e890340ac59a Deleted: sha256:77366f15e73eef5c23ff7bd0be0c09f1b280c9586863232392c2d500eed148e7 Deleted: sha256:7447c8c6be248218804380a22d47c130f7efc16f31550cb446fc3cc91f98a54c
Cette fois-ci, le résultat de la commande docker rmi
est différent. Nous avons effectivement supprimé un certain nombre de couches, et ce faisant nous avons libéré de l’espace disque.
Dans certains cas il peut être nécessaire de forcer la suppression d’une image :
$ docker rmi -f debian:bookworm-slim
Rappelez-vous que chaque commande dispose d’une aide en ligne contextuelle. En l’occurrence, voici ce que nous avons fait pour découvrir l’option -f
:
$ docker rmi --help Usage: docker rmi [OPTIONS] IMAGE [IMAGE...] Remove one or more images Options: -f, --force Force removal of the image --no-prune Do not delete untagged parents
Faire le ménage sur le disque dur
Docker utilise une terminologie qui lui est propre pour désigner toutes les couches d’images qui ne sont utilisées par aucune image disposant d’un tag. Ces layers inutilisés sont des images en suspens (ou dangling images).
La sous-commande prune
permet de supprimer ces images en suspens :
$ docker image prune WARNING! This will remove all dangling images. Are you sure you want to continue? [y/N] y
Pour supprimer aussi bien les images inutilisées que les images en suspens, utilisez la commande suivante :
$ docker system prune -a
WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all images without at least one container associated to them
- all build cache
Are you sure you want to continue? [y/N] y
...
Si vous souhaitez savoir la quantité d’espace disque utilisé par Docker, invoquez la commande suivante :
$ docker system df TYPE TOTAL ACTIVE SIZE RECLAIMABLE Images 6 1 495MB 495MB (100%) Containers 1 1 2B 0B (0%) Local Volumes 0 0 0B 0B Build Cache 0 0 0B 0B
Exercice
- Rendez-vous sur Docker Hub.
- Téléchargez la dernière image Docker officielle du magasin de données en mémoire Memcached.
- Téléchargez l’image Docker officielle du serveur web Apache dans sa mouture
2-alpine
. - Affichez les images que vous venez de télécharger.
- Affichez l’espace disque total occupé par ces images.
- Supprimez l’image de Memcached.
- Supprimez l’image d’Apache.
- Vérifiez que vous n’avez plus aucune image Docker locale sur votre système.
Lire la suite : Exécuter un conteneur
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.
5 commentaires
Isch Pascal · 3 décembre 2023 à 10 h 04 min
Bonjour. Félicitations pour votre cours sur Docker qui est très clair. En revanche, en faisant la commande docker build -t mon_nginx . j’obtiens ce message d’erreur : /30-tune-worker-processes.sh »: not found (failed to calculate checksum). J’ai récupéré le Dockfile à partir du lien latest. Je l’ai téléchargé en Dockfile.txt. Avant de le renommer en Dockfile. Je suis sous Linux.
Isch Pascal · 4 décembre 2023 à 8 h 45 min
Bonjour. Le problème posé dans le message précédent est résolu. A priori, il fallait utiliser le Dockerfile simplifié et non celui de nginx directement. Surtout qu’au début de leur Dockerfile, ils indiquent qu’il ne faut pas l’éditer. Vous pouvez supprimer mes deux messages sans problème. Encore félicitations pour votre travail. 🙂
Rukhazon · 3 septembre 2024 à 14 h 02 min
Hello, le build du Dockerfile ne fonctionne pas pour nginx:latest
Je pense que sa méthode de construction à du changer depuis al rédaction de l’article.
Peut-être qu’il faut essayer avec une version précise …
kikinovak · 4 septembre 2024 à 7 h 40 min
Merci pour l’info. Je regarde ça dès que je trouve un moment.
kikinovak · 17 octobre 2024 à 12 h 01 min
Je viens de tester, et ça fonctionne toujours parfaitement.