Aller au contenu

Exercice 3 — Images et conteneurs

Durée : ~35 min · Individuel · Théorie associée : Docker : images et conteneurs, Les commandes de base de Docker

Objectif

Vous avez vu par vous-même qu'un conteneur est un programme isolé, qu'il naît d'une image qui ne change jamais, et que chaque conteneur est indépendant des autres.

Prérequis

  • L'exercice 2 terminé : vous êtes connecté à votre VM docker, et docker ps répond sans sudo.

Étape 1 — Télécharger une image sans la lancer

Alpine est une distribution Linux minuscule, très utilisée comme base pour les images Docker.

Bash
docker pull alpine
Texte
Using default tag: latest
latest: Pulling from library/alpine
...
Status: Downloaded newer image for alpine:latest
docker.io/library/alpine:latest

docker pull fait seulement la première étape de docker run : il télécharge l'image, sans créer de conteneur.

Bash
docker images
Texte
REPOSITORY    TAG       IMAGE ID       CREATED         SIZE
alpine        latest    b92841763c5c   13 days ago     8.43MB
hello-world   latest    e2ac70e7319a   7 months ago    10.1kB

Un système Linux complet en 8 Mo. Votre template Debian en occupe plus de 2 Go. La différence : l'image n'a pas de noyau, pas de pilotes, pas de service de démarrage. Elle utilisera le noyau de votre VM.

La console : docker pull alpine, puis docker images affiche alpine (8,43 Mo) et hello-world

Étape 2 — Lancer une seule commande dans un conteneur

Bash
docker run alpine cat /etc/os-release
Texte
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.24.3
PRETTY_NAME="Alpine Linux v3.24"
...

Tout ce qui suit le nom de l'image, ici cat /etc/os-release, est la commande à lancer dans le conteneur. Elle remplace la commande prévue par l'image.

Le fichier lu est celui du conteneur : il décrit Alpine. Comparez avec celui de votre VM :

Bash
cat /etc/os-release

Votre VM est une Debian 13. Le conteneur a ses propres fichiers, séparés de ceux de la VM.

La console : le os-release du conteneur décrit Alpine Linux v3.24, celui de la VM décrit Debian 13

Étape 3 — Le conteneur n'a qu'un seul programme

Bash
docker run alpine ps
Texte
PID   USER     TIME  COMMAND
    1 root      0:00 ps

Dans le conteneur, il n'y a qu'un seul processus : ps lui-même, avec le numéro 1. Pas de systemd, pas de sshd, pas de cron. Rien d'autre ne tourne.

Faites la même commande dans votre VM :

Bash
ps -e | wc -l

Votre VM compte plus d'une centaine de processus. C'est la différence entre un conteneur système (LXC ou VM), qui fait tourner un système entier, et un conteneur applicatif, qui ne fait tourner qu'un programme.

La console : docker run alpine ps n'affiche que ps au PID 1, alors que la VM compte 101 processus

Étape 4 — Le noyau, lui, est partagé

Bash
uname -r
docker run alpine uname -r

Les deux commandes affichent le même numéro de version. Le conteneur n'a pas de noyau à lui : il utilise celui de la VM. C'est pourquoi il démarre en une fraction de seconde. Il n'y a rien à démarrer, à part le programme.

La console : uname -r dans la VM et dans le conteneur affichent la même version, 6.12.113+deb13-cloud-amd64

Étape 5 — Entrer dans un conteneur

Bash
docker run -it alpine sh

L'invite change et devient / #. Vous êtes dans un shell, à l'intérieur d'un nouveau conteneur, connecté en root. Tapez ces commandes l'une après l'autre :

Bash
hostname
whoami
ls /

hostname affiche une suite de 12 caractères : c'est le début de l'identifiant du conteneur. ls / montre une arborescence Linux ordinaire, mais elle appartient au conteneur.

Étape 6 — Laisser une trace dans le conteneur

Toujours dans le shell du conteneur :

Bash
echo "Je suis passé ici" > /root/note.txt
cat /root/note.txt

Puis sortez :

Bash
exit

Vous revenez à l'invite de la VM. Le shell s'est terminé : c'était le programme principal du conteneur, qui s'est donc arrêté.

La console : dans le conteneur, hostname, whoami, ls /, puis l'écriture et la lecture de /root/note.txt, et exit

Étape 7 — Lancer un deuxième conteneur

Bash
docker run -it alpine sh
Bash
cat /root/note.txt
Texte
cat: can't open '/root/note.txt': No such file or directory

Le fichier n'existe pas. Ce n'est pas le même conteneur : docker run en a créé un nouveau, à partir de l'image, qui ne contient pas votre fichier. L'image n'a pas changé quand vous avez écrit dans le premier conteneur.

Vérifiez avec hostname : l'identifiant est différent de celui de l'étape 5. Tapez exit.

La console : dans le deuxième conteneur, /root/note.txt n'existe pas et hostname est différent

Étape 8 — Retrouver le premier conteneur

Le premier conteneur n'a pas été supprimé, il est seulement arrêté.

Bash
docker ps -a
Texte
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS                      PORTS     NAMES
23a3641c85f8   alpine    "sh"                    10 seconds ago   Exited (0) 4 seconds ago              laughing_haibt
4e144cf83c7b   alpine    "sh"                    7 minutes ago    Exited (0) 7 minutes ago              relaxed_heisenberg
a8160bd07d75   alpine    "uname -r"              24 minutes ago   Exited (0) 24 minutes ago             agitated_brahmagupta
...

Chaque docker run des étapes 2 à 7 a laissé un conteneur arrêté. Repérez celui de l'étape 5 : c'est le plus ancien des deux conteneurs dont la commande est "sh". Relancez-le, avec son nom :

Bash
docker start -ai relaxed_heisenberg

docker start relance un conteneur existant. Les options -a et -i y rattachent votre terminal, comme -it le faisait au docker run. Dans le shell :

Bash
cat /root/note.txt
Texte
Je suis passé ici

Le fichier est là : c'est bien le même conteneur. Un conteneur arrêté garde son contenu. Tapez exit.

La console : docker ps -a liste cinq conteneurs arrêtés, puis docker start -ai relance le premier, où note.txt est toujours là

Étape 9 — Ne plus laisser de traces

Les conteneurs arrêtés s'accumulent vite. Quand vous lancez un conteneur pour un test d'une seconde, ajoutez --rm :

Bash
docker run --rm alpine echo "Je disparais tout de suite"
docker ps -a

Le message s'affiche, mais aucun nouveau conteneur n'apparaît dans la liste : Docker l'a supprimé dès son arrêt.

La console : docker run --rm affiche son message, et docker ps -a ne montre aucun nouveau conteneur

Étape 10 — Faire le ménage

Supprimez tous les conteneurs arrêtés d'un seul coup :

Bash
docker container prune

Docker demande une confirmation : répondez y. Il affiche la liste des conteneurs supprimés et l'espace libéré. docker ps -a est vide.

L'image alpine est toujours là (docker images) : vous allez la réutiliser.

La console : docker container prune supprime les cinq conteneurs, docker ps -a est vide, les deux images restent

Étape 11 — Supprimer une image

L'image hello-world ne vous servira plus. Lancez-la une dernière fois, puis essayez de la supprimer :

Bash
docker run hello-world
docker rmi hello-world
Texte
Error response from daemon: conflict: unable to remove repository reference "hello-world" (must force) - container 27851b557f1d is using its referenced image e2ac70e7319a

Docker refuse : le conteneur que vous venez de créer est arrêté, mais il existe encore, et il dépend de l'image. Une image ne peut pas être supprimée tant qu'un conteneur, même arrêté, en dépend.

Supprimez d'abord le conteneur, avec le nom affiché par docker ps -a, puis l'image :

Bash
docker rm NOM_DU_CONTENEUR
docker rmi hello-world
Texte
Untagged: hello-world:latest
Untagged: hello-world@sha256:...
Deleted: sha256:e2ac70e7319a...

docker images n'affiche plus que alpine. Si vous relanciez docker run hello-world, Docker devrait la télécharger de nouveau.

La console : docker rmi hello-world est refusé, puis accepté après docker rm du conteneur, et docker images n'affiche plus qu'alpine

Étape 12 — Le ménage des images

docker rmi supprime une image à la fois. Pour faire le ménage d'un coup, Docker propose :

Commande Supprime
docker container prune Tous les conteneurs arrêtés
docker image prune Les images sans étiquette, restes de téléchargements ou de constructions remplacés
docker image prune -a Toutes les images qu'aucun conteneur n'utilise
Bash
docker image prune

Répondez y. Docker ne supprime rien : vous n'avez pas d'image sans étiquette. Ne lancez pas docker image prune -a maintenant : il supprimerait alpine, qu'aucun conteneur n'utilise. Vous vous en servirez à la fin du défi de l'exercice 6.

La console : docker image prune ne supprime rien, Total reclaimed space: 0B

Vérification finale

  • Vous savez montrer qu'un conteneur Alpine utilise le même noyau que la VM
  • Le fichier /root/note.txt a disparu dans le deuxième conteneur, et était toujours là au docker start du premier
  • docker rmi hello-world a d'abord été refusé, puis a réussi après la suppression du conteneur
  • docker ps -a est vide, et docker images n'affiche plus que alpine

Question 1

À l'étape 7, le fichier /root/note.txt n'existait pas. À l'étape 8, il était là. Expliquez la différence.

Voir la réponse À l'étape 7, `docker run` a créé un **nouveau** conteneur à partir de l'image `alpine`. L'image ne contient pas le fichier : vous l'aviez écrit dans un autre conteneur, et écrire dans un conteneur ne modifie jamais l'image. À l'étape 8, `docker start` a relancé **le même** conteneur que celui de l'étape 5, qui avait été arrêté mais pas supprimé. Il avait gardé son contenu.

Question 2

Pourquoi le conteneur Alpine démarre-t-il en une fraction de seconde, alors que votre VM met une minute ?

Voir la réponse Le conteneur ne démarre pas de système d'exploitation. Il n'a pas de noyau à charger (il utilise celui de la VM, comme l'a montré `uname -r`), et pas de services à lancer (l'étape 3 a montré qu'un seul processus y tourne). Démarrer un conteneur, c'est seulement lancer un programme, dans un espace isolé.

En cas de problème

Symptôme Cause probable Correction
docker run -it alpine bash répond executable file not found Alpine n'a pas bash, seulement sh Utiliser sh
docker start relaxed_heisenberg ne donne pas de shell Il manque -ai docker start -ai relaxed_heisenberg
docker start répond No such container Le nom ne correspond pas à un de vos conteneurs Copier le nom depuis la colonne NAMES de docker ps -a
L'invite reste / # après une commande Vous êtes encore dans le conteneur exit