Skip to content

Systemd

Diagnostic et Commandes de base

Identifier les services en échec

Pour voir rapidement quels services sont en erreur (failed) :

systemctl --failed

Ou pour plus de détails :

systemctl list-units --state=failed

Commandes systemctl essentielles

Commande Action
systemctl status <service> Vérifier l'état du service
systemctl start <service> Démarrer le service
systemctl stop <service> Arrêter le service
systemctl restart <service> Redémarrer le service
systemctl reload <service> Recharger la configuration du service
systemctl enable <service> Activer le service au démarrage
systemctl disable <service> Désactiver le service au démarrage
systemctl daemon-reload Recharger la configuration systemd après modification d'un fichier unit

Journalisation avec journalctl

Utilisation

Voire en live les infos :

journalctl -f

Voire le journal en commençant par la fin :

journalctl -e

Voir les informations importantes :

journalctl -xe

Filtrer par service :

journalctl -u crond

Filtrer par niveau de log (ici que les erreurs) :

journalctl -p err

On peut filtrer par date :

journalctl --since "2023-02-10 21:00:00"

On peut combiner toutes ces options :

journalctl -f /usr/sbin/urpmi -p info

Navigation dans journalctl :

Key Description
Arrow Move by one line
Space Move down one page
b Move up one page
g Go to the first line
G Go to the last line
100g Go to the 100th line
/string Search for the string from current position
n/N Go to the next or previous search match
q Exit the logs

On peut aussi utilisé tail pour voire les info en live :

sudo tailf /var/log/apache2/access.log

Source : linuxtricks tecmint

Configuration

Les configuratio sont dans le dossier suivant :

/etc/systemd/journald.conf

Les journaux sont dans l'emplacement suivant :

Note

/var/log/journal

Crée son propre service “systemd”

Service simple

  • Créez un fichier Unit pour définir un service systemd :
File: /lib/systemd/system/myservice.service

Exemple de configuration de service :

[Unit]
Description=FUSE filesystem over Google Drive
After=network.target
StartLimitIntervalSec=0
[Service]
User=root
Group=root
ExecStart=google-drive-ocamlfuse /mnt/googledrive/ -o allow_other
ExecStop=fusermount -u /mnt/googledrive/
Restart=always
Type=forking

[Install]
WantedBy=multi-user.target

Exemple de configuration pour redémarrer un conteneur docker toutes les 2 heures :

[Unit]
Description=Restart the container Syncthings
After=docker.service

[Service]
Type=simple
ExecStart=/bin/bash -c "sleep 120 && docker restart syncthing"
Restart=always
RestartSec=3600

[Install]
WantedBy=multi-user.target

Service persistant

Pour s'assurer qu'un service reste actif ou redémarre automatiquement en cas de problème, systemd propose différentes approches : l'utilisation des directives de redémarrage intégrées, la mise en place d'un mécanisme de "health check", ou l'utilisation de fichiers "Drop-in" pour les prérequis complexes.

Option 1 : Redémarrage automatique via les directives systemd

C'est la méthode recommandée pour gérer les crashs ou les échecs de dépendances. Vous pouvez configurer le fichier unit du service pour qu'il tente de se relancer selon des critères précis.

Voici les directives clés à ajouter dans la section [Service] ou [Unit] :

  • Restart= : Définit quand le service doit redémarrer. Les valeurs courantes sont always (toujours), on-failure (en cas d'erreur de sortie, de signal ou de timeout), ou on-abnormal.
  • RestartSec= : Le temps d'attente avant de tenter un redémarrage (ex: 5s, 1min).
  • StartLimitBurst= : Le nombre maximum de tentatives de démarrage autorisées dans un intervalle de temps donné.
  • StartLimitIntervalSec= (à placer dans la section [Unit]) : L'intervalle de temps pendant lequel les tentatives (StartLimitBurst) sont comptées.

Exemple : Un service qui redémarre en cas d'échec, attend 10 secondes entre chaque essai, et abandonne après 3 échecs en moins de 60 secondes.

[Unit]
Description=Mon service résilient
After=network.target
StartLimitIntervalSec=60s

[Service]
Type=simple
ExecStart=/usr/bin/mon_programme
Restart=on-failure
RestartSec=10s
StartLimitBurst=3

[Install]
WantedBy=multi-user.target
Si le service échoue 3 fois en moins d'une minute, systemd arrêtera d'essayer et le service restera en état "failed".

Option 2 : Redémarrage conditionnel via un Health Check (Timer + Script)

Parfois, un service peut être "actif" du point de vue de systemd (le processus tourne), mais "cassé" fonctionnellement (ex: perte de connexion à une base de données ou tunnel VPN figé). Dans ce cas, les directives Restart= ne suffisent pas.

La solution consiste à créer un script de vérification et de l'exécuter régulièrement avec un systemd.timer.

1. Le script de vérification (/usr/local/bin/check-mon-service.sh) : Ce script vérifie l'état réel et redémarre le service ciblé si nécessaire.

#!/bin/bash
# Vérifie si google.com est joignable
if ! ping -c 3 8.8.8.8 > /dev/null 2>&1; then
    echo "$(date): Perte de connexion, redémarrage du service..."
    systemctl restart mon_service.service
fi
(N'oubliez pas de rendre le script exécutable : chmod +x /usr/local/bin/check-mon-service.sh)

2. Le service qui lance le script (/etc/systemd/system/healthcheck.service) :

[Unit]
Description=Healthcheck pour mon_service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/check-mon-service.sh

3. Le timer qui planifie l'exécution (/etc/systemd/system/healthcheck.timer) :

[Unit]
Description=Lance le healthcheck toutes les 5 minutes

[Timer]
OnBootSec=5min
OnUnitActiveSec=5min

[Install]
WantedBy=timers.target

Activation :

sudo systemctl daemon-reload
sudo systemctl enable --now healthcheck.timer

Option 3 : Dépendances complexes (Drop-in et ExecStartPre)

Pour des services nécessitant des prérequis plus avancés (comme attendre qu'un point de montage spécifique soit réellement disponible avant de démarrer), il est recommandé d'utiliser les fichiers "Drop-in" de systemd couplés à l'instruction ExecStartPre.

Cela permet de surcharger la configuration d'un service existant (comme Docker) sans modifier son fichier principal d'origine (qui risquerait d'être écrasé lors d'une mise à jour).

Voici un exemple concret pour forcer Docker à attendre le montage de /mnt/data.

1. Le script d'attente (/usr/local/bin/docker-mount-check.sh) : Ce script va bloquer la séquence de démarrage du service tant que la condition (la présence du point de montage) n'est pas remplie.

#!/bin/bash
# Attendre que le point de montage personnalisé soit prêt
echo "Attente du montage de /mnt/data..."
until mountpoint -q /mnt/data; do
  echo "/mnt/data n'est pas encore monté, on patiente..."
  sleep 1
done
echo "/mnt/data est monté."
echo "Tous les points de montage sont prêts."
(N'oubliez pas de rendre le script exécutable : chmod +x /usr/local/bin/docker-mount-check.sh)

2. Le fichier Drop-in (/etc/systemd/system/docker.service.d/10-mount-dependencies.conf) : Créez un dossier portant le nom du service suivi de .d (ex: docker.service.d). Tous les fichiers .conf placés à l'intérieur s'ajouteront à la configuration principale.

[Unit]
# Dépendances de montage personnalisées pour Docker
After=mnt-data.mount
Requires=mnt-data.mount

[Service]
# Attendre que tous les points de montage soient là avant de lancer Docker
ExecStartPre=/usr/local/bin/docker-mount-check.sh

Activation :

sudo systemctl daemon-reload
sudo systemctl restart docker.service
Vous pourrez vérifier que la configuration est bien prise en compte avec systemctl status docker qui affichera la mention Drop-In: /etc/systemd/system/docker.service.d └─10-mount-dependencies.conf.

Dépendance ZFS

Résolution de service qui dépende de ZFS

On peut éditer les service qui dépende d'un point de montage ZFS avec la ligne :

After=zfs-mount.service

Voici un exemple avec le service docker :

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target docker.socket firewalld.service containerd.service
Wants=network-online.target containerd.service
Requires=docker.socket
After=zfs.target

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
EnvironmentFile=-/etc/default/docker
#ExecStartPre=/bin/sleep 10
ExecStart=/usr/sbin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock $DOCKER_OPTS
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process
# restart the docker process if it exits prematurely
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s

[Install]
WantedBy=multi-user.target

Crontab

Commande pour configurer Crontab :

sudo crontab -e

Exemple de configuration crontab :

@reboot rm -rf /mnt/data/* && sleep 25 && sshfs user@10.3.1.2:/mnt/data /mnt/data -o reconnect,allow_other
@daily docker system prune -af --volumes
@hourly docker exec -t photoprism photoprism index
@weekly rsync -r --del --exclude='photoprism/cache/*' /docker/appdata/ /mnt/data/Backup/Docker

Service de vérification de montage (Exemple systemd)

La solution trouvé est de faire un service systemd qui vérifie en boucle que les point de montage fonctionne. Dans cette exemple je l'ai écrit à l'emplacement suivant : /etc/systemd/system/mount-check.service

[Unit]
Description=Mount NFS and CIFS Shares and Periodically Check
After=network.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/bin/bash -c 'while true; do \
    if ! mountpoint -q /mnt/OT; then \
        umount -f -l /mnt/OT 2>/dev/null; \
        mount -t nfs4 10.168.7.20:/Talend/MES/Monitoring/Ecarts_stocks/ /mnt/OT || \
        { echo "NFS Mount failed, will retry in 5 minutes" >&2; sleep 300; continue; }; \
    fi; \
    if ! mountpoint -q /mnt/VMFSFMESWT01; then \
        umount -f -l /mnt/VMFSFMESWT01 2>/dev/null; \
        mount -t cifs //VMFSFMESWT01.organisation.one/organisation_ERP /mnt/VMFSFMESWT01 -o credentials=/etc/samba/user.cred,file_mode=0777,dir_mode=0777,_netdev || \
        { echo "CIFS Mount failed, will retry in 5 minutes" >&2; sleep 300; continue; }; \
    fi; \
    sleep 300; \
done'
ExecStop=/bin/bash -c 'umount -f -l /mnt/OT 2>/dev/null; umount -f -l /mnt/VMFSFMESWT01 2>/dev/null'
Restart=always
RestartSec=30

[Install]
WantedBy=multi-user.target

Pour activé le service on fait les commande suivante :

sudo systemctl daemon-reload
sudo systemctl enable mount-check.service
sudo systemctl start mount-check.service