Aller au contenu
Administration Linux medium

systemd : comprendre le gestionnaire de services Linux

21 min de lecture

systemd est le gestionnaire de système et de services de la quasi-totalité des distributions Linux modernes. C'est le premier programme que le noyau lance au démarrage, celui qui porte le PID 1 (Process IDentifier numéro 1) et devient le parent de tous les autres processus. Son travail tient en quatre verbes : démarrer la machine dans le bon ordre, lancer et superviser les services (les programmes qui tournent en arrière-plan sans interface), les relancer quand ils tombent, et centraliser les journaux en un seul endroit. Cette page pose le modèle mental : les unités, les targets, les dépendances, pour que les commandes que vous taperez ensuite aient du sens.

Cette page est une page de concept, pas un tutoriel de commandes. Elle sert à comprendre comment systemd raisonne, parce que les erreurs les plus tenaces en administration Linux viennent d'un modèle mental faux, pas d'une option mal tapée.

  • Ce qu'est systemd, et ce qui le distingue de systemctl
  • Pourquoi il a remplacé SysV init, et ce qu'on lui reproche
  • Le concept d'unité et les huit types que vous croiserez
  • La différence entre ordre de démarrage et dépendance
  • Pourquoi daemon-reload n'est pas une formalité

Quand vous allumez un serveur Linux, le noyau se charge en mémoire, monte le système de fichiers racine, puis passe la main à un programme en espace utilisateur. Ce programme reçoit le PID 1. Il ne s'arrêtera jamais tant que la machine tourne, et tous les autres processus descendront de lui. Sur une distribution moderne, ce programme s'appelle systemd.

Vérifiez-le sur votre machine, la commande fonctionne partout :

Fenêtre de terminal
ps -p 1 -o comm=
# systemd
systemctl --version | head -1
# systemd 257 (257.13-1~deb13u1)

Le terme daemon, que vous verrez partout dans ce domaine, désigne simplement un programme qui tourne en arrière-plan, détaché de tout terminal : un serveur web, une base de données, un agent de supervision. Le d final de systemd vient de là. Le rôle de systemd est de lancer ces daemons, de savoir à tout instant lesquels tournent, et de réagir quand l'un d'eux meurt.

Attention à une nuance qui coûte cher aux débutants : systemd n'est pas une commande. C'est un processus permanent. Ce que vous tapez, vous, c'est systemctl, la commande cliente qui transmet vos ordres à systemd et affiche son état. systemd est le serveur, systemctl est la télécommande. La même logique vaut pour journalctl, qui lit le journal que systemd collecte.

Avant systemd, le PID 1 était SysV init. Son fonctionnement était simple à décrire : au démarrage, il exécutait des scripts shell rangés dans /etc/init.d/, appelés un par un, dans l'ordre imposé par des liens symboliques numérotés (S20nginx passait avant S30postgresql). Chaque script devait gérer lui-même le lancement en arrière-plan, l'écriture d'un fichier PID, l'arrêt propre et les codes de retour, souvent sur plusieurs centaines de lignes.

Ce modèle a deux faiblesses structurelles. D'abord la lenteur : un script qui attend le réseau bloque toute la file, même les services qui n'ont rien à voir. Ensuite l'absence de supervision : une fois le script terminé, plus personne ne surveille le processus. S'il meurt trois heures plus tard, init l'ignore.

AspectSysV initsystemd
DémarrageSéquentiel, un script à la foisParallèle, piloté par un graphe de dépendances
DépendancesEncodées à la main dans la numérotationDéclarées explicitement dans le fichier unité
SupervisionAucune après le lancementPermanente, avec politique de redémarrage
Suivi des processusFichier PID, souvent périmé ou fauxcgroups, tous les enfants sont suivis
JournauxFichiers dispersés dans /var/log/Journal centralisé, interrogeable
Écriture d'un serviceScript shell de 100 à 300 lignesFichier déclaratif de 10 à 20 lignes

systemd renverse la logique : au lieu d'exécuter des scripts dans un ordre figé, il lit des fichiers déclaratifs où chaque service dit de quoi il a besoin, puis il calcule le graphe de dépendances et démarre en parallèle tout ce qui peut l'être. Le gain de temps au boot est réel, mais le vrai apport est ailleurs : systemd garde la main sur les processus qu'il a lancés.

Il serait malhonnête de présenter systemd comme un consensus. Son adoption, autour de 2014-2015, a provoqué une des controverses les plus violentes de l'histoire de Linux, et les critiques n'ont pas disparu.

Le reproche central porte sur le périmètre. systemd ne s'est pas contenté de remplacer init : le projet a absorbé la journalisation, la résolution DNS, la configuration réseau, la gestion des sessions, la synchronisation de l'heure. Pour ses détracteurs, cette centralisation contredit la philosophie Unix du « un outil, une tâche », crée un point de défaillance unique en PID 1, et rend le système plus difficile à comprendre de bout en bout. Le second reproche est la complexité : là où un script d'init se lisait avec un shell, comprendre pourquoi systemd a pris telle décision demande de connaître son modèle d'unités, ses cibles implicites et ses générateurs.

Les mainteneurs répondent que ces composants sont optionnels et séparables, et que la fiabilité de la supervision justifie la surface. Le fait est là : Debian, Ubuntu, RHEL, Fedora, SUSE et Arch l'ont adopté. En environnement professionnel, vous administrerez du systemd. Des alternatives subsistent néanmoins, et elles ne sont pas marginales : Alpine Linux utilise OpenRC, Void Linux utilise runit, et Devuan est un fork de Debian créé précisément pour rester sans systemd.

Tout ce que systemd gère est une unité (unit). Une unité est un objet décrit par un fichier texte au format INI, découpé en sections entre crochets. Un service est une unité, un point de montage est une unité, une tâche planifiée est une unité. C'est le concept central : si vous ne retenez qu'une chose de cette page, retenez celle-là.

L'extension du fichier détermine le type d'unité et donc le comportement de systemd :

ExtensionCe que ça gèreExemple concret
.serviceUn programme à lancer et supervisernginx.service
.timerUne tâche planifiée, l'alternative à cronlogrotate.timer
.socketUn port ou un socket, avec activation à la demandessh.socket
.mountUn point de montage de système de fichiersboot.mount
.targetUn groupe d'unités, remplace les runlevelsmulti-user.target
.pathLa surveillance d'un fichier ou d'un dossiercups.path
.deviceUn périphérique exposé par le noyauDisque, carte réseau
.sliceUn groupe de limites CPU et mémoiresystem.slice
.scopeDes processus non lancés par systemd, mais suivisSession SSH, conteneur

Les trois derniers types se rencontrent rarement en écriture manuelle, mais vous les verrez dans les sorties de commandes, et savoir ce qu'ils sont évite de se croire perdu.

Voici la distinction qui débloque la lecture des sorties systemd. Deux commandes qui se ressemblent renvoient des choses très différentes :

Fenêtre de terminal
# Ce que systemd a CHARGE en memoire, maintenant
systemctl list-units --type=service
# Ce qui est INSTALLE sur le disque
systemctl list-unit-files --type=service

Sur un système Debian 13 minimal, la première annonce 14 services chargés :

14 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.

La seconde en compte 119 :

119 unit files listed.

L'écart n'est pas une anomalie. Les 119 fichiers sont les unités livrées par les paquets, présentes sur le disque, disponibles. Les 14 unités chargées sont celles que systemd a effectivement lues et instanciées en mémoire, parce qu'elles ont été démarrées ou tirées par une dépendance. Tout le reste dort. Quand list-units ne montre pas votre service, il n'a pas disparu : il n'est simplement pas chargé, et list-unit-files le confirmera.

Un target est une unité qui ne fait rien par elle-même : elle sert de point de regroupement. On l'utilise comme un jalon dans le démarrage, l'équivalent moderne des runlevels de SysV init, ces niveaux numérotés qui définissaient l'état de la machine.

TargetAncien runlevelÉtat de la machine
rescue.target1Maintenance, mono-utilisateur, minimum vital
multi-user.target3Serveur opérationnel, réseau actif, sans interface graphique
graphical.target5Idem, plus l'environnement de bureau
reboot.target6Redémarrage

Un target agrège des unités : atteindre multi-user.target, c'est avoir démarré tout ce qui s'y rattache. C'est exactement le sens de la ligne WantedBy=multi-user.target que vous croiserez dans les fichiers de service : elle dit « accroche-moi à ce jalon ». Les targets sont eux-mêmes chaînés, graphical.target dépendant de multi-user.target, qui dépend de basic.target, qui dépend de sysinit.target.

Fenêtre de terminal
systemctl list-units --type=target --no-pager
UNIT LOAD ACTIVE SUB DESCRIPTION
basic.target loaded active active Basic System
graphical.target loaded active active Graphical Interface
local-fs.target loaded active active Local File Systems
multi-user.target loaded active active Multi-User System
network-online.target loaded active active Network is Online
sysinit.target loaded active active System Initialization
timers.target loaded active active Timer Units

La commande systemctl get-default affiche le target atteint automatiquement au démarrage. Sur un serveur, la réponse attendue est multi-user.target : lancer une pile graphique sur une machine sans écran consomme de la mémoire pour rien. Le réglage inverse ne se signale par aucune erreur, ce qui le rend difficile à repérer, et Ubuntu Server est justement livré avec graphical.target par défaut.

Le détail des manipulations (basculer à la volée avec isolate, fixer la cible du prochain démarrage avec set-default, entrer en mode rescue sans perdre son accès SSH) est traité dans Arrêter et redémarrer le système.

C'est la confusion la plus coûteuse du modèle systemd, et elle produit des pannes intermittentes, celles qui n'apparaissent qu'un boot sur cinq quand la machine est chargée. Les fichiers unités manipulent deux notions distinctes qui se ressemblent :

DirectiveCe qu'elle dit vraimentCe qu'elle ne dit pas
After= / Before=L'ordre : si les deux unités démarrent, l'une passe après l'autreElle ne demande pas le démarrage de l'autre unité
Requires=La dépendance forte : l'autre doit démarrer, et s'il échoue, je suis arrêtéElle ne dit rien de l'ordre
Wants=La dépendance souple : essaie de démarrer l'autre, continue s'il échoueElle ne dit rien de l'ordre

Le piège est mécanique. Un Requires=postgresql.service seul, sans After=, demande bien le démarrage de la base, mais en parallèle. Votre application tente alors d'ouvrir une connexion pendant que PostgreSQL initialise encore ses fichiers, et échoue. À l'inverse, un After=postgresql.service seul ordonne correctement, mais ne demande jamais le démarrage de la base : si personne d'autre ne la tire, elle ne démarre pas, et votre application se lance dans le vide.

La combinaison correcte pour une application qui ne peut pas vivre sans sa base déclare les deux :

[Unit]
Description=API de facturation
Requires=postgresql.service
After=postgresql.service

Pour une dépendance non vitale, un cache par exemple, on remplace Requires= par Wants= : le service démarre même si le cache est indisponible. La commande systemctl list-dependencies permet de vérifier l'arbre réellement construit par systemd, plutôt que celui que vous croyez avoir écrit.

Les fichiers unités sont éparpillés dans trois répertoires, et cette dispersion n'est pas un défaut : elle encode une hiérarchie de priorité qui protège vos modifications.

RépertoireQui écrit iciDurée de vie
/usr/lib/systemd/system/Les paquets de la distributionÉcrasé à chaque mise à jour
/run/systemd/system/Les unités temporaires, générées à chaudDisparaît au reboot
/etc/systemd/system/Vous, l'administrateurPersistant, jamais écrasé

La règle de priorité est /etc/ devant /run/ devant /usr/lib/. Une unité placée dans /etc/systemd/system/ masque celle du paquet portant le même nom. C'est ce qui rend la règle suivante non négociable : ne modifiez jamais un fichier dans /usr/lib/systemd/system/. Votre modification y survivra jusqu'à la prochaine mise à jour du paquet, qui l'effacera sans prévenir, et le service reprendra son comportement d'origine à un moment que vous n'aurez pas choisi.

La bonne méthode s'appelle le drop-in : un fragment de configuration placé dans un sous-répertoire <unité>.service.d/, qui ne contient que ce que vous changez. systemd empile le fichier du paquet et vos fragments. La commande systemctl edit crée ce fragment pour vous, et systemctl cat affiche le résultat final, fichier d'origine et drop-ins fusionnés. Pour savoir quel fichier est réellement utilisé, systemctl show <unité> -p FragmentPath donne le chemin exact.

systemd ne relit pas les fichiers unités à chaque commande. Au démarrage, il construit en mémoire un graphe compilé de toutes les unités, et c'est cette version en mémoire qu'il applique. Modifier un fichier sur le disque ne change rien tant que vous ne le lui avez pas dit.

La démonstration est sans appel. Prenons un service dont le fichier contient sleep 30, et remplaçons cette valeur par sleep 45 sur le disque. Sans rien d'autre, un restart :

Fenêtre de terminal
sudo systemctl restart horloge
Warning: The unit file, source configuration file or drop-ins of horloge.service
changed on disk. Run 'systemctl daemon-reload' to reload units.

systemd vous prévient, mais il relance quand même l'ancienne version. La preuve, en interrogeant la commande qu'il vient réellement d'exécuter :

Fenêtre de terminal
systemctl show horloge -p ExecStart --value
{ path=/bin/sh ; argv[]=/bin/sh -c while true; do date; sleep 30; done ; ... }

Le disque dit 45, systemd exécute 30. Après un daemon-reload, la même interrogation renvoie enfin la bonne valeur :

Fenêtre de terminal
sudo systemctl daemon-reload
sudo systemctl restart horloge
systemctl show horloge -p ExecStart --value
{ path=/bin/sh ; argv[]=/bin/sh -c while true; do date; sleep 45; done ; ... }

Ne confondez pas les deux « reload ». systemctl reload nginx demande à nginx de relire sa configuration (/etc/nginx/nginx.conf). systemctl daemon-reload demande à systemd de relire ses fichiers unités. Les deux mots se ressemblent, les deux commandes n'ont aucun rapport. La règle tient en une ligne : après toute création ou modification d'un fichier unité, daemon-reload est obligatoire.

systemd n'est pas un binaire isolé mais une suite d'outils qui partagent le même modèle d'unités. Trois commandes couvrent l'essentiel du quotidien, et savoir laquelle sert à quoi évite de chercher au mauvais endroit.

CommandeCe qu'elle faitOù l'approfondir
systemctlPiloter les unités : état, démarrage, activation au bootDémarrer et diagnostiquer un service
journalctlLire le journal centralisé collecté par systemdMaîtriser les journaux avec journalctl
systemd-analyzeMesurer le boot, vérifier une unité, auditer sa sécuritéDurcir un service systemd

Chaque service lancé par systemd est placé dans son propre cgroup (control group), un mécanisme du noyau Linux qui regroupe des processus pour les compter et les limiter ensemble. C'est ce qui explique le champ CGroup que vous voyez dans un systemctl status :

CGroup: /system.slice/nginx.service
├─81 "nginx: master process /usr/sbin/nginx"
├─82 "nginx: worker process"
└─83 "nginx: worker process"

Ce détail a trois conséquences très concrètes. systemd suit tous les processus enfants, y compris ceux qui se sont détachés, là où SysV init perdait leur trace dès que le fichier PID devenait faux. Un systemctl stop arrête réellement tout le groupe, sans processus orphelin qui continue de tenir un port. Enfin, les limites de ressources (mémoire maximale, quota CPU) s'appliquent au groupe entier. Le mécanisme lui-même est détaillé dans la page Comprendre les cgroups Linux.

Quatre paires de termes se ressemblent et provoquent l'essentiel des incompréhensions. Les fixer maintenant vous évitera de perdre du temps sur les pages pratiques.

On confondAlors que
systemd et systemctlsystemd est le processus PID 1 ; systemctl est la commande qui lui parle
unité et serviceLe service est un type d'unité parmi neuf, pas un synonyme
start et enablestart démarre maintenant ; enable configure le prochain boot. Aucune des deux ne fait ce que fait l'autre
reload et daemon-reloadreload recharge la config du service ; daemon-reload recharge les fichiers unités

La paire start / enable mérite une insistance particulière parce qu'elle produit le grand classique du serveur qui marche parfaitement jusqu'au premier redémarrage, puis ne remonte pas : le service avait été démarré, jamais activé. Le mécanisme complet, avec les liens symboliques créés par enable et le rôle des presets, est traité dans Activer un service au démarrage.

Le modèle mental est posé. Les gestes, eux, sont répartis sur des pages dédiées, chacune correspondant à un besoin précis.

systemd est le PID 1 : le premier processus lancé par le noyau, parent de tous les autres, jamais arrêté tant que la machine tourne.

systemd n'est pas systemctl : le premier est le processus qui gère le système, le second la commande cliente qui lui transmet vos ordres.

Tout est unité : service, timer, socket, montage, target, slice. L'extension du fichier détermine le type et le comportement.

Chargé n'est pas installé : list-units montre ce qui est en mémoire, list-unit-files ce qui existe sur le disque. L'écart est normal.

L'ordre n'est pas la dépendance : After= ordonne, Requires= exige. Il faut souvent déclarer les deux, sous peine de pannes intermittentes.

/etc/ gagne toujours : on ne modifie jamais /usr/lib/systemd/system/, on passe par un drop-in.

daemon-reload est obligatoire : sans lui, systemd continue d'appliquer l'ancienne version du fichier, même après un restart.

Les questions ci-dessous sont celles qui reviennent le plus souvent chez les administrateurs qui découvrent systemd : sa définition, son rapport à SysV init, la distinction avec systemctl, et le rôle exact de daemon-reload.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn