Chapitre 03
systemd : état des services & remise en route
Objectifs du chapitre
- Comprendre ce qu'est une unité systemd et lire son état
(
active,failed,enabled…). - Inspecter le système avec
systemctl status,list-units,--failed, et lire les dépendances. - Distinguer les quatre verbes qui comptent :
start/stop,restart/reload,enable/disable. - Écrire une unité de service pour lancer le service edge au boot, et mesurer le
démarrage avec
systemd-analyze.
1. systemd, PID 1 : le chef d'orchestre
Au démarrage de Debian, le noyau lance un unique processus qui porte le numéro PID 1 :
systemd. C'est lui qui démarre tout le reste, dans le bon ordre, en respectant les
dépendances, et qui supervise ensuite chaque service : s'il meurt, systemd peut le
relancer ; s'il refuse de démarrer, systemd le marque failed et garde la trace.
Tout ce que gère systemd est décrit par des unités. Les types qu'on croise sur un edge :
| Suffixe | Type d'unité | Exemple |
|---|---|---|
.service | un service (démon) | docker.service, chronyd.service |
.socket | un socket qui active un service à la demande | ssh.socket |
.timer | un déclencheur périodique (cron moderne) | backup.timer (chapitre 8) |
.target | un groupe/étape (ancien « runlevel ») | multi-user.target |
.mount | un point de montage | data.mount |
2. Lire l'état d'un service
La commande de base, systemctl status, donne une photo complète :
maint@edge-cell12:~$ systemctl status chronyd
● chronyd.service - chrony, an NTP client/server
Loaded: loaded (/lib/systemd/system/chronyd.service; enabled; preset: enabled)
Active: active (running) since Tue 2026-04-08 06:14:02 CEST; 87 days ago
Docs: man:chronyd(8)
Main PID: 612 (chronyd)
Tasks: 1 (limit: 4571)
Memory: 2.1M
CPU: 41.800s
CGroup: /system.slice/chronyd.service
└─612 /usr/sbin/chronyd -F 1
Les deux lignes qui portent l'information :
- Loaded … enabled — l'unité est chargée et
enabled= elle démarrera automatiquement au prochain boot. (disabled= installée mais pas lancée au boot.) - Active: active (running) — l'état runtime maintenant. Les valeurs qu'on
voit :
active (running),active (exited)(a fini son travail, normal pour un one-shot),inactive (dead)(arrêté), et surtoutfailed.
Deux axes indépendants à ne pas confondre : enabled/disabled répond à
« démarre-t-il au boot ? », active/inactive à « tourne-t-il
maintenant ? ». Un service peut être enabled mais inactive (planté),
ou active mais disabled (lancé à la main, il ne reviendra pas après reboot —
piège classique : « ça marchait, puis on a rebooté et c'est parti »).
Balayer tout le système
maint@edge-cell12:~$ systemctl --failed
UNIT LOAD ACTIVE SUB DESCRIPTION
● edge-gateway.service loaded failed failed Edge Gateway (OPC-UA → MQTT)
1 loaded units listed.
systemctl --failed est la première commande de diagnostic : elle liste tout
ce qui est en échec, rien d'autre. Ici, le service edge est tombé. On regarde ensuite son statut détaillé.
3. Lire un service failed
maint@edge-cell12:~$ systemctl status edge-gateway
● edge-gateway.service - Edge Gateway (OPC-UA → MQTT)
Loaded: loaded (/etc/systemd/system/edge-gateway.service; enabled)
Active: failed (Result: exit-code) since Sat 2026-07-04 08:03:11 CEST; 2min ago
Process: 21874 ExecStart=/usr/bin/docker compose -f /opt/edge/compose.yml up (code=exited, status=1)
Main PID: 21874 (code=exited, status=1)
Jul 04 08:03:11 edge-cell12 docker[21874]: Error response from daemon: driver failed programming
Jul 04 08:03:11 edge-cell12 docker[21874]: external connectivity: port 1883 already allocated
Jul 04 08:03:11 edge-cell12 systemd[1]: edge-gateway.service: Failed with result 'exit-code'.
Le bloc status se lit de bas en haut : systemd affiche les dernières lignes
de journal de l'unité. Ici la cause est explicite — port 1883 déjà alloué : un
ancien conteneur MQTT tient encore le port. On saura le résoudre au chapitre 6 ; pour l'instant,
l'important est que systemctl status a montré la cause sans qu'on aille chercher
ailleurs.
Le réflexe canonique face à un service en défaut : systemctl status <unité>
pour la photo + les dernières erreurs, puis journalctl -u <unité> -e (chapitre 4)
pour le fil complet. Neuf pannes sur dix se diagnostiquent dans ces deux commandes.
4. Les verbes d'action
Une fois la cause comprise, on agit. Quatre paires de verbes couvrent l'exploitation ; tous
demandent sudo.
| Commande | Effet | Quand |
|---|---|---|
start / stop | lance / arrête maintenant | action ponctuelle |
restart | stop puis start | relancer un service planté ou après changement de config d'app |
reload | recharge la config sans couper | quand le service le supporte (ex. ssh, chronyd) |
enable / disable | (dé)active le démarrage au boot | rendre un service permanent |
maint@edge-cell12:~$ sudo systemctl restart edge-gateway
maint@edge-cell12:~$ systemctl is-active edge-gateway
active
maint@edge-cell12:~$ systemctl is-enabled edge-gateway
enabled
enable --now combine enable + start en une fois, et
disable --now combine disable + stop. Pratique pour « je veux
que ce service tourne et revienne au boot » d'un seul geste :
sudo systemctl enable --now edge-gateway.
Voir les dépendances
Le service edge dépend de Docker, qui dépend du réseau… list-dependencies déroule l'arbre :
maint@edge-cell12:~$ systemctl list-dependencies edge-gateway
edge-gateway.service
● ├─docker.service
● ├─system.slice
● └─network-online.target
● └─...
Utile quand un service ne démarre pas « sans raison » : souvent c'est une dépendance en amont qui a échoué (Docker pas prêt, réseau pas monté). On corrige la cause, pas le symptôme.
5. Écrire l'unité du service edge
Pour que le service edge démarre au boot, survive à un crash et s'intègre aux journaux, on l'enveloppe
dans une unité systemd. Fichier /etc/systemd/system/edge-gateway.service :
[Unit]
Description=Edge Gateway (OPC-UA → MQTT)
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/edge
# Démarre la stack Docker Compose au premier plan (pas de -d)
ExecStart=/usr/bin/docker compose -f /opt/edge/compose.yml up
ExecStop=/usr/bin/docker compose -f /opt/edge/compose.yml down
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Les clés importantes :
Requires+Afterdocker.service : le service edge a besoin de Docker et ne doit démarrer qu'après lui.Requiresexprime la dépendance,Afterl'ordre — les deux sont nécessaires.Restart=on-failure+RestartSec=10: si le service sort en erreur, systemd le relance après 10 s. C'est la résilience de base.WantedBy=multi-user.target: c'est ce qui rendenableeffectif — le service s'accroche à l'étape « système multi-utilisateur » atteinte à chaque boot.
Après toute création ou édition d'unité, on recharge la définition avant d'agir :
maint@edge-cell12:~$ sudo systemctl daemon-reload # relit les fichiers d'unités
maint@edge-cell12:~$ sudo systemctl enable --now edge-gateway
Created symlink /etc/systemd/system/multi-user.target.wants/edge-gateway.service → /etc/systemd/system/edge-gateway.service.
Oublier daemon-reload après avoir modifié un fichier .service est l'erreur
la plus courante : systemd continue d'utiliser l'ancienne version en mémoire et tes
changements semblent « ignorés ». systemd te prévient d'ailleurs avec un
Warning: The unit file … changed on disk. Run 'systemctl daemon-reload'. Réflexe :
j'édite une unité → je fais daemon-reload → j'agis.
Deux écoles pour le service edge, toutes deux valables : (a) une unité systemd
qui lance docker compose up (ci-dessus) — systemd est le superviseur, les logs vont
dans journald ; (b) laisser Docker gérer avec restart: unless-stopped
dans le compose (chapitre 7) — c'est le démon Docker qui relance. On peut combiner : le plus
robuste est d'avoir Docker enabled au boot et une politique de restart dans le
compose, l'unité systemd servant surtout d'interrupteur clair et de point de log.
6. Mesurer le démarrage : systemd-analyze
Un edge qui met deux minutes à booter, c'est deux minutes sans remontée de données. systemd-analyze
dit où part le temps.
maint@edge-cell12:~$ systemd-analyze
Startup finished in 3.891s (kernel) + 18.4s (userspace) = 22.3s
maint@edge-cell12:~$ systemd-analyze blame | head -5
11.204s docker.service
4.019s edge-gateway.service
1.337s NetworkManager-wait-online.service
812ms chronyd.service
330ms systemd-journald.service
blame classe les unités par durée de démarrage. Ici Docker domine (normal : il monte
ses réseaux et volumes), suivi du service edge. Si un service inattendu traîne en tête, c'est une
piste — souvent un *-wait-online qui attend un réseau qui ne vient jamais.
Le pendant côté automate : le CPU S7-1500 a lui aussi une séquence de démarrage (STOP → STARTUP → RUN) et des diagnostics de mise en route dans TIA. La philosophie est jumelle : un redémarrage n'est pas instantané, il suit un ordre de dépendances, et on peut en mesurer/lire chaque étape. Sur l'edge, cet ordre, c'est systemd qui le tient.
Récapitulatif
- systemd (PID 1) démarre et supervise tout via des unités
(
.service,.socket,.timer,.target). - Deux axes indépendants : enabled/disabled (démarre au boot ?) et active/failed (tourne maintenant ?).
- Diagnostic :
systemctl --failedpuissystemctl status <unité>— les dernières lignes de journal montrent souvent la cause directement. - Verbes :
restart(relancer),reload(recharger sans couper),enable --now(permanent + démarre). - Une unité pour le service edge :
Requires/After=docker.service,Restart=on-failure,WantedBy=multi-user.target. Toujoursdaemon-reloadaprès édition. systemd-analyze blamepour savoir où part le temps de boot.
Exercices
Exercice 1 — « Ça marchait, puis on a rebooté »
Un service tournait, mais après le dernier reboot il n'est plus là. systemctl status
montre active: inactive (dead). Quelle est la cause probable, et quelle commande la
confirme puis la corrige ?
Voir la solution
$ systemctl is-enabled monservice
disabled # ← voilà : il n'était pas activé au boot
$ sudo systemctl enable --now monservice
Le service avait été lancé à la main (start) mais jamais enable. Il
tournait donc jusqu'au reboot, puis n'est pas revenu. enable --now le relance et
le rend permanent. C'est la confusion enabled/active du §2.
Exercice 2 — Un service en échec : la démarche
systemctl --failed montre edge-gateway.service en failed. Écris
la séquence exacte pour comprendre pourquoi, puis le relancer une fois la cause traitée.
Voir la solution
$ systemctl status edge-gateway # photo + dernières erreurs
$ journalctl -u edge-gateway -e # fil de journal complet (ch. 4)
# … on lit la cause, on la corrige (port occupé, image manquante, disque plein…) …
$ sudo systemctl restart edge-gateway
$ systemctl is-active edge-gateway
active
On ne relance jamais en boucle sans lire la cause : un
restart aveugle sur un service qui échoue à cause d'un disque plein ou d'un port occupé
rejouera le même échec. Lire d'abord, agir ensuite.
Exercice 3 — Mes changements d'unité sont ignorés
Tu modifies /etc/systemd/system/edge-gateway.service pour ajouter
RestartSec=30, tu fais restart, mais le comportement n'a pas changé. Pourquoi,
et comment corriger ?
Voir la solution
systemd travaille sur la version en mémoire de l'unité, pas sur le fichier fraîchement édité. Il faut lui dire de relire les fichiers :
$ sudo systemctl daemon-reload
$ sudo systemctl restart edge-gateway
daemon-reload recharge les définitions ; restart applique le
nouveau comportement au service qui tourne. L'ordre compte : reload puis restart.