Quand vous tapez docker run, un conteneur démarre. Si on vous demande qui a lancé son processus, vous répondez sans doute « Docker ». C'est incomplet, et cela compte le jour où vous diagnostiquez une panne. Le démon Docker peut ne plus répondre alors que les conteneurs tournent, ou l'inverse. Pour comprendre ce qui se passe, il faut savoir quels programmes se placent entre la commande et le processus du conteneur.
Cette page remonte cette chaîne depuis la machine avec ps et docker container inspect. Vous redémarrez ensuite le démon pour voir ce que deviennent les conteneurs. Elle suppose que vous savez déjà qu'un conteneur est un processus (voir le cycle de vie et le PID 1).
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Nommer les programmes intermédiaires entre
docker runet le processus du conteneur - Retrouver le processus intermédiaire d'un conteneur et son vrai parent
- Lire le runtime employé, et comprendre qu'on peut le remplacer
- Prévoir ce que devient un conteneur quand le démon redémarre
Prérequis
Section intitulée « Prérequis »Il vous faut Docker installé (installation de Docker), un accès sudo sur la machine pour redémarrer le démon, et l'habitude de lire un conteneur avec docker container inspect (inspecter un conteneur). Les commandes sont écrites pour Docker Engine 29.9.2 et l'image alpine:3.24.
Cette page n'explique pas les isolations du noyau (namespaces, cgroups) : elles sont dans sous le capot. Le partage des rôles entre runtime, moteur et orchestrateur est dans Runtime, moteur, orchestrateur.
Quels programmes se placent entre docker run et le processus du conteneur ?
Section intitulée « Quels programmes se placent entre docker run et le processus du conteneur ? »Il y en a au moins quatre, et le processus du conteneur n'est l'enfant d'aucun de ceux auxquels vous pensez.
Le client docker, que vous tapez, ne fait que transmettre votre commande au démon dockerd. Le démon est le programme de Docker qui reste actif en arrière-plan sur la machine. Il gère les images, les réseaux et les volumes, mais il ne lance pas lui-même les conteneurs. Il confie leur cycle de vie (création, démarrage, arrêt) à containerd.
Pour chaque conteneur, containerd démarre un petit programme intermédiaire, le shim (containerd-shim-runc-v2). Le shim appelle le runtime, runc par défaut, qui crée réellement le conteneur. Une fois le processus du conteneur créé, runc se termine : vous ne le verrez pas dans la liste des processus. Le shim, lui, reste et surveille le conteneur.
Dans le schéma, les traits pleins suivent votre demande, du client jusqu'au processus du conteneur. Les trois traits pointillés montrent des liens moins directs : l'appel à runc, qui ne dure pas, et les deux flèches qui partent du PID 1 vers les shims. Ce parent des shims est la surprise de cette page.
Chacun de ces programmes a un rôle. Le shim permet au conteneur de ne dépendre ni du démon ni de containerd pendant qu'il tourne. Il garde ouverts les flux d'entrée et de sortie du conteneur, et il récupère son code de sortie quand il s'arrête. Il est aussi détaché du programme qui l'a créé, comme vous allez le constater.
Le runtime est le programme qui sait lire une configuration au format OCI et créer le processus. OCI est le format normalisé des conteneurs : il décrit les namespaces, les cgroups et les montages à mettre en place. Docker ne crée donc pas les conteneurs lui-même.
Comment remonter la chaîne depuis l'hôte ?
Section intitulée « Comment remonter la chaîne depuis l'hôte ? »Vous partez du processus du conteneur et vous remontez de parent en parent. Docker vous donne le numéro de ce processus vu de la machine : c'est son PID, l'identifiant que le noyau attribue à chaque processus. Le conteneur veilleur exécute tail -f /dev/null, une commande qui ne fait rien et ne se termine jamais. Il vous suffit d'un processus vivant à remonter.
docker run -d --name veilleur alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a tail -f /dev/nullPID=$(docker container inspect veilleur --format '{{.State.Pid}}')SHIM=$(ps -o ppid= -p "$PID" | tr -d ' ')PARENT=$(ps -o ppid= -p "$SHIM" | tr -d ' ')ps -o pid,ppid,args -p "$PID,$SHIM,$PARENT"ps -o ppid= -p N affiche le numéro du parent du processus N, sans en-tête. Le dernier ps affiche trois lignes : le parent du shim, le shim, puis le tail. Il les trie par numéro croissant, donc le parent du shim vient en premier et le tail en dernier.
PID PPID COMMAND 1 0 /sbin/init 5257 1 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 5de653b80403d6cff66eaa0d7ff9bc823ff707280d7d14df9c2f1b9ccbc24520 -address /run/containerd/containerd.sock 5281 5257 tail -f /dev/nullRegardez la ligne du shim : son PPID vaut 1. Son parent n'est ni dockerd ni containerd. C'est le processus numéro 1 de la machine, le gestionnaire de services (systemd sur la plupart des distributions). Ce n'est pas une erreur de lecture : le shim a été détaché du programme qui l'a créé, et c'est voulu.
Vérifiez maintenant que le démon et containerd sont deux services distincts, avec chacun leur numéro, différents de ce parent.
systemctl show --property=MainPID docker.service containerd.serviceMainPID=3660
MainPID=3511systemctl affiche les deux numéros dans l'ordre demandé, docker.service puis containerd.service, séparés par une ligne vide. Ils sont différents l'un de l'autre, et aucun ne vaut 1. Le parent du shim n'est donc ni le démon ni containerd.
Vous pouvez aussi retrouver le shim autrement, en cherchant l'identifiant du conteneur dans la liste des processus. Le shim le porte dans ses arguments.
ID=$(docker container inspect veilleur --format '{{.Id}}')ps -eo pid,ppid,args | grep "$ID" | grep -v grepLa ligne affichée est celle du shim. Vous y retrouvez l'option -id suivie de l'identifiant du conteneur, comme dans la sortie précédente.
Pourquoi y a-t-il un shim par conteneur ?
Section intitulée « Pourquoi y a-t-il un shim par conteneur ? »Parce qu'avec un seul shim pour tous les conteneurs, sa chute les entraînerait tous. Lancez un second conteneur pour le vérifier : il a son propre shim, avec un autre numéro, mais le même parent.
docker run -d --name veilleur-bis alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a tail -f /dev/nullPID2=$(docker container inspect veilleur-bis --format '{{.State.Pid}}')SHIM2=$(ps -o ppid= -p "$PID2" | tr -d ' ')echo "shim de veilleur = $SHIM, shim de veilleur-bis = $SHIM2"ps -o ppid= -p "$SHIM2"shim de veilleur = 5257, shim de veilleur-bis = 53481Les deux shims ont des numéros différents, et la dernière ligne montre que leur parent est le même : le PID 1. Chaque conteneur a donc son shim, indépendant du démon qui l'a lancé et des autres conteneurs.
Ce que cela change quand le démon s'arrête, vous le mesurez dans la dernière section. Avant cela, il reste un maillon à regarder : le runtime.
Quel runtime crée réellement le conteneur ?
Section intitulée « Quel runtime crée réellement le conteneur ? »Docker déclare un runtime par défaut, et chaque conteneur déclare le sien. Les deux sont identiques sur une installation simple. Ils diffèrent dès que vous installez plusieurs runtimes, par exemple un runtime qui isole davantage le conteneur du noyau de la machine. Pour savoir ce qu'utilise un conteneur, lisez le runtime du conteneur, pas celui par défaut.
docker info --format '{{.DefaultRuntime}}'docker container inspect veilleur --format '{{.HostConfig.Runtime}}'runcruncLa première ligne est le runtime par défaut de Docker, la seconde celui de veilleur. Ici, les deux valent runc.
Parce que la chaîne comporte plusieurs programmes, vous pouvez remplacer le runtime sans toucher au reste : le shim, containerd et le démon ne changent pas.
Mettre en pratique
Section intitulée « Mettre en pratique »Le lab vous fait remonter la chaîne sur un conteneur déjà lancé. Vous notez dans un fichier de réponses les numéros de processus qui portent ce conteneur, puis vous lancez un second conteneur pour montrer que son processus intermédiaire est différent.
La validation interroge le système au moment de la notation. Aucun numéro n'est écrit à l'avance dans les contrôles : elle retrouve le processus intermédiaire grâce à l'identifiant du conteneur, lit son parent avec ps, et vérifie le runtime dans l'inspection du conteneur. Elle attend que le conteneur du lab tourne. Ne redémarrez donc pas le démon avant d'avoir validé le lab, car la section suivante se joue après lui.
Un conteneur survit-il au redémarrage du démon ?
Section intitulée « Un conteneur survit-il au redémarrage du démon ? »Pas par défaut. On pourrait croire le contraire, puisque les shims sont détachés du démon. Mais ce détachement rend la survie possible, il ne l'assure pas. Sans le réglage live-restore, le démon arrête ses conteneurs quand il s'arrête.
Quand il repart, il relance seulement les conteneurs dont la politique de redémarrage le permet. Cette politique est l'option --restart que vous posez à la création du conteneur. Avec always ou unless-stopped, le conteneur est relancé avec un nouveau numéro de processus. D'après la documentation de Docker, on-failure ne relance pas un conteneur quand le démon redémarre.
Le réglage "live-restore": true du fichier /etc/docker/daemon.json fait l'inverse : les conteneurs continuent de tourner pendant que le démon est arrêté. Il est présenté dans la configuration du démon.
Le schéma résume ce que devient un conteneur selon ces deux réglages. Suivez-le de haut en bas : la première question porte sur live-restore, la seconde sur la politique de redémarrage.
Comparez le numéro de processus et la date de démarrage d'un conteneur avant et après un redémarrage du démon. Faites cette mesure sur une machine de test, jamais sur un hôte qui porte des services. Si vous suivez le lab dans sa VM, attendez d'avoir validé le lab : son conteneur n'a pas de politique de redémarrage, il tomberait avec le démon et la validation échouerait.
docker container inspect veilleur --format 'pid={{.State.Pid}} demarre={{.State.StartedAt}}'sudo systemctl restart dockerdocker container inspect veilleur --format 'pid={{.State.Pid}} demarre={{.State.StartedAt}}'pid=5281 demarre=2026-11-01T23:02:43.446341174Zpid=0 demarre=2026-11-01T23:02:43.446341174ZLe conteneur veilleur a été créé sans politique de redémarrage. Docker l'a arrêté en s'arrêtant et ne l'a pas relancé. Son numéro de processus vaut donc 0, et sa date de démarrage n'a pas changé, puisqu'il n'a pas redémarré. Attendez quelques secondes après le redémarrage du démon avant de relire l'état.
Avec --restart unless-stopped, la même mesure donne un autre résultat. La politique de redémarrage est décrite dans le guide de diagnostic.
Avant de refaire la mesure, une précaution. Ce deuxième redémarrage suit le premier de près, et sur Engine 29.9.2 l'unité docker.service n'accepte que trois démarrages par minute. Au quatrième, systemctl répond « Job for docker.service failed because start of the service was attempted too often » et l'unité passe en échec (start-limit-hit). La commande sudo systemctl reset-failed docker supprime cette limite, et vous pouvez alors relancer le démon. Les deux redémarrages de cette page, séparés de quelques secondes, restent sous la limite.
docker run -d --name veilleur-ur --restart unless-stopped alpine:3.24@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a tail -f /dev/nulldocker container inspect veilleur-ur --format 'pid={{.State.Pid}} demarre={{.State.StartedAt}}'sudo systemctl restart dockerdocker container inspect veilleur-ur --format 'pid={{.State.Pid}} demarre={{.State.StartedAt}}'pid=5787 demarre=2026-11-01T23:03:00.023174869Zpid=6099 demarre=2026-11-01T23:03:11.137331998ZLe conteneur est de nouveau à l'état running, mais avec un nouveau numéro de processus et une nouvelle date de démarrage. Docker l'a relancé : il n'a pas survécu au redémarrage.
Comment nettoyer après les mesures ?
Section intitulée « Comment nettoyer après les mesures ? »Chacun des trois conteneurs de la page exécute un processus qui ne s'arrête jamais. Supprimez-les quand vous avez fini vos mesures. L'option -f arrête le conteneur s'il tourne. Elle fonctionne aussi pour veilleur, que le démon a déjà arrêté.
docker rm -f veilleur veilleur-bis veilleur-urLa commande affiche les trois noms, un par ligne. docker ps -a --filter name=veilleur ne doit plus rien lister.
À retenir
Section intitulée « À retenir »-
Le processus d'un conteneur n'est pas l'enfant de Docker. Il descend d'un shim (
containerd-shim-runc-v2), lancé par containerd à la demande du démondockerd. -
Le parent réel du shim est le PID 1 de la machine, le gestionnaire de services. Ce n'est ni le démon ni containerd, et ce détachement est voulu.
-
Il y a un shim par conteneur, tous rattachés au même parent. La chute de l'un n'entraîne pas celle des autres.
-
Le runtime se lit par conteneur (
.HostConfig.Runtime) et se remplace sans changer le reste de la chaîne. Une fois le conteneur créé,runcne reste pas en mémoire. -
Le détachement rend la survie possible, il ne l'assure pas. Sans
live-restore, un redémarrage du démon arrête les conteneurs, et ceux que Docker relance repartent avec un nouveau numéro de processus.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Score par domaine
Un domaine regroupe plusieurs guides et reçoit plusieurs questions : son score est plus fiable qu'un score par thème, qui porte souvent sur une seule question.
Bilan
Points forts
Aucun sujet réussi à 80 % sur au moins deux questions pour l’instant.
Points faibles
Aucun sujet sous le seuil de réussite.
À faire ensuite
Des indices pour retenter votre chance ?
Continuer le cours : Brider un conteneur : processeur, ulimits et mémoire partagée
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications