Gérer les images des conteneurs
Objectif de cet atelier pratique
- Télécharger et manipuler les images des conteneurs Docker
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.
Docker vs. Git
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
d107e437f729: Pull complete
cb497a329a81: Pull complete
f1c4d397f477: Pull complete
f72106e86507: Pull complete
899c83fc198b: Pull complete
a785b80f5a67: Pull complete
6c50e4e0c439: Pull complete
Digest: sha256:d5f28ef21aabddd098f3dbc21fe5b7a7d7a184720bc07da0b6c9b9820e97f25e
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
oraclelinux   9         b849892fb693   2 days ago      239MB
alpine        latest    706db57fb206   3 days ago      8.32MB
nginx         latest    07ccdb783875   4 days ago      160MB
archlinux     latest    9925fab8d3a1   7 days ago      494MB
ubuntu        latest    97bed23a3497   10 days ago     78.1MB
debian        latest    61d0976aceca   13 days ago     120MB
almalinux     latest    1e86a8eba5bf   4 weeks ago     189MB
hello-world   latest    1b44b5a3e06a   2 months ago    10.1kB
rockylinux    9         9cc24f05f309   22 months ago   176MB
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                                     ... 
41f689c20910   6 weeks ago   CMD ["nginx" "-g" "daemon off;"]               ... 
...            6 weeks ago   STOPSIGNAL SIGQUIT                             ... 
...            6 weeks ago   EXPOSE map[80/tcp:{}]                          ... 
...            6 weeks ago   ENTRYPOINT ["/docker-entrypoint.sh"]           ... 
...            6 weeks ago   COPY 30-tune-worker-processes.sh /docker-ent…  ... 
...            6 weeks ago   COPY 20-envsubst-on-templates.sh /docker-ent…  ... 
...            6 weeks ago   COPY 15-local-resolvers.envsh /docker-entryp…  ... 
...            6 weeks ago   COPY 10-listen-on-ipv6-by-default.sh /docker…  ... 
...            6 weeks ago   COPY docker-entrypoint.sh / # buildkit         ... 
...            6 weeks ago   RUN /bin/sh -c set -x     && groupadd --syst…  ... 
...            6 weeks ago   ENV DYNPKG_RELEASE=1~trixie                    ... 
...            6 weeks ago   ENV PKG_RELEASE=1~trixie                       ... 
...            6 weeks ago   ENV NJS_RELEASE=1~trixie                       ... 
...            6 weeks ago   ENV NJS_VERSION=0.9.3                          ... 
...            6 weeks ago   ENV NGINX_VERSION=1.29.2                       ... 
...            6 weeks ago   LABEL maintainer=NGINX Docker Maintainers <d…  ... 
...            6 weeks ago   # debian.sh --arch 'amd64' out/ 'bookworm' '…  ...
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é :
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 :
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) 41f689c20910 pour les
images nginx:latest et nginx:monblog_prod. Docker n'a pas utilisé 192 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
oraclelinux   9              b849892fb693   2 days ago      239MB
alpine        latest         706db57fb206   3 days ago      8.32MB
nginx         latest         07ccdb783875   4 days ago      160MB
nginx         monblog_prod   07ccdb783875   4 days ago      160MB
archlinux     latest         9925fab8d3a1   7 days ago      494MB
ubuntu        latest         97bed23a3497   10 days ago     78.1MB
debian        latest         61d0976aceca   13 days ago     120MB
almalinux     latest         1e86a8eba5bf   4 weeks ago     189MB
hello-world   latest         1b44b5a3e06a   2 months ago    10.1kB
rockylinux    9              9cc24f05f309   22 months ago   176MB
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 Dockerfilelinks.
- 
Cliquez sur le tag en question (en l'occurrence latest) pour afficher leDockerfilecorrespondant.
Voici une version simplifiée du Dockerfile pour Nginx :
FROM debian:trixie-slim
LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>"
ENV NGINX_VERSION=1.29.2
ENV NJS_VERSION=0.9.3
ENV PKG_RELEASE=1~trixie
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 :
L'entrée LABEL est l'endroit idéal pour fournir vos coordonnées de
contact :
Les instructions ENV introduisent une série de variables d'environnement tout
comme celles utilisées par le shell Bash :
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 cleansupprime 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 :
L'instruction COPY au quotidien
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 :
Le port 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 :
- 
La syntaxe en vigueur est un tableau (array) JSON, qui signifie JavaScript Object Notation. 
- 
L'option daemon offfait 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 :
À présent je peux lancer la construction de l'image en utilisant la commande
docker build :
- 
L'option -tme permet de spécifier un nom et/ou un tag pour l'image.
- 
N'oubliez pas le point .qui dit à Docker d'utiliser leDockerfilesitué dans le répertoire courant.
Maintenant que nous avons l'image, nous pouvons l'utiliser pour lancer un conteneur :
Jetez un œil aux différentes couches (layers) qui constituent notre image :
Supprimer les images
À présent, faisons un peu de ménage sur notre système :
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:593dac25b7733ffb7afe1a72649a43e574778bf025ad60514ef40
Deleted: sha256:eb4a57159180767450cb8426e6367f11b999653d8f185b5e3b78a9ca30c2
Deleted: sha256:387c6708d068d261ce5b1fe3e67323cbf64d8a37901f3d9742557f4abb83
Deleted: sha256:2946620cb422511c62ba67d12b1c16bbf6b85e6ce42e93a4dace94b4a701
Deleted: sha256:f2545115e362a40e5b3fe057ad159aa9824f40a0e9341f4743b4d0c4f532
Deleted: sha256:9b3ff8c6f07faac480afaeecc0388a387f8cf92832de656a2d35e890340a
Deleted: sha256:77366f15e73eef5c23ff7bd0be0c09f1b280c9586863232392c2d500eed1
Deleted: sha256:7447c8c6be248218804380a22d47c130f7efc16f31550cb446fc3cc91f98
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 :
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 (« élaguer ») 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
À vous de jouer !
- 
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. 
