Introduction
systemd est le système d'initialisation et le gestionnaire de services par défaut sur la plupart des distributions Linux modernes. Il initialise le système, gère les services, assure la journalisation et applique le contrôle des ressources via les cgroups. Pour les développeurs, les ingénieurs DevOps et les équipes techniques, une connaissance pratique de l'architecture de systemd est essentielle pour diagnostiquer les problèmes, ajuster le comportement des services et garantir un fonctionnement fiable.
Cet article explique l'architecture de systemd avec des exemples pratiques. Vous apprendrez à identifier la version de systemd et la topologie de déploiement, à inspecter l'état des unités, à configurer les services en toute sécurité, à diagnostiquer les pannes et à planifier la récupération. Chaque section comprend des commandes, les résultats attendus, les signaux d'échec et les étapes de récupération. L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés pour les données sensibles, vérifier le résultat et documenter les procédures de récupération.
Inventaire de la version et de l'environnement
Avant d'interagir avec systemd, établissez la version et l'environnement. Connaître la version est important car les fonctionnalités et les valeurs par défaut de systemd changent entre les versions. Par exemple, systemd 240 a introduit RestartKillSignal=, et la version 249 a changé la valeur par défaut de Restart= à on-failure pour les services avec Restart=always et un délai d'attente.
Rassembler les informations de version
Exécutez les commandes suivantes sur le système cible :
systemctl --version
uname -r
cat /etc/os-release
Exemple de sortie :
systemd 249 (249.11-0ubuntu3.6)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT +QRENCODE +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified
Linux 5.15.0-60-generic
NAME="Ubuntu"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
Cette sortie indique :
- la version de systemd 249 avec des fonctionnalités spécifiques à la compilation ;
- la version du noyau (5.15.0) et la distribution (Ubuntu 22.04) ;
- la hiérarchie des cgroups est unifiée (cgroup v2), ce qui affecte la configuration du contrôle des ressources.
Vérifiez que la version des cgroups est v2, car certains conteneurs ou outils plus anciens peuvent supposer la v1. Pour confirmer :
stat -fc %T /sys/fs/cgroup/
La sortie doit être cgroup2fs. Si c'est tmpfs, le système utilise des cgroups hérités ou hybrides.
Topologie de déploiement
Déterminez comment systemd est utilisé dans votre environnement. S'agit-il d'un hôte physique, d'une machine virtuelle ou d'un conteneur ? Dans les conteneurs, systemd peut ne pas être le PID 1, et certaines fonctionnalités sont indisponibles. Vérifiez :
ps -p 1 -o comm=
La sortie attendue est systemd sur un hôte. Si c'est bash ou sh, vous êtes dans un conteneur sans système d'initialisation complet.
Pour l'inspection des services, identifiez le nom du service et son fichier d'unité :
systemctl cat sshd.service
Cela affiche le fichier d'unité et les éventuels overrides de type drop-in. Notez les sections [Unit], [Service] et [Install].
Prérequis pour une exploitation sûre
- Vous avez un accès shell avec la permission d'exécuter
systemctl(généralement sudo ou root). - Le système n'est pas en mode d'urgence ou de secours, sauf si c'est la cible.
- Vous comprenez que la modification des fichiers d'unité affecte le comportement du service et peut nécessiter un rechargement ou un redémarrage.
Observation en lecture seule
Avant d'apporter des modifications, capturez l'état actuel avec des horodatages :
date --utc
systemctl is-system-running
systemctl list-units --type=service --state=running
La commande is-system-running renvoie running, degraded, maintenance, stopping ou initializing. Un état degraded indique au moins une unité en échec. Enregistrez cette sortie pour une comparaison ultérieure.
Chemin de configuration sûr
Les modifications de configuration de systemd doivent être minimes, testées et réversibles. Cette section explique comment ajouter un service personnalisé, modifier une unité existante via un drop-in et revenir en arrière en toute sécurité.
Exemple : Créer un service simple
Supposons que vous deviez exécuter un script au démarrage en tant qu'utilisateur spécifique. Tout d'abord, écrivez le script et rendez-le exécutable :
sudo mkdir -p /usr/local/lib/myservice
sudo tee /usr/local/lib/myservice/myscript.sh > /dev/null <<'EOF'
#!/bin/bash
while true; do
echo "Service running at $(date)" >> /var/log/myservice.log
sleep 60
done
EOF
sudo chmod +x /usr/local/lib/myservice/myscript.sh
Créez un fichier d'unité à /etc/systemd/system/myservice.service :
[Unit]
Description=My Custom Service
After=network.target
[Service]
Type=simple
User=myserviceuser
ExecStart=/usr/local/lib/myservice/myscript.sh
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Directives clés expliquées
Type=simple: systemd considère le service comme démarré immédiatement après le fork du processus. Convient aux processus de premier plan à longue durée de vie.User=myserviceuser: exécute le service en tant qu'utilisateur non root pour la sécurité. Créez d'abord l'utilisateur :sudo useradd -r -s /usr/sbin/nologin myserviceuser.Restart=on-failure: redémarre uniquement en cas de code de sortie non propre ou de signal.RestartSec=5s: attend 5 secondes entre les redémarrages.
Appliquer la configuration en toute sécurité
Après avoir créé le fichier d'unité, rechargez le gestionnaire systemd pour prendre en compte les modifications, puis démarrez et activez le service :
sudo systemctl daemon-reload
sudo systemctl start myservice.service
sudo systemctl status myservice.service
Sortie attendue (partielle) :
● myservice.service - My Custom Service
Loaded: loaded (/etc/systemd/system/myservice.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2023-01-02 12:34:56 UTC; 5s ago
Main PID: 1234 (myscript.sh)
Tasks: 1 (limit: 2356)
Memory: 1.0M
CPU: 20ms
CGroup: /system.slice/myservice.service
└─1234 /bin/bash /usr/local/lib/myservice/myscript.sh
Vérifiez que le service est en cours d'exécution et que les journaux apparaissent :
sudo tail /var/log/myservice.log
Pour l'activer au démarrage :
sudo systemctl enable myservice.service
Utiliser des overrides de type drop-in
Au lieu de modifier le fichier d'unité d'origine, utilisez un drop-in pour remplacer des paramètres spécifiques. Cela préserve l'original et facilite le retour en arrière. Par exemple, pour modifier le comportement de redémarrage sans modifier le fichier d'unité :
sudo mkdir -p /etc/systemd/system/myservice.service.d
sudo tee /etc/systemd/system/myservice.service.d/override.conf > /dev/null <<'EOF'
[Service]
Restart=always
RestartSec=10s
EOF
sudo systemctl daemon-reload
sudo systemctl restart myservice.service
Vérifiez que l'override est appliqué :
systemctl cat myservice.service | grep -A2 'override'
La sortie affiche à la fois les sections d'origine et d'override.
Rayon d'impact et récupération
Modifier Restart peut augmenter le bruit dans les journaux si le service échoue de manière répétée. Avant d'appliquer, considérez l'impact. Si la modification cause des problèmes, supprimez le drop-in et rechargez :
sudo rm /etc/systemd/system/myservice.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart myservice.service
Testez toujours les modifications de configuration dans un environnement de préproduction d'abord.
Vérification et diagnostics
Après les modifications de configuration, vérifiez que le service se comporte comme prévu et diagnostiquez tout problème. systemd fournit plusieurs commandes pour l'introspection.
Vérifier l'état du service
systemctl status donne un aperçu. Pour un service en échec, il affiche les lignes de journal pertinentes et les codes de sortie.
systemctl status myservice.service
Si le service échoue, la sortie inclut :
● myservice.service - My Custom Service
Loaded: loaded (/etc/systemd/system/myservice.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Mon 2023-01-02 12:40:00 UTC; 10s ago
Process: 1235 ExecStart=/usr/local/lib/myservice/myscript.sh (code=exited, status=1/FAILURE)
Main PID: 1235 (code=exited, status=1/FAILURE)
Result: exit-code et status=1/FAILURE indiquent que le script s'est terminé avec le code 1. Examinez la logique du script ou les permissions.
Consulter les journaux
Utilisez journalctl pour des journaux détaillés :
journalctl -u myservice.service -e
-e saute à la fin. Pour suivre les journaux en temps réel :
journalctl -u myservice.service -f
Filtrez par heure :
journalctl -u myservice.service --since "2023-01-02 12:30:00" --until "2023-01-02 12:45:00"
Inspecter les dépendances des unités
Comprenez l'arbre des dépendances du service :
systemctl list-dependencies myservice.service
Cela montre ce que le service requiert et ce qui le requiert. Si une dépendance échoue, le service peut ne pas démarrer.
Vérifier les limites de ressources
Utilisez les commandes liées aux cgroups pour vérifier l'utilisation des ressources :
systemctl show myservice.service | grep -E 'MemoryCurrent|CPUUsageNSec|TasksCurrent'
Exemple de sortie :
MemoryCurrent=1024000
CPUUsageNSec=25000000
TasksCurrent=1
Ces valeurs aident à identifier les fuites de mémoire ou une utilisation élevée du processeur.
Tester la validité de la configuration
Avant de redémarrer, vérifiez la syntaxe du fichier d'unité :
systemd-analyze verify myservice.service
Aucune sortie signifie aucune erreur. S'il y a des avertissements ou des erreurs, ils sont affichés et doivent être traités.
Modes de défaillance et récupération
Les services systemd peuvent échouer pour diverses raisons : chemin ExecStart incorrect, dépendances manquantes, problèmes de permission ou épuisement des ressources. Cette section couvre les schémas de défaillance courants et les étapes de récupération.
Échec : chemin ExecStart non exécutable
Si le chemin de l'exécutable est incorrect ou manque de permission d'exécution, le service échoue immédiatement.
Symptôme : status=203/EXEC dans systemctl status.
Diagnostic :
systemctl status myservice.service | grep ExecStart
ls -l /usr/local/lib/myservice/myscript.sh
Récupération : Corrigez le chemin ou la permission, puis rechargez et redémarrez :
sudo chmod +x /usr/local/lib/myservice/myscript.sh
sudo systemctl daemon-reload
sudo systemctl restart myservice.service
Échec : port déjà utilisé
Si un service se lie à un port spécifique et que le port est occupé, il se termine avec une erreur comme bind: address already in use.
Diagnostic :
journalctl -u myservice.service -e
ss -tulpn | grep :8080
Récupération : Arrêtez le processus en conflit ou modifiez le port dans la configuration du service.
Échec : dépendance non satisfaite
Si un service dépend d'une autre unité inactive, il peut ne pas démarrer.
Symptôme : Condition: start condition failed ou dépendance non satisfaite dans les journaux.
Diagnostic :
systemctl list-dependencies myservice.service
systemctl status network.target
Récupération : Démarrez d'abord la dépendance ou ajustez les directives After= et Requires= de manière appropriée.
Récupération après un fichier d'unité cassé
Si un fichier d'unité contient une erreur de syntaxe, daemon-reload échoue et le service peut disparaître.
Symptôme : systemctl signale Failed to parse ou Invalid argument.
Récupération :
journalctl -xe | grep -i 'myservice'
Modifiez le fichier d'unité, corrigez la syntaxe et exécutez à nouveau systemd-analyze verify.
Récupération en mode d'urgence
Si le système démarre en mode d'urgence, utilisez un shell de secours pour inspecter. Les causes courantes incluent des unités de montage échouées ou des problèmes de fsck.
systemctl list-units --failed
journalctl -b -p err
Pour sortir du mode d'urgence après correction, exécutez systemctl default ou redémarrez.
Pièges courants et comment les éviter
De nombreux problèmes de systemd proviennent de malentendus ou d'oublis. Voici les pièges fréquents, pourquoi ils surviennent et comment les éviter ou s'en remettre.
Modifier les fichiers d'unité sans daemon-reload
- Pourquoi cela arrive : Les utilisateurs modifient un fichier d'unité et s'attendent à ce que les changements prennent effet immédiatement.
- Conséquence : Le gestionnaire systemd en cours utilise toujours l'ancienne configuration.
- Comment l'éviter : Toujours exécuter
sudo systemctl daemon-reloadaprès avoir modifié les fichiers d'unité ou les drop-ins. - Récupération : Exécutez la commande de rechargement et redémarrez le service.
Utiliser Restart=always sans limite de taux
- Pourquoi cela arrive : Un service qui plante continuellement est redémarré sans fin, remplissant les journaux et consommant du CPU.
- Conséquence : La charge du système augmente et les journaux deviennent ingérables.
- Comment l'éviter : Utilisez
Restart=on-failureet définissezRestartSec=de manière appropriée. ConsidérezStartLimitBurst=etStartLimitIntervalSec=pour limiter les tentatives de redémarrage. - Récupération : Arrêtez le service, corrigez la cause racine, puis redémarrez-le.
Ignorer les variables d'environnement dans les fichiers d'unité
- Pourquoi cela arrive : Les scripts supposent que certaines variables d'environnement sont définies, mais systemd ne source pas
/etc/profileni les profils shell des utilisateurs. - Conséquence : Le service échoue ou se comporte de manière inattendue.
- Comment l'éviter : Utilisez les directives
Environment=ouEnvironmentFile=dans le fichier d'unité. - Récupération : Ajoutez les variables manquantes et rechargez.
Ne pas spécifier un type de processus approprié
- Pourquoi cela arrive : Le type par défaut
Type=simplepeut ne pas convenir aux démons qui se mettent en arrière-plan via fork. - Conséquence : systemd peut tuer le processus ou signaler un état incorrect.
- Comment l'éviter : Choisissez le bon
Type=(par exemple,forking,notify,oneshot) en fonction du comportement de l'exécutable. - Récupération : Ajustez
Type=et redémarrez.
Exécuter des services en tant que root inutilement
- Pourquoi cela arrive : La commodité conduit à utiliser l'utilisateur root par défaut.
- Conséquence : Risque de sécurité si le service est compromis.
- Comment l'éviter : Créez un utilisateur système dédié et définissez
User=etGroup=dans le fichier d'unité. - Récupération : Changez la propriété des fichiers nécessaires et mettez à jour le fichier d'unité.
Liste de vérification opérationnelle
Utilisez cette liste avant et après avoir apporté des modifications à systemd pour garantir la sécurité et l'observabilité.
| Étape | Action | Commande | Résultat attendu | Responsable | Fréquence |
|---|---|---|---|---|---|
| 1 | Enregistrer la version actuelle de systemd | systemctl --version | La chaîne de version correspond à la plage prise en charge | Ingénieur DevOps (par exemple, Priya Shah) | Avant chaque modification |
| 2 | Vérifier l'état global du système | systemctl is-system-running | running ou degraded (documenté) | Ingénieur DevOps | Avant chaque modification |
| 3 | Capturer la liste des services en cours | systemctl list-units --type=service --state=running > /tmp/services_before.txt | Fichier créé avec la liste | Ingénieur DevOps | Avant chaque modification |
| 4 | Appliquer une modification ciblée | (modifier le fichier d'unité ou le drop-in) | Modification appliquée à un seul service | Propriétaire du service (par exemple, développeur Alex Chen) | Lors du changement d'un service |
| 5 | Recharger la configuration systemd | sudo systemctl daemon-reload | Aucune sortie d'erreur | Ingénieur DevOps | Après modification des fichiers d'unité |
| 6 | Vérifier la syntaxe du fichier d'unité | systemd-analyze verify <unit> | Aucune erreur ni avertissement | Propriétaire du service | Après la modification |
| 7 | Redémarrer/démarrer le service | sudo systemctl restart <unit> | Active: active (running) | Propriétaire du service | Après la modification |
| 8 | Vérifier l'état et les journaux du service | systemctl status <unit> et journalctl -u <unit> -n 50 | Pas d'état failed ; les journaux montrent un fonctionnement normal | Propriétaire du service | Après la modification |
| 9 | Comparer la liste des unités avant/après | diff /tmp/services_before.txt <(systemctl list-units --type=service --state=running) | Seulement les changements prévus | Ingénieur DevOps | Après la modification |
| 10 | Documenter le changement et la récupération | Mettre à jour le runbook avec les étapes de récupération | Récupération testée en préproduction | Propriétaire du service | Audit mensuel |
Note sur la responsabilité : Chaque élément a un seul responsable, généralement le propriétaire du service ou l'ingénieur DevOps de garde. La fréquence de révision est définie par élément mais doit être réexaminée mensuellement ou après tout incident.
Conclusion
L'architecture de systemd, bien que complexe, devient gérable avec une approche systématique de l'observation, de la configuration et de la récupération. En comprenant les composants essentiels (fichiers d'unité, cgroups, journal et gestionnaire) et en utilisant les bonnes commandes, vous pouvez maintenir des services stables et sécurisés.
Commencez par appliquer une vérification à faible risque dans votre environnement :
- Enregistrez la version actuelle de systemd et l'état du système.
- Choisissez un service que vous possédez et inspectez son fichier d'unité avec
systemctl cat. - Vérifiez la syntaxe avec
systemd-analyze verify. - Vérifiez les dépendances et les journaux pour comprendre son comportement.
- Si vous devez modifier un paramètre, utilisez un override de type drop-in et suivez le chemin de configuration sûr.
En rendant les échecs visibles, en protégeant les valeurs sensibles, en limitant les modifications à la ressource prévue et en définissant à l'avance la vérification de la récupération, vous gagnez en confiance opérationnelle. La prochaine fois qu'un service se comporte mal, vous aurez les outils pour diagnostiquer et corriger rapidement.