Il y a deux types de journées Linux.
Celles où tout tourne. Et celles où tu déploies un service, il démarre, puis il meurt. Ou pire, il redémarre en boucle. Et toi tu regardes l’écran en te disant « mais pourtant, ça marchait en manuel ».
Systemd, au début, peut donner cette sensation bizarre : tout est structuré, propre, mais quand ça casse, tu ne sais pas par quel bout prendre. Bonne nouvelle : on peut rendre ça très mécanique. Une checklist. Des commandes. Un peu de méthode, et tu passes de « je subis » à « je diagnostique ».
Dans cet article, on va faire exactement ça. Et je vais rester dans un cadre réaliste : services qui crash, services qui restent en « activating », services qui bouclent en restart, variables d’environnement pas prises, droits foireux, dépendances réseau, etc.
Ce que systemd essaie de te dire (et pourquoi tu ne l’entends pas)
Quand un service plante, systemd sait souvent très bien pourquoi. Le souci, c’est qu’il te le dit dans plusieurs endroits.
Tu as au moins 3 sources d’info :
- l’état du service via
systemctl status - les logs via
journalctl - et parfois les logs applicatifs, si ton service écrit ailleurs
L’erreur classique, c’est de faire seulement :
bash systemctl status monservice
De voir 4 lignes rouges. Et de repartir bidouiller le fichier .service au hasard.
On va plutôt faire ça proprement.
Étape 1 : lire l’état, mais vraiment
La commande de base :
bash systemctl status monservice --no-pager -l
--no-pager: pas de less, pas de scroll qui te cache des trucs-l: lignes complètes, sinon systemd tronque et tu rates l’info utile
Ce que tu cherches dans la sortie :
- Active :
failed,activating,inactive,active (running)… logique - Main PID : est ce que le process existe vraiment
- ExecStart : la commande exacte lancée
- Exit code :
status=1/FAILURE,status=203/EXEC, etc. - les dernières lignes de logs juste en dessous
Exemples de codes qui parlent beaucoup :
status=203/EXEC: binaire introuvable, droit d’exécution manquant, ou chemin fauxstatus=217/USER: utilisateur déclaré dansUser=invalide ou inaccessiblestatus=1/FAILURE: erreur applicative, souvent à creuser dans les logs
Étape 2 : aller au journal, côté systemd
Ensuite, logs complets du service :
bash journalctl -u monservice --no-pager -b
-u: unité-b: depuis le dernier boot, sinon tu mélanges avec des logs d’il y a 3 jours
Astuce simple mais puissante : afficher les logs en temps réel.
bash journalctl -u monservice -f
Tu relances ton service dans un autre terminal, et tu vois instantanément ce qui se passe :
bash systemctl restart monservice
Si le service crashe immédiatement, tu auras la trace au même moment.
Bonus : filtrer les logs d’erreur seulement
Pour couper le bruit :
bash journalctl -u monservice -p err..alert --no-pager -b
Ça remonte souvent pile l’exception ou le message qui manque.
Étape 3 : repérer une boucle de redémarrage
Le scénario typique : ton service démarre, plante, systemd redémarre, replante… et ainsi de suite.
Dans systemctl status, tu verras souvent un truc comme :
Scheduled restart job, restart counter is at 5.
Regarde aussi ces paramètres dans ton unité :
Restart=RestartSec=StartLimitIntervalSec=StartLimitBurst=
Si tu veux temporairement arrêter la boucle pour respirer :
bash systemctl stop monservice systemctl reset-failed monservice
Le reset-failed est très utile, sinon systemd garde l’état « failed » en mémoire.
Étape 4 : valider le fichier service sans se mentir
Tu as modifié /etc/systemd/system/monservice.service ? Tu dois faire :
bash systemctl daemon-reload
Sinon, systemd ne recharge pas la définition. Et tu crois tester un fix, alors que tu testes l’ancienne config. Classique.
Ensuite :
bash systemctl restart monservice systemctl status monservice --no-pager -l
Vérifier ce que systemd a réellement compris
bash systemctl cat monservice
Tu vois le fichier final, y compris les overrides.
Et encore mieux :
bash systemctl show monservice | head -n 80
Ou ciblé :
bash systemctl show monservice -p ExecStart -p User -p Group -p WorkingDirectory -p Environment
Ça évite les surprises.
Étape 5 : les erreurs les plus fréquentes (et comment les attraper vite)
1) Chemin binaire faux ou non exécutable
Erreur typique : status=203/EXEC.
Vérifie :
bash ls -l /chemin/vers/ton/binaire file /chemin/vers/ton/binaire
Si c’est un script, check le shebang :
bash head -n 1 /chemin/script.sh
Et teste manuellement la commande ExecStart en copiant collant, mais attention : pas dans ton shell habituel avec ton environnement perso. J’y reviens.
2) Variables d’environnement absentes
Un service lancé à la main dans ton terminal marche. En systemd, ça plante. Souvent parce que ton .bashrc n’existe pas ici.
Solutions :
- définir des variables avec
Environment= - ou charger un fichier avec
EnvironmentFile=
Exemple :
ini [Service] Environment="NODE_ENV=production" EnvironmentFile=/etc/monservice.env
Puis dans /etc/monservice.env :
bash API_KEY=xxxx PORT=8080
Vérifie ensuite que systemd les a bien :
bash systemctl show monservice -p Environment
3) Mauvais répertoire de travail
Si ton app suppose un cwd, mets :
ini WorkingDirectory=/opt/monservice
Sans ça, l’app peut chercher des fichiers relatifs et exploser.
4) Droits utilisateur, permissions, fichiers non accessibles
Si tu as :
ini User=monuser Group=monuser
Vérifie :
bash id monuser sudo -u monuser ls -la /opt/monservice sudo -u monuser /opt/monservice/ton-binaire --version
Beaucoup de crash « silencieux » viennent d’un accès refusé sur un fichier de config, un socket, un dossier de logs.
5) Port déjà utilisé
Si ton service écoute un port, vérifie :
bash ss -lntp | grep :8080
Ou :
bash lsof -i :8080
Si tu vois un autre process, ton service peut mourir direct.
Étape 6 : simuler le contexte systemd (le truc qui change tout)
Ton terminal a ton PATH, tes variables, ton user, ton home. Systemd, non.
Deux outils très pratiques :
1) Exécuter comme l’utilisateur du service
bash sudo -u monuser -H bash -lc '/opt/monservice/start.sh'
-lsimule un shell login (selon les cas)- tu vois déjà si ça plante hors de ton compte
2) systemd-run pour tester rapidement
Tu peux lancer une commande dans un scope systemd :
bash systemd-run --unit=test-monservice --same-dir /opt/monservice/ton-binaire
Puis voir ses logs :
bash journalctl -u test-monservice --no-pager
Ça te rapproche du comportement réel.
Étape 7 : comprendre les services « qui ne sont pas vraiment des services »
Parfois ton unité est de type oneshot ou ton programme se fork en arrière plan. Et systemd croit que c’est fini, ou au contraire croit que ça n’a jamais démarré.
Regarde :
Type=simple(par défaut)Type=forkingType=oneshotType=notify
Si ton programme se met en arrière plan tout seul, Type=simple peut poser souci. Tu peux aussi avoir besoin de :
ini RemainAfterExit=yes
Ou de corriger le comportement du programme (idéalement).
Étape 8 : les timeouts et dépendances (réseau, DB, etc.)
Tu as un service qui plante au boot mais marche ensuite. Souvent, c’est juste trop tôt. Le réseau n’est pas prêt. La base n’est pas prête.
Tu peux :
- ajouter
After=network-online.target - et
Wants=network-online.target
Exemple :
ini [Unit] Wants=network-online.target After=network-online.target
Pour les DB, parfois un simple retry applicatif est mieux qu’une dépendance systemd rigide.
Si c’est un problème de timeout, tu peux ajuster :
ini [Service] TimeoutStartSec=60
Mais attention : rallonger un timeout peut masquer un vrai bug.
Étape 9 : quand ça sent le crash natif (segfault)
Si dans les logs tu vois segfault ou core dumped, là on passe en mode debug plus bas niveau.
Déjà, check :
bash coredumpctl list monservice coredumpctl info monservice
Et pour extraire :
bash coredumpctl dump monservice > core.dump
Selon le langage, tu auras tes outils (gdb, etc.). Mais au moins, tu sais que ce n’est pas un simple souci de config systemd.
Petit modèle de service propre (à adapter)
ini [Unit] Description=monservice After=network-online.target Wants=network-online.target
[Service] Type=simple User=monuser Group=monuser WorkingDirectory=/opt/monservice EnvironmentFile=/etc/monservice.env ExecStart=/opt/monservice/monservice Restart=on-failure RestartSec=2 TimeoutStartSec=30
[Install] WantedBy=multi-user.target
Puis :
bash systemctl daemon-reload systemctl enable --now monservice
Checklist express quand ça plante
Quand je veux aller vite, je fais ça, dans cet ordre :
systemctl status monservice --no-pager -ljournalctl -u monservice --no-pager -bjournalctl -u monservice -fpuissystemctl restart monservicesystemctl cat monservicesystemctl show monservice -p ExecStart -p User -p WorkingDirectory -p Environment- test manuel en conditions proches :
sudo -u monuser -H bash -lc '...'
Et seulement après, je modifie.
Conclusion : systemd est strict, mais il est cohérent
Une fois que tu acceptes que systemd est un orchestrateur qui aime les choses explicites, ça devient plus simple. Tu lui dis exactement quoi lancer, avec quel user, dans quel dossier, avec quelles variables, et comment réagir si ça tombe.
Et quand ça plante, tu ne devines pas. Tu lis. Tu reproduis. Tu corriges. C’est presque reposant, en fait.
Si tu veux d’autres guides dans ce style, côté Linux et sysadmin pratique, j’en publie régulièrement sur « Le Blog Tech Pro de Samyn-Antoy ABASSE » : https://monblog-sa-abasse.blogspot.com/
Je garde le même angle que ici, du concret, des commandes, et pas trop de blabla.
Questions fréquemment posées
Pourquoi mon service systemd démarre puis plante immédiatement ?
Un service systemd qui démarre puis plante peut être dû à plusieurs causes : binaire introuvable ou sans droit d'exécution (status=203/EXEC), utilisateur invalide (status=217/USER), ou erreur applicative (status=1/FAILURE). Il est essentiel de consulter l'état complet via 'systemctl status monservice --no-pager -l' et les logs avec 'journalctl -u monservice --no-pager -b' pour identifier précisément la cause.
Comment lire correctement l'état d'un service avec systemctl ?
Utilisez la commande 'systemctl status monservice --no-pager -l' pour afficher l'état complet sans pagination ni troncature. Vérifiez les champs importants comme Active, Main PID, ExecStart et Exit code. Cette méthode évite de manquer des informations cruciales souvent tronquées ou cachées par le pager.
Comment suivre les logs en temps réel d'un service systemd ?
Pour suivre les logs en temps réel, utilisez la commande 'journalctl -u monservice -f'. Lancez cette commande dans un terminal, puis redémarrez votre service dans un autre terminal avec 'systemctl restart monservice'. Vous verrez immédiatement les messages générés lors du démarrage ou du plantage du service.
Que faire si mon service boucle en redémarrage continu ?
Une boucle de redémarrage peut être identifiée par un message comme 'Scheduled restart job, restart counter is at X.' dans 'systemctl status'. Pour stopper temporairement la boucle, exécutez 'systemctl stop monservice' suivi de 'systemctl reset-failed monservice'. Vérifiez aussi les paramètres Restart=, RestartSec=, StartLimitIntervalSec= et StartLimitBurst= dans le fichier .service.
Comment s'assurer que systemd prend en compte mes modifications dans le fichier .service ?
Après avoir modifié '/etc/systemd/system/monservice.service', il faut impérativement exécuter 'systemctl daemon-reload' pour recharger la configuration. Sans cela, systemd continue d'utiliser l'ancienne définition et vos changements ne seront pas pris en compte. Ensuite, redémarrez le service avec 'systemctl restart monservice'.
Où trouver toutes les informations utiles lors du diagnostic d'un service systemd ?
Il existe au moins trois sources d'information : 1) L'état détaillé du service via 'systemctl status monservice --no-pager -l', 2) Les logs système liés au service avec 'journalctl -u monservice --no-pager -b', 3) Les logs applicatifs spécifiques si le service écrit ailleurs. Combiner ces sources permet un diagnostic précis et efficace.
0 Commentaires