Dépannage des pannes de service Systemd : un guide étape par étape
Systemd est devenu le gestionnaire de systèmes et de services de facto pour la plupart des distributions Linux modernes, jouant un rôle essentiel dans la gestion des services, des démons et des processus. Bien qu'ils soient puissants et efficaces, les services gérés par systemd peuvent parfois ne pas démarrer, entraînant des temps d'arrêt d'application ou une instabilité du système. Le diagnostic de ces pannes nécessite une approche systématique, tirant parti des capacités robustes de journalisation et d'introspection de systemd.
Ce guide fournit une méthodologie complète et étape par étape pour dépanner les échecs courants de démarrage des services systemd. Nous couvrirons tout, des vérifications initiales du statut à la plongée approfondie dans les journaux, en passant par l'inspection des fichiers d'unité (unit files) et la résolution de problèmes de dépendances complexes. À la fin de cet article, vous disposerez des connaissances pratiques et des outils nécessaires pour diagnostiquer et résoudre efficacement la plupart des pannes de service systemd, garantissant ainsi que vos applications et services fonctionnent sans heurts.
La première ligne de défense : systemctl status
Lorsqu'un service ne démarre pas, la toute première commande que vous devriez exécuter est systemctl status <nom_du_service>. Cette commande fournit un aperçu de l'état actuel du service, y compris s'il est actif, chargé, et, surtout, un extrait de ses journaux récents. Cela fournit souvent suffisamment d'informations pour identifier rapidement le problème.
Imaginons que votre service d'application web, mywebapp.service, ne démarre pas :
systemctl status mywebapp.service
Interprétation de l'exemple de sortie :
● mywebapp.service - My Web Application
Loaded: loaded (/etc/systemd/system/mywebapp.service; enabled; vendor preset: disabled)
Active: failed (Result: exit-code) since Mon 2023-10-26 10:30:05 UTC; 10s ago
Process: 12345 ExecStart=/usr/local/bin/mywebapp-start.sh (code=exited, status=1/FAILURE)
Main PID: 12345 (code=exited, status=1/FAILURE)
CPU: 10ms
Oct 26 10:30:05 hostname systemd[1]: Started My Web Application.
Oct 26 10:30:05 hostname mywebapp-start.sh[12345]: Error: Port 8080 already in use
Oct 26 10:30:05 hostname systemd[1]: mywebapp.service: Main process exited, code=exited, status=1/FAILURE
Oct 26 10:30:05 hostname systemd[1]: mywebapp.service: Failed with result 'exit-code'.
À partir de cette sortie, nous pouvons immédiatement voir :
* Le service mywebapp.service est en statut failed (échec).
* Il a échoué avec Result: exit-code, ce qui signifie que la commande ExecStart s'est terminée avec un statut non nul.
* La ligne Process indique que la commande mywebapp-start.sh a échoué avec status=1/FAILURE.
* Surtout, les lignes de journal indiquent : Error: Port 8080 already in use. C'est un indicateur clair du problème.
Cette commande est votre premier outil de diagnostic, pointant souvent directement vers la cause ou précisant où chercher ensuite.
Plongée approfondie avec journalctl
Alors que systemctl status fournit un résumé rapide, journalctl est votre commande de référence pour une journalisation détaillée. Elle interroge le journal systemd, qui collecte les journaux de toutes les parties du système, y compris les services.
Examen de base des journaux
Pour afficher tous les journaux d'un service spécifique, y compris les entrées historiques :
journalctl -u mywebapp.service
Ceci affichera toutes les entrées de journal associées à mywebapp.service. Si le service échoue de manière répétée, vous verrez les entrées de chaque tentative ratée.
Filtrage et requêtes basées sur le temps
Pour affiner les résultats, en particulier après un échec récent, vous pouvez utiliser des drapeaux comme --since et --priority :
- Afficher les journaux depuis une heure précise :
bash journalctl -u mywebapp.service --since "10 minutes ago" journalctl -u mywebapp.service --since "2023-10-26 10:00:00" - Afficher uniquement les messages de niveau erreur ou supérieur :
bash journalctl -u mywebapp.service -p err - Combiner avec
-xepour une explication étendue et une sortie verbeuse :
bash journalctl -u mywebapp.service -xe --since "5 minutes ago"
Ceci est incroyablement utile carjournalctl -xefournit un contexte supplémentaire, y compris des explications pour certains messages de journal et des traces de pile (stack traces) si disponibles.
Comprendre les messages de journalisation
Recherchez des mots-clés comme Error, Failed, Warning, ou des messages spécifiques à l'application qui indiquent ce qui n'a pas fonctionné. Faites attention aux horodatages pour comprendre la séquence d'événements menant à la panne.
Astuce : Si le script ExecStart de votre service écrit sur la sortie standard ou l'erreur standard, ces messages sont généralement capturés par journalctl. Assurez-vous que vos scripts enregistrent des messages d'erreur descriptifs.
Inspection du Fichier d'Unité (Unit File) : le plan de votre service
Chaque service systemd est défini par un fichier d'unité (par exemple, mywebapp.service). Les erreurs de configuration dans ce fichier sont une source courante d'échecs de démarrage. Vous devez comprendre ce que le service essaie de faire.
Récupération du Fichier d'Unité
Pour visualiser le fichier d'unité actif de votre service :
systemctl cat mywebapp.service
Cette commande affiche le fichier d'unité exact que systemd utilise, y compris toutes les surcharges (overrides).
Directives clés à vérifier
Concentrez-vous sur la section [Service] pour les problèmes liés à l'exécution et sur [Unit] pour les dépendances.
ExecStart: C'est la commande que systemd exécute pour démarrer votre service. Vérifiez que le chemin est correct et que la commande elle-même est exécutable et s'exécute avec succès lorsqu'elle est appelée manuellement (par exemple, en tant queUserspécifié).
ini ExecStart=/usr/local/bin/mywebapp-start.shType: Définit le type de démarrage du processus. Les types courants comprennent :simple(par défaut) :ExecStartest le processus principal.forking:ExecStartcrée un processus enfant (fork) et le parent se termine. Systemd attend que le parent se termine.oneshot:ExecStarts'exécute et se termine ; systemd considère le service actif tant que la commande est en cours d'exécution.notify: Le service envoie une notification à systemd lorsqu'il est prêt.- Un
Typeincorrect peut amener systemd à penser qu'un service a échoué alors qu'il a réellement démarré, ou vice-versa.
User/Group: L'utilisateur et le groupe sous lesquels le service s'exécutera. Les problèmes de permissions proviennent souvent du fait que le service tente d'accéder à des fichiers ou des ressources pour lesquels il n'a pas les droits sous cet utilisateur.
ini User=mywebappuser Group=mywebappgroupWorkingDirectory: Le répertoire à partir duquel le service s'exécutera. Les chemins relatifs dansExecStartou d'autres commandes en dépendent.Restart: Définit quand le service doit être redémarré. S'il est défini suron-failureoualways, un service défaillant pourrait redémarrer constamment, rendant plus difficile la détection de la panne initiale.TimeoutStartSec/TimeoutStopSec: Le temps que systemd attend pour que le service démarre ou s'arrête. Si un service prend plus de temps à s'initialiser queTimeoutStartSec, systemd le terminera et signalera une panne.
Problèmes courants dans les Fichiers d'Unité
- Chemins incorrects : Faute de frappe dans
ExecStartou d'autres chemins de fichiers. - Variables d'environnement manquantes : Les services nécessitent souvent des variables d'environnement spécifiques (par exemple,
PATH) qui pourraient ne pas être présentes dans l'environnement minimal de systemd (voir ci-dessous). - Permissions : L'utilisateur
Userspécifié n'a pas les autorisations d'exécution pour le script ou les permissions de lecture/écriture pour les fichiers de données nécessaires. - Erreurs de syntaxe : Simples fautes de frappe dans le fichier d'unité lui-même.
Pour tester ExecStart manuellement :
Basculez vers l'utilisateur du service et essayez d'exécuter la commande directement :
sudo -u mywebappuser /usr/local/bin/mywebapp-start.sh
Ceci reproduit souvent l'erreur vue dans journalctl directement dans votre terminal, facilitant le débogage.
Gestion des Dépendances : Quand les services ne peuvent pas démarrer seuls
Les services s'appuient souvent sur d'autres services ou composants système pour être actifs avant de pouvoir démarrer eux-mêmes. Systemd utilise les directives Wants, Requires, After et Before pour gérer ces dépendances.
Identification des Dépendances
Utilisez systemctl list-dependencies <nom_du_service> pour voir ce qu'un service exige ou souhaite explicitement pour fonctionner.
systemctl list-dependencies mywebapp.service
Directives courantes dans la section [Unit] :
After=: Spécifie que ce service doit démarrer après les unités listées. Si l'unité listée échoue, ce service tentera quand même de démarrer (sauf siRequires=est également utilisé).Requires=: Spécifie que ce service nécessite les unités listées. Si l'une des unités requises ne démarre pas, ce service ne démarrera pas.Wants=: Une forme plus souple deRequires=. Si une unité souhaitée échoue, ce service tentera quand même de démarrer.
Exemple :
[Unit]
Description=My Web Application
After=network.target mysql.service
Requires=mysql.service
Ici, mywebapp.service ne démarrera qu'après le démarrage de network.target et de mysql.service, et il requiert que mysql.service réussisse. Si mysql.service échoue, mywebapp.service ne démarrera pas.
Résolution des conflits de dépendances
Si un service échoue en raison d'un problème de dépendance, journalctl indiquera généralement quelle dépendance n'a pas pu être satisfaite. Par exemple, il pourrait indiquer Dependency failed for My Web Application suivi de détails sur l'échec de mysql.service.
Étapes à suivre pour résoudre :
1. Vérifiez le service dépendant : Exécutez systemctl status <service_dependant> (par exemple, systemctl status mysql.service) et journalctl -u <service_dependant> pour dépanner son échec en premier.
2. Vérifiez les directives After= et Requires= : Assurez-vous qu'elles reflètent correctement l'ordre de démarrage souhaité et la rigueur. Parfois, un service doit attendre qu'un port spécifique soit ouvert, et pas seulement que le service soit actif. Pour les cas complexes, systemd-socket-activate ou des scripts ExecStartPre personnalisés peuvent être utiles.
Variables d'Environnement et Chemins : Les pièges cachés
Les services Systemd s'exécutent dans un environnement très propre et minimal. Cela conduit souvent à des problèmes où des commandes qui fonctionnent parfaitement dans le shell d'un utilisateur échouent lorsqu'elles sont exécutées par systemd parce que des variables d'environnement cruciales (comme PATH) sont manquantes.
L'environnement minimal de Systemd
Lorsque systemd démarre un service, il n'hérite pas de l'environnement complet de l'utilisateur qui a initié systemctl start. La variable PATH, par exemple, est souvent réduite, ce qui signifie que des commandes comme python ou node pourraient ne pas être trouvées si elles ne se trouvent pas dans des emplacements standards comme /usr/bin ou /bin.
Symptôme : ExecStart=/usr/local/bin/myscript.sh échoue avec "