Dépannage des services systemd défaillants : Un guide pratique pour les administrateurs système
Les services systemd sont le pilier des systèmes Linux modernes, mais ils peuvent échouer. Ce guide pratique permet aux administrateurs système de diagnostiquer et résoudre systématiquement les défaillances courantes des services systemd. Apprenez à utiliser efficacement `journalctl` pour l'analyse des logs, diagnostiquer les problèmes de dépendances, interpréter les codes de sortie et appliquer des correctifs spécifiques pour les serveurs web, bases de données, etc., afin de restaurer rapidement la fonctionnalité des services.
Dépannage des services systemd défaillants : Un guide pratique pour les administrateurs système
Les services systemd défaillants sont généralement moins mystérieux qu'ils n'y paraissent. Les preuves utiles sont déjà sur la machine : la définition de l'unité, la commande exacte que systemd a tenté d'exécuter, le statut de sortie et les lignes du journal autour de l'échec. L'astuce est de les lire dans le bon ordre au lieu de redémarrer le service dix fois en espérant que le message change.
Je commence généralement par trois questions : systemd a-t-il trouvé l'unité, le processus a-t-il démarré, et l'application elle-même a-t-elle rejeté sa configuration ou son environnement ? Les commandes ci-dessous maintiennent cette investigation ancrée.
Comprendre les défaillances des services systemd
Lorsqu'un service systemd ne parvient pas à démarrer ou plante de manière inattendue, cela est souvent dû à diverses raisons. Celles-ci peuvent aller de simples erreurs de configuration, des dépendances manquantes, des limitations de ressources, à des bugs dans le service lui-même. Systemd fournit des mécanismes robustes pour vous aider à identifier la cause exacte de ces défaillances.
Causes courantes des défaillances de services :
- Erreurs de configuration : Paramètres incorrects dans le fichier d'unité
.servicedu service ou dans les fichiers de configuration associés. - Dépendances manquantes : Le service dépend d'autres ressources système (comme le réseau, d'autres services, des systèmes de fichiers spécifiques) qui ne sont pas disponibles ou n'ont pas encore démarré.
- Épuisement des ressources : Le service nécessite plus de mémoire, de CPU ou d'E/S disque que le système ne peut en fournir.
- Problèmes de permissions : Le processus du service ne dispose pas des permissions nécessaires pour accéder aux fichiers, répertoires ou ports réseau requis.
- Bugs dans le service : L'application elle-même contient un bug qui la fait planter lors du démarrage ou de l'exécution.
- Données corrompues : Les fichiers de données essentiels utilisés par le service sont corrompus.
- Problèmes réseau : Problèmes avec les interfaces réseau, le DNS ou les règles de pare-feu empêchant le service de se lier aux ports ou de communiquer.
Étape 1 : Inspection de l'état du service
La première étape du dépannage d'un service défaillant consiste à vérifier son état actuel. La commande systemctl de systemd est votre outil principal pour cela.
Utilisation de systemctl status
La commande systemctl status <nom_du_service>.service fournit un aperçu concis de l'état actuel du service, des entrées de journal récentes et des informations sur le processus.
sudo systemctl status nginx.service
Exemple de sortie (Service défaillant) :
● nginx.service - Serveur web haute performance et proxy inverse
Chargé : chargé (/lib/systemd/system/nginx.service ; activé ; préréglage fournisseur : activé)
Actif : échoué (résultat=code-sortie) depuis mar. 2023-10-27 10:30:00 UTC ; il y a 1 min
Docs : man:nginx(8)
Processus : 1234 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=1/FAILURE)
PID principal : 1234 (code=exited, status=1/FAILURE)
Oct 27 10:30:00 votre-serveur systemd[1] : Démarrage du serveur web haute performance et proxy inverse...
Oct 27 10:30:00 votre-serveur nginx[1234] : nginx: [emerg] bind() to port 80 failed (98: Address already in use)
Oct 27 10:30:00 votre-serveur systemd[1] : nginx.service : Le processus principal est sorti, code=exited, status=1/FAILURE
Oct 27 10:30:00 votre-serveur systemd[1] : Échec du démarrage du serveur web haute performance et proxy inverse.
Informations clés à rechercher dans la sortie de systemctl status :
Active:: Cette ligne indique l'état actuel.failedest l'état qui nous intéresse. Il peut également afficherfailed (result=exit-code)oufailed (result=oom-kill). Leresultfournit souvent un indice.Process:: Détails sur le processus que systemd a tenté d'exécuter. S'il affichecode=exited, status=..., c'est critique.- Entrées de journal : Les lignes de journal les plus récentes contiennent souvent le message d'erreur direct du service.
Étape 2 : Analyse des logs avec journalctl
La commande journalctl est l'outil puissant de systemd pour interroger et afficher les logs du journal systemd. Elle est essentielle pour obtenir des informations détaillées sur la raison pour laquelle un service a échoué.
Utilisation de base de journalctl pour les services
Pour afficher les logs d'un service spécifique, utilisez l'option -u :
sudo journalctl -u <nom_du_service>.service
Pour suivre les logs en temps réel :
sudo journalctl -f -u <nom_du_service>.service
Pour afficher les logs du dernier démarrage (utile pour les services qui ont échoué au démarrage) :
sudo journalctl -b -u <nom_du_service>.service
Pour voir les logs depuis une heure spécifique :
sudo journalctl --since "2023-10-27 10:00:00" -u <nom_du_service>.service
Interprétation de la sortie de journalctl
Recherchez les messages d'erreur, les traces de pile ou les codes d'erreur spécifiques rapportés par l'application ou systemd lui-même. L'exemple de sortie de systemctl status montrait déjà une erreur clé : bind() to port 80 failed (98: Address already in use). Cela indique clairement qu'un autre processus utilise déjà le port 80, empêchant Nginx de démarrer.
Astuce : Si le service est très verbeux, vous pouvez limiter la sortie :
sudo journalctl -n 50 -u <nom_du_service>.service # Afficher les 50 dernières lignes
Étape 3 : Vérification des dépendances et exigences du service
Les services systemd dépendent souvent d'autres services ou ressources système pour être disponibles. Si une dépendance n'est pas satisfaite, le service ne démarrera pas.
Affichage des dépendances
Vous pouvez inspecter les dépendances d'un service en utilisant systemctl cat et en recherchant les directives comme Requires=, Wants=, After=, Before= et PartOf=.
systemctl cat <nom_du_service>.service
Par exemple, un service qui se lie à une adresse spécifique peut nécessiter un ordre après la configuration du réseau. After=network-online.target ne contrôle que l'ordre ; il ne tire pas cette cible dans la transaction par lui-même. Si le service en a vraiment besoin, on voit souvent les deux :
Wants=network-online.target
After=network-online.target
Soyez prudent avec Requires=. Cela crée une relation plus forte et peut arrêter votre service lorsque l'unité requise s'arrête. De nombreux services applicatifs n'ont besoin que de Wants= plus After=.
Vérification des dépendances manquantes
Bien que systemctl status indique souvent les problèmes de dépendances, vérifier explicitement si les services requis sont actifs peut être utile.
systemctl is-active <nom_service_dependance>.service
Si un service requis est masqué ou arrêté, cela peut empêcher votre service cible de démarrer.
systemctl list-dependencies <nom_du_service>.service
Cette commande affiche l'arbre de dépendances complet.
Étape 4 : Comprendre les codes de sortie
Lorsqu'un service échoue, il se termine avec un code de sortie spécifique. Ce code fournit des informations précieuses sur la nature de l'échec.
- Code de sortie 0 : Succès.
- Code de sortie 1 : Échec générique pour de nombreux programmes. La signification spécifique dépend de l'application.
- Code de sortie 127 : Commande introuvable (souvent dû à un chemin
ExecStartincorrect ou à un exécutable manquant). - Code de sortie 137 : Tué par
SIGKILL. Cela est souvent, mais pas toujours, lié à la pression mémoire. - Code de sortie 139 : Tué par
SIGSEGV(Erreur de segmentation).
À partir de la sortie de systemctl status, nous avons vu status=1/FAILURE. C'est un échec générique, et les messages de journal précédents sont essentiels pour comprendre pourquoi il a échoué avec le statut 1.
Identification des OOM kills
Si systemctl status affiche failed (result=oom-kill), cela signifie que le tueur Out-Of-Memory (OOM) de Linux a terminé le processus du service car le système manquait cruellement de mémoire.
Pour le confirmer, vous pouvez souvent trouver des messages associés dans journalctl ou dmesg :
dmesg | grep -i oom
Dépannage des erreurs OOM
- Augmenter la RAM du système : Si possible.
- Réduire l'utilisation de la mémoire : Optimiser le service ou d'autres processus en cours d'exécution.
- Configurer le swap : Assurer un espace de swap adéquat.
- Vérifier les limites mémoire du service : Un paramètre
MemoryMax=peut provoquer un OOM spécifique au service même si l'hôte a encore de la mémoire libre. - Examiner les déploiements récents : Les échecs mémoire suivent souvent un changement de configuration, de trafic ou de version.
Étape 5 : Vérifier le fichier d'unité que systemd utilise réellement
Ne supposez pas que le fichier dans votre éditeur est l'unité complète. Les paquets, les drop-ins et les surcharges peuvent se combiner dans la définition finale :
systemctl cat <nom_du_service>.service
systemctl show <nom_du_service>.service -p FragmentPath -p DropInPaths
Cela permet de détecter un problème courant : quelqu'un a édité /usr/lib/systemd/system/app.service, tandis qu'une surcharge dans /etc/systemd/system/app.service.d/override.conf modifie toujours Environment= ou ExecStart=.
Après avoir modifié des fichiers d'unité ou des drop-ins, rechargez systemd :
sudo systemctl daemon-reload
Si vous oubliez cette étape, systemctl restart peut continuer à utiliser l'ancienne définition d'unité.
Étape 6 : Problèmes et correctifs courants spécifiques aux services
Bien que les étapes ci-dessus soient générales, des services spécifiques ont des modes de défaillance courants.
Serveurs web (Nginx, Apache)
- Port déjà utilisé : Comme dans l'exemple, un autre processus peut écouter sur le port 80 ou 443. Utilisez
sudo ss -tulnp | grep :80pour trouver le processus incriminé. - Erreurs de syntaxe de configuration : Exécutez le test de configuration du serveur web (par exemple,
sudo nginx -tousudo apachectl configtest). - Certificats SSL manquants : Assurez-vous que les fichiers de certificat sont présents et lisibles.
Bases de données (MySQL, PostgreSQL)
- Permissions du répertoire de données : Assurez-vous que l'utilisateur de la base de données a un accès en lecture/écriture correct à son répertoire de données.
- Fichiers de données corrompus : Peut nécessiter une restauration à partir d'une sauvegarde ou l'utilisation d'outils de récupération spécifiques à la base de données.
- Espace disque plein : Les bases de données peuvent consommer un espace disque important.
Services réseau
- Adresses IP ou noms d'hôte incorrects : Vérifiez la configuration réseau.
- Règles de pare-feu : Assurez-vous que les ports nécessaires sont ouverts.
- Problèmes de résolution DNS : Vérifiez
/etc/resolv.confet la connectivité réseau.
Étape 7 : Techniques avancées de dépannage
Réactivation et redémarrage du service
Après avoir effectué des modifications, rechargez les unités si nécessaire, puis redémarrez le service. Vous n'avez pas besoin d'exécuter enable à chaque fois, sauf si vous modifiez le comportement au démarrage.
sudo systemctl daemon-reload # Recharger la configuration du gestionnaire systemd
sudo systemctl restart <nom_du_service>.service
Utilisation de systemctl --failed
Cette commande liste toutes les unités qui sont actuellement dans un état d'échec.
systemctl --failed
Vérification des limites de ressources (ulimit)
Certains services peuvent échouer s'ils atteignent les limites de ressources au niveau du système d'exploitation. Vérifiez les limites avec ulimit -a en tant qu'utilisateur sous lequel le service s'exécute, ou vérifiez les directives de contrôle des ressources de systemd dans le fichier d'unité.
Pour les services gérés par systemd, les propriétés de l'unité sont souvent plus pertinentes que le ulimit d'un shell interactif :
systemctl show <nom_du_service>.service -p LimitNOFILE -p User -p Group -p MemoryMax -p TasksMax
Si une application indique too many open files, comparez LimitNOFILE avec le nombre de connexions et l'utilisation de fichiers de l'application. Si un service ne peut pas créer de threads ou de processus enfants, regardez TasksMax.
Indicateurs de débogage
De nombreuses applications ont des modes de débogage ou une journalisation verbeuse qui peuvent être activés via des arguments de ligne de commande dans la ligne ExecStart du fichier .service. Consultez la documentation de l'application.
Un exemple rapide : Le service fonctionne manuellement, échoue au démarrage
C'est l'une des plaintes les plus courantes concernant systemd. Un développeur exécute la commande à la main et elle fonctionne. La même commande échoue en tant que service. La différence habituelle est l'environnement.
Vérifiez l'utilisateur du service et le répertoire de travail :
systemctl show myapp.service -p User -p Group -p WorkingDirectory
systemctl cat myapp.service
Ensuite, recherchez les hypothèses dans l'application : chemins relatifs, fichiers dans un répertoire personnel, variables d'environnement de .bashrc, ou informations d'identification chargées par un shell interactif. systemd ne lit pas vos fichiers de démarrage de shell pour un service. Si l'application a besoin de APP_ENV=production ou DATABASE_URL=..., placez cette configuration dans l'unité avec Environment=, un EnvironmentFile=, ou votre chemin normal de gestion des secrets.
Les échecs uniquement au démarrage peuvent également être des problèmes d'ordre. Un service peut démarrer avant que le DNS, l'adresse réseau ou un système de fichiers monté ne soit prêt. Ne corrigez pas cela avec un sleep aveugle dans l'application. Exprimez la dépendance dans l'unité :
Wants=network-online.target
After=network-online.target
RequiresMountsFor=/srv/myapp
RequiresMountsFor= est utile lorsque le service a besoin d'un chemin spécifique, surtout si ce chemin provient d'un disque séparé ou d'un montage réseau. C'est plus clair que d'espérer qu'une cible large se termine en premier.
Réinitialisation de l'état d'échec
Après qu'un service a échoué, systemd se souvient de l'état d'échec jusqu'à ce qu'il soit réinitialisé ou que l'unité réussisse. C'est utile pour la visibilité, mais cela peut perturber les vérifications d'état après avoir déjà corrigé le problème :
sudo systemctl reset-failed myapp.service
sudo systemctl restart myapp.service
systemctl status myapp.service
Utilisez reset-failed après avoir capturé les preuves dont vous avez besoin. Pendant un incident, l'état d'échec et les horodatages du journal sont des indices utiles.
Une autre petite habitude aide après des échecs bruyants : vérifiez si l'unité boucle en redémarrage avant de modifier quoi que ce soit.
systemctl show myapp.service -p NRestarts -p RestartUSec
Si le nombre de redémarrages augmente rapidement, arrêtez l'unité pendant que vous enquêtez. Cela protège les dépendances des connexions répétées défectueuses et maintient le journal lisible.
Le modèle fiable est : lisez status, lisez le journal, inspectez l'unité effective avec systemctl cat, vérifiez les dépendances et les chemins, puis ne redémarrez qu'après avoir su ce qui a changé. Cela rend le dépannage systemd ennuyeux, ce qui est exactement ce que vous voulez lors d'une panne.