Chapitre 06
Docker sur l'edge : état & diagnostic
Objectifs du chapitre
- Distinguer les quatre objets Docker : image, conteneur, volume, réseau.
- Lire l'état du service edge :
docker ps,logs,inspect,stats, et le healthcheck. - Diagnostiquer les deux pannes classiques : le conteneur qui redémarre en boucle et le conteneur qui a disparu.
- Comprendre pourquoi les volumes sont là où vivent les données à sauvegarder (chapitre 8), et borner les logs pour ne pas remplir le disque.
1. Le vocabulaire minimal
| Objet | Ce que c'est | Analogie |
|---|---|---|
| Image | un modèle figé en lecture seule (app + dépendances), versionné par un tag | le « programme installé », une version précise |
| Conteneur | une instance en cours d'exécution d'une image | le programme « lancé » |
| Volume | un stockage persistant, hors du conteneur | le disque de données, qui survit au conteneur |
| Réseau | le réseau virtuel qui relie les conteneurs entre eux | le switch interne de la stack |
La distinction image ≠ conteneur est le socle : une image ne « tourne » pas, elle sert de moule ; un conteneur est une image en train de s'exécuter, avec son état propre. Et surtout : tout ce qu'un conteneur écrit hors d'un volume est perdu à sa recréation. C'est pour ça que les données vivent dans des volumes — retiens-le pour le chapitre 8 (sauvegarde).
2. Voir ce qui tourne : docker ps
maint@edge-cell12:~$ docker ps
CONTAINER ID IMAGE STATUS PORTS NAMES
b1f9a2c3d4e5 registry.local/edge:1.8.2 Up 87 days (healthy) 0.0.0.0:8080->8080/tcp edge-gateway
7a2b1c9d8e6f eclipse-mosquitto:2.0.18 Up 87 days 0.0.0.0:1883->1883/tcp edge-mqtt
Chaque colonne dit quelque chose d'utile :
- IMAGE :
registry.local/edge:1.8.2— l'image et son tag. Le tag1.8.2est explicite ; méfie-toi d'un:latest(chapitre 7). - STATUS :
Up 87 days (healthy)— tourne depuis 87 jours et son healthcheck est vert.Restarting,Exited (1),unhealthysont les états qui alertent. - PORTS :
0.0.0.0:8080->8080/tcp— le port 8080 du conteneur est publié sur toutes les interfaces de l'edge.
docker ps ne montre que les conteneurs en cours d'exécution. Un
conteneur qui a planté n'apparaît pas — et on croit à tort qu'« il n'existe pas ». Pour voir
aussi les morts, il faut docker ps -a : c'est là qu'on découvre un
Exited (137) révélateur. Réflexe : quand un conteneur « a disparu », la
première commande est docker ps -a, pas docker ps.
maint@edge-cell12:~$ docker ps -a
CONTAINER ID IMAGE STATUS NAMES
b1f9a2c3d4e5 registry.local/edge:1.8.2 Up 87 days (healthy) edge-gateway
7a2b1c9d8e6f eclipse-mosquitto:2.0.18 Exited (137) 4 minutes ago edge-mqtt
3. Que dit le conteneur : docker logs
La sortie de l'application à l'intérieur du conteneur (que journald ne montre pas) se lit
avec docker logs :
maint@edge-cell12:~$ docker logs --tail 20 -f edge-gateway
2026-07-04T08:24:01Z INFO connected to opc.tcp://192.168.0.1:4840
2026-07-04T08:24:01Z INFO subscribed 128 nodes, publish interval 1000ms
2026-07-04T08:24:02Z INFO → mqtt localhost:1883 (128 tags)
^C
Les options utiles : --tail 20 (les 20 dernières lignes), -f (suivre en
direct, comme journalctl -f), --since 10m (fenêtre temporelle),
--timestamps (forcer l'horodatage).
Rappel de la répartition : journalctl -u edge-gateway répond « le
service a-t-il démarré/planté ? » (vu par systemd) ; docker logs
edge-gateway répond « que dit l'application dedans ? ». Sur un service
edge qui remonte des données, la panne applicative (session OPC-UA refusée, broker injoignable) se lit
dans docker logs.
4. Le healthcheck : sain ou malade ?
Un conteneur peut être Up (le processus tourne) tout en étant incapable de rendre son
service (bloqué, déconnecté). Le healthcheck est une sonde définie dans l'image
ou le compose qui teste périodiquement la santé applicative. On voit son verdict dans STATUS
(healthy/unhealthy) et son détail avec inspect :
maint@edge-cell12:~$ docker inspect --format '{{json .State.Health}}' edge-gateway | python3 -m json.tool
{
"Status": "healthy",
"FailingStreak": 0,
"Log": [
{ "ExitCode": 0, "Output": "OPC-UA up; MQTT up\n" }
]
}
Un conteneur Up … (unhealthy) est un signal précieux : le processus n'est
pas mort, donc docker ps paraît normal, mais la sonde applicative échoue. C'est
typiquement l'edge qui « tourne » mais ne remonte plus rien : la session OPC-UA est
tombée, ou le broker MQTT ne répond plus. Sans healthcheck, cette panne serait invisible jusqu'à ce que
quelqu'un remarque l'absence de données côté supervision.
5. Consommation : docker stats
maint@edge-cell12:~$ docker stats --no-stream
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O
edge-gateway 3.2% 142MiB / 512MiB 27.7% 88MB / 44MB 12MB / 0B
edge-mqtt 0.8% 18MiB / 128MiB 14.1% 44MB / 88MB 2MB / 0B
--no-stream donne un instantané (sans lui, l'affichage se rafraîchit en continu). On
surveille surtout la colonne MEM USAGE / LIMIT : un conteneur qui frôle sa limite
mémoire est candidat à se faire tuer par le noyau (l'OOM kill du chapitre 4), avec un code
de sortie 137.
6. Panne classique nº 1 : le restart loop
docker ps montre le conteneur en Restarting en boucle. La démarche :
maint@edge-cell12:~$ docker ps
CONTAINER ID IMAGE STATUS NAMES
b1f9a2c3d4e5 registry.local/edge:1.8.2 Restarting (1) 8 seconds ago edge-gateway
maint@edge-cell12:~$ docker logs --tail 5 edge-gateway
2026-07-04T09:01:14Z FATAL config file /cfg/gateway.yml: no such file or directory
maint@edge-cell12:~$ docker inspect --format '{{.State.ExitCode}} {{.RestartCount}}' edge-gateway
1 214
Lecture : le conteneur sort en erreur (ExitCode 1), la politique de redémarrage le
relance, il replante — 214 fois. La cause est dans docker logs : un fichier de config
manquant (un volume mal monté ? un chemin renommé ?). Le restart loop n'est
pas la maladie, c'est le symptôme : on lit toujours la dernière erreur avant le
redémarrage.
Les codes de sortie les plus parlants : 137 = tué par SIGKILL, presque
toujours un OOM kill (manque de mémoire) — croise avec journalctl -k | grep -i oom
et docker stats. 139 = segfault (SIGSEGV), un bug applicatif.
143 = arrêt propre par SIGTERM (normal lors d'un stop). 1 = erreur
applicative générique — la vraie raison est dans les logs.
7. Réseaux & volumes en un coup d'œil
maint@edge-cell12:~$ docker volume ls
DRIVER VOLUME NAME
local edge_gateway-data # ← les données à sauvegarder (ch. 8)
local edge_mqtt-data
maint@edge-cell12:~$ docker network ls
NETWORK ID NAME DRIVER SCOPE
3f1a... edge_default bridge local
# Les conteneurs de la stack se parlent par leur nom sur ce réseau :
# edge-gateway atteint le broker via « edge-mqtt:1883 », pas via une IP.
Sur le réseau d'une stack compose, les conteneurs se résolvent par leur nom de service
(DNS interne Docker). Si le gateway ne joint plus le broker, avant de suspecter le réseau OT, vérifie que
les deux sont bien sur le même réseau Docker et que le nom de service n'a pas changé : une
erreur « could not resolve edge-mqtt » est interne à Docker, pas un problème de
câble.
8. Borner les logs Docker (place disque)
Par défaut, le pilote de logs json-file de Docker écrit sans limite : un conteneur
bavard peut remplir /var/lib/docker et donc le disque. On borne, globalement dans
/etc/docker/daemon.json :
{
"log-driver": "json-file",
"log-opts": { "max-size": "20m", "max-file": "5" }
}
Chaque conteneur garde alors au plus 5 fichiers de 20 Mo. On applique par
sudo systemctl restart docker — ce qui redémarre tous les conteneurs, donc à
faire dans une fenêtre de maintenance. On peut aussi mettre ces options par service dans le compose
(chapitre 7), ce qui évite le restart global.
Le geste à ne jamais faire à l'aveugle sur un edge : docker system
prune -a. Il supprime toutes les images non utilisées par un conteneur actif — y compris
l'image de la version précédente que tu gardais exprès pour un rollback (chapitre 7), et
potentiellement une image dont dépend un conteneur arrêté que tu comptais relancer. Sur un edge sans
accès facile au registry, tu peux te retrouver incapable de redéployer. Purge de façon ciblée
(docker image rm <tag précis>), jamais en masse.
Récapitulatif
- Quatre objets : image (modèle figé + tag), conteneur (instance qui tourne), volume (données persistantes), réseau (lien interne). Hors volume, tout est perdu à la recréation.
docker ps(ce qui tourne) maisdocker ps -apour voir les morts ;docker logs -f(ce que dit l'app),inspect(healthcheck, exit code, restart count),stats(CPU/mémoire).- Un conteneur
Up (unhealthy)tourne mais ne rend pas son service — signal précieux. - Restart loop : lire la dernière erreur dans
docker logs; exit 137 = OOM, 143 = SIGTERM normal, 1 = erreur applicative. - Borner les logs (
max-size) pour la place disque ; jamais dedocker system prune -aà l'aveugle (il tue tes images de rollback).
Exercices
Exercice 1 — « Le conteneur a disparu »
Un collègue dit que edge-mqtt « n'existe plus » car docker ps ne
le montre pas. Comment vérifies-tu s'il a planté, et pourquoi ?
Voir la solution
$ docker ps -a | grep edge-mqtt
7a2b1c9d8e6f eclipse-mosquitto:2.0.18 Exited (137) 4 minutes ago edge-mqtt
$ docker logs --tail 20 edge-mqtt # que disait-il avant de mourir ?
$ journalctl -k | grep -i oom # le noyau l'a-t-il tué (OOM) ?
docker ps -a révèle le conteneur mort (que docker ps cache). Le
Exited (137) oriente vers un OOM kill ; on confirme avec les logs du noyau et
docker stats sur les conteneurs restants. Le conteneur n'a pas « disparu », il
s'est arrêté — on peut le relancer une fois la cause traitée.
Exercice 2 — Up mais rien ne remonte
La supervision ne reçoit plus de données, pourtant docker ps montre
edge-gateway en Up. Où regardes-tu ?
Voir la solution
Le mot-clé est le healthcheck : regarde si le STATUS dit (unhealthy), et lis la
sonde :
$ docker ps # Up ... (unhealthy) ?
$ docker inspect --format '{{json .State.Health}}' edge-gateway
$ docker logs --tail 30 edge-gateway # session OPC-UA tombée ? broker injoignable ?
« Up » ne veut pas dire « fonctionne ». Le healthcheck et les logs applicatifs disent la vérité : souvent la session OPC-UA vers le CPU est tombée (redémarrage automate, certificat, réseau) ou le broker MQTT ne répond plus. La cause peut même être en dehors de l'edge (l'automate) — d'où l'intérêt du cours réseau en complément.
Exercice 3 — Pourquoi pas prune -a ?
Le disque se remplit d'images Docker. Un collègue lance docker system prune -a. Quel
risque, et quelle alternative ?
Voir la solution
prune -a supprime toutes les images qu'aucun conteneur actif n'utilise —
dont l'image de la version précédente gardée exprès pour un rollback
(chapitre 7). Sur un edge coupé du registry, on peut alors ne plus pouvoir redéployer l'ancienne
version. Alternative ciblée : docker images pour lister, puis
docker image rm registry.local/edge:1.7.0 pour retirer une image précise dont on
est sûr de ne plus avoir besoin. On peut aussi docker image prune (sans -a)
qui ne retire que les couches « dangling » (orphelines), bien plus sûr.