Tom Daluzeau
← Parcours Linux
Linux · leçon 4 / 6Ch. 1 · systemd11 minTerminée

systemd : unités et services

Tu sais lire et écrire un fichier .service section par section, choisir le bon Type et le bon Restart, expliquer ce qu'est une cible, et distinguer une dépendance (Wants, Requires) d'un simple ordre de démarrage (After, Before).

Mis à jour le

Pourquoi on voit ça

La leçon précédente s’arrêtait sur systemd, le PID 1 : le premier processus, celui qui lance tout le reste. Mais comment sait-il quoi lancer, dans quel ordre, et quoi faire si un programme plante ?

Tout est écrit dans de petits fichiers texte : les unités. En DevOps, tu en liras tous les jours et tu en écriras dès que tu déploieras ta propre application sur un serveur. Savoir lire une unité, c’est comprendre pourquoi un service démarre, ou ne démarre pas.

Une unité, c’est quoi ?

Une unité est un objet que systemd sait gérer. Chaque unité est décrite par un fichier, et l’extension du fichier donne son type.

Extension Ce que l’unité gère Exemple
.service un programme à lancer et à surveiller ssh.service
.target un groupe d’unités, un état à atteindre multi-user.target
.timer une planification (lancer un service à une heure donnée) apt-daily.timer
.socket un port ou un socket en écoute ssh.socket
.mount un point de montage home.mount

Le type le plus courant, c’est le .service. On commence par lui.

Anatomie d’un fichier .service

Voici une unité complète pour une petite application web :

[Unit]
Description=Application web de démonstration
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /opt/monapp/app.py
Restart=on-failure

[Install]
WantedBy=multi-user.target

Trois sections, toujours entre crochets. Chacune répond à une question.

[Unit] Description=Application web After=network.target [Service] Type=simple ExecStart=/usr/bin/python3 … Restart=on-failure [Install] WantedBy=multi-user.target Qui es-tu, avec qui es-tu lié ? nom lisible, dépendances, ordre Comment te lance-t-on ? la commande, le Type, le Restart Quand t'active-t-on ? lu par systemctl enable
Une section, une question. [Install] ne sert à rien tant qu'on n'a pas fait enable.
Section Question Directives à connaître
[Unit] Qui es-tu, et avec qui es-tu lié ? Description, les dépendances
[Service] Comment te lance-t-on ? ExecStart, Type, Restart
[Install] À quel moment du démarrage t’active-t-on ? WantedBy
  • Description : une phrase lisible par un humain. Elle s’affiche dans les commandes d’état et dans les journaux.
  • ExecStart : la commande à lancer, avec son chemin complet (/usr/bin/python3, pas python3).
  • WantedBy=multi-user.target : « quand le serveur atteint son état normal, lance-moi aussi ». C’est cette ligne qui est utilisée quand on active le service au démarrage.

Type : comment le programme se comporte

Type dit à systemd à quoi s’attendre une fois la commande lancée.

Valeur Comportement du programme Cas typique
simple il reste au premier plan ; le processus lancé par ExecStart est le service une application moderne (valeur par défaut)
forking il se dédouble, le parent se termine et l’enfant continue en arrière-plan un démon à l’ancienne
oneshot il fait son travail puis se termine ; systemd attend la fin un script de sauvegarde ou de nettoyage
notify comme simple, mais le programme prévient lui-même systemd quand il est prêt un service qui met du temps à s’initialiser

Si tu te trompes de Type, systemd comprend mal ce qu’il voit. Par exemple, avec simple sur un programme qui se détache, systemd voit le processus de départ se terminer et croit que le service s’est arrêté.

Restart : que faire quand il s’arrête

Valeur systemd relance le service…
no jamais (valeur par défaut)
on-failure seulement s’il s’est terminé en erreur (code de sortie différent de 0, plantage)
always toujours, quelle que soit la raison de l’arrêt

Dans tous les cas, un arrêt que tu demandes à systemd n’est pas suivi d’une relance.

Les cibles

Une cible (.target) ne lance rien elle-même. C’est un point de rassemblement : elle regroupe des unités et représente un état du système. « Atteindre la cible », c’est avoir démarré tout ce qu’elle regroupe.

Cible État du système
multi-user.target plusieurs utilisateurs, réseau, mode texte : l’état normal d’un serveur
graphical.target la même chose, plus l’interface graphique : un poste de travail
rescue.target le mode dépannage : root seul, le strict minimum de services
graphical.target + l'interface graphique multi-user.target réseau, plusieurs utilisateurs, mode texte ssh.service nginx.service monapp.service fournis par les paquets WantedBy=multi-user.target default.target → multi-user.target sur un serveur : c'est ce lien que lit get-default
Atteindre une cible, c'est avoir démarré tout ce qu'elle regroupe.

Au démarrage, systemd vise la cible par défaut. Pour la connaître :

systemctl get-default

En coulisses, default.target est un lien vers la vraie cible : get-default lit ce lien. Deux commandes voisines :

systemctl set-default multi-user.target
systemctl isolate rescue.target

set-default change la cible des prochains démarrages. isolate bascule tout de suite dans la cible demandée et arrête ce qui n’en fait pas partie : avec rescue.target, il ne reste que le minimum pour dépanner.

Tu comprends maintenant WantedBy=multi-user.target : ton service s’accroche à la cible que le serveur atteint à chaque démarrage.

Les dépendances

Les directives de dépendance s’écrivent dans [Unit]. Il y a deux questions différentes, et c’est le piège du chapitre :

  1. Faut-il lancer l’autre unité ? → Wants, Requires
  2. Dans quel ordre ? → After, Before

Imagine qu’on écrit dans l’unité A :

Directive dans A Sens
Wants=B B est souhaitée : lancer A lance aussi B, mais si B échoue, A démarre quand même
Requires=B B est obligatoire : lancer A lance aussi B, et si B échoue, A ne démarre pas
After=B A démarre après B
Before=B A démarre avant B
Conflicts=B A et B ne peuvent pas tourner ensemble : démarrer A arrête B
Faut-il lancer B ? Wants, Requires Wants=B si B échoue A démarre quand même Requires=B si B échoue A ne démarre pas Dans quel ordre ? After, Before After=B B démarre puis A B d'abord Before=B A démarre puis B A d'abord After et Before ne lancent rien : ils fixent seulement l'ordre
Toutes les directives sont écrites dans A. After=B : A passe après B.

After et Before ne règlent que l’ordre. After=B ne lance pas B : la directive dit seulement « si les deux doivent démarrer, B passe d’abord ». À l’inverse, Requires=B sans After=B lance les deux en même temps.

C’est pour ça qu’on les écrit souvent par paires :

[Unit]
Description=Application qui a besoin de sa base
Requires=postgresql.service
After=postgresql.service

Une analogie : pour un repas, Requires dit « pas de repas sans plat principal », After dit « le dessert se sert après le plat ». Ce sont deux informations distinctes.

Mesurer le démarrage : systemd-analyze

Puisque systemd lance tout, il sait combien de temps chaque chose a pris.

systemd-analyze

Cette commande affiche le temps total du dernier démarrage, découpé par grandes phases (noyau, puis espace utilisateur).

systemd-analyze blame

Celle-ci liste les unités de la plus lente à la plus rapide. Blame veut dire « accuser » : c’est la commande à lancer quand un serveur est devenu lent à démarrer.

À retenir

  • Une unité = un objet géré par systemd, décrit par un fichier. L’extension donne le type : .service, .target, .timer, .socket, .mount.
  • Un .service a trois sections : [Unit] (identité et liens), [Service] (ExecStart, Type, Restart), [Install] (WantedBy).
  • Type : simple (reste au premier plan), forking (se détache), oneshot (fait son travail et se termine).
  • Restart : no, on-failure (seulement après une erreur), always.
  • Wants = souhaitée, Requires = obligatoire. After et Before ne règlent que l’ordre : After=B dans A veut dire que A démarre après B.
  • systemctl get-default donne la cible par défaut ; systemd-analyze blame désigne les unités lentes au démarrage.

Entraînement

12 questions, dont 4 à compléter. Tu réponds, on passe à la suivante. La note arrive à la fin.

Cartes · 8

Réviser les cartes ici

Espace : retourner