Qué es ?
Systemd ou system daemon est un système d’initialisation à destination du noyau Linux. Il a été conçu pour offrir un paramétrage des services au démarrage, une meilleur gestion des dépendances entre ces services et réduire les appels aux scripts shell linux. Son homologue historique est System V, et on peux aperçevoir encore aujourd’hui de nombreux débats entre systemd et System V …
Au niveau des versions, on en est à la v238, disponible ici.
Pour connaître son numéro de version actuel :
$ systemd --version
Emplacement
System V
Pour system V, l’emplacement des scripts d’initialisation se situe dans /etc/init.d. Et on gère les services avec /etc/init.d/mon_service start ou alors avec la commande service, qui point sur le même chemin d’init.
systemd
Pour les fichiers de configuration de systemd, on trouve deux répertoires :
• Le premier, contenant la configuration par défaut dans /lib/systemd/system.
• Un second répertoire existe, /etc/systemd/system qui est utilisé pour stocker ces propres configurations/modifs’ personnelles. Ce répertoire contient des fichiers service sous forme de liens symboliques, pointant sur le répertoire /lib/systemd/system.
Placer ses propres modifications dans /etc/systemd/system évite de les voir écraser en cas de mises à jours système (le répertoire /lib contient toutes les libraires nécessaire pour le bon fonctionnement du système et l’exécution des commandes).
Lors du listage du répertoire /etc/systemd/system, on s’aperçois que les services présents sont des liens symboliques pointant vers /lib/systemd/system :
$ ls -al /etc/systemd/system/ lrwxrwxrwx 1 root root 35 déc. 23 15:22 display-manager.service -> /lib/systemd/system/lightdm.service lrwxrwxrwx 1 root root 31 janv. 17 19:22 sshd.service -> /lib/systemd/system/ssh.service
Commandes en vrac
Services
Démarrer le service exemple
$ systemctl start exemple.service
Stopper le service exemple
$ systemctl stop exemple.service
Afficher le statut du service exemple (état, emplacement, temps d’activité, PID ..)
$ systemctl status exemple.service
Redémarrer le service exemple (stop puis start)
$ systemctl restart exemple.service
Redémarrer le service exemple en étant déja actif
$ systemctl condrestart exemple.service
Activer au démarrage le service exemple
$ systemctl enable exemple.service
Afficher les processus en cours d’exécutions avec leur PID sous forme d’arbre
$ systemctl status
Suspendre le système (mise en veille)
$ systemctl suspend
Vérifier si le service exemple est actif au démarrage du poste ou non
$ systemctl is-enabled exemple.service
Lister les services actifs au démarrage de l’OS
$ systemctl list-unit-files | grep enabled
Lister les services actuellement actifs
$ systemctl list-units -t service
Liste les dépendances du service exemple
$ systemctl list-dependecies exemple.service
Rechargement de systemd (nouveau fichier init par ex..)
$ systemctl daemon-reload
Analyser son temps de boot (chargement du kernel + espace utilisateur).
$ systemd-analyze
Dans le même genre, pour repérer les services ralentissant le démarrage du système
$ systemd-analyze blame
Logs
SystemD inclue également l’outil journalctl pour la journalisation (logs) de ses évènements.
Consulter les logs en temps réel
$ journalctl -f
Consulter les logs d’un services précis
$ journalctl --unit <mon_service>
Consulter les logs jusqu’au 03 Février 2019 à 10h00
$ journalctl --until "2019-02-03 10:00:00"
Consulter les logs depuis le 07 Février 2019 à 23h20
$ journalctl --since "2019-02-07 23:20:00"
On peut combiner cela avec un service précis
$ journalctl --since "2019-02-07 23:20:00" --unit <mon_service>
Étude d’un service
SSH
Un service basique : le serveur SSH.
$ systemctl status ssh
1. ● ssh.service – My Secure Shell Server 🙂
2. Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled)
3. Active: active (running) since jeu. 2018-01-25 18:11:10 CET; 1h 16min ago
4. Process: 15781 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
5. Main PID: 1201 (sshd)
6. CGroup: /system.slice/ssh.service
└─1201 /usr/sbin/sshd -D
1. Nom du service suivi de sa description (custom pour ma part).
2. Son statut (loaded) et son emplacement. Plus de détails sur le preset ici. L’administrateur peut faire le choix de sélectionner uniquement certaines unités à activer.
3. L’état du service, sa date de démarrage et son uptime.
4. C’est un peu flou. Ce numéro est utilise pour tout les autres processus qui auraient pu être démarré par le service avec ExecStartPre, ExecStartPost etc .. Plusieurs autres lignes lancés par le service AUTRES que le processus principal.
5. Le PID du processus lancé avec ExecStart. Retrouvable avec un $ ps -aux |grep num_pid
6. Le groupe de contrôle (allocation des ressources à un processus) en lien avec avec le systemd.slice.
Les composants d’un fichier service
[Unit]
Description= Description du service
Avec After=my_service.service, il ne se lanceras qu’une fois que my_service.service sera démarré, dans un deuxième temps donc. A contrario, il y a aussi Before=my_service.service
Requires= conditionne les dépendances. Si l’exigence de la ligne requires n’est pas respecté, alors le service ne démarrera pas.
[Service]
Temps d’attente avant la mise en service avec TimeoutStartSec=
ExecStart= indique la commande à exécuter au moment du lancement du service. Paramètre obligatoire.
On peut également trouvé TimeoutStopSec= (temps d’attente avant l’arrêt du service) et TimeoutSec= (Raccourcis pour définir en même temps la valeur de Start et Stop)
ExecStartPre= correspond aux commandes exécutées avant le démarrage du service. Au niveau de la syntaxe, c’est un chemin absolu à respecter.
ExecStop= indique la commande pour stopper le service.
Type= est facultatif, et permet d’indiquer le type de démarrage du processus. Plusieurs valeurs sont possibles, voici les principales :
– simple : la valeur qui définis ExecStart= sera le processus principal du service. Il deviens actif immédiatement, même si il est encore en cours d’initialisation.
– forking : lorsque le processus parent se termine, le processus enfant continue toujours à tourner : c’est un daemon.
– oneshot : similaire à la valeur simple, le processus doit se terminer avant les unités de suivis. Il ne contient pas de ExecStart= mais un ExecStop=
StandardOutput= pour la sortie d’affichage (tty, logs ..)
RemainAfterExit= qui permet d’indiquer qu’une fois la commande de lancement exécutée (ExecStart), le service est toujours considéré comme actif. Et ceux jusqu’à l’arrêt (ExecStop) de ce service.
Restart= et l’argument associé permet d’indiquer le mode de fonctionnement du service si il crash, redémarre, arrêté ou si un délai d’attente définis (timeout) est atteint.
Au niveau des arguments principaux possible pour le Restart= :
– no : présent par défaut, le service ne sera pas redémarré
– on-success : le service ne sera redémarré que lorsque le processus sera proprement terminé (code de sortie = 0)
– on-failure : le service ne sera redémarré lorsque le processus sera terminé avec une erreur (code de sortie différent de 0)
– always : Le service sera redémarré peu importe le fait qu’il se soit terminé proprement ou non.
[Install]
La section Install d’une unité est facultative et n’est pas interprétée par systemd. Son exécution ici se passera dans le niveau d’exécution multi-utilisateur au niveau des Runkevels 2, 3, 4 et 5.
Un runlevel correspond au niveau d’exécution du processus. Avec Debian, sept niveaux sont définis :
- 0 – Arrêt du système
- 1 – Simple utilisateur, mode minimal/maintenance
- 2 à 5 – Mode multi-utilisateurs
- 6 – Redémarrage système
Avec WantedBy= et l’argument multi-user.target, on indique à notre service d’agir dans la target multi-utilisateurs.
Tableau de correspondance des targets systemd
WantedBy= est le plus courant, mais on peut également trouver :
- RequiredBy= qui permet de spécifier une dépendance recquise au démarrage de l’unité. Si la dépendance n’est pas respecté, l’unité ne démarrera pas
- Alias= permet d’activer l’unité sous un autre nom
- Also= permet d’activer/désactiver les unités comme un ensemble
- DefaultInstance= utilisé comme valeur de repli, concernant les templates d’unité nommant des instances de manière aléatoire
Création de mon propre service
Lancement et management d’un container Nginx avec systemd.
Création du fichier service
$ sudo nano /etc/systemd/system/nginx-docker.service
Contenu du fichier
[Unit] Description=Container Nginx with systemD After=docker.service Requires=docker.service [Service] Type=simple ExecStartPre=-/usr/bin/docker kill systemd_nginx ExecStartPre=-/usr/bin/docker rm systemd_nginx ExecStartPre=-/usr/bin/docker pull nginx:latest Restart=on-success ExecStart=/usr/bin/docker run -d --name systemd_nginx --restart always -p 8080:80 nginx:latest ExecStop=/usr/bin/docker stop systemd_nginx RemainAfterExit=yes [Install] WantedBy=multi-user.target
Rechargement de systemd pour la prise en compte de mon nouveau service
$ sudo systemctl daemon-reload
On peut maintenant le manager :
$ systemctl start nginx-docker.service
$ systemctl status nginx-docker.service ● nginx-docker.service - Container Nginx with systemD Loaded: loaded (/etc/systemd/system/nginx-docker.service; disabled) Active: active (exited) since jeu. 2018-03-22 18:42:18 CET; 5s ago Process: 764 ExecStart=/usr/bin/docker run -d --name systemd_nginx --restart always -p 8080:80 nginx:latest (code=exited, status=0/SUCCESS) Process: 745 ExecStartPre=/usr/bin/docker pull nginx:latest (code=exited, status=0/SUCCESS) Process: 741 ExecStartPre=/usr/bin/docker rm systemd_nginx (code=exited, status=0/SUCCESS) Process: 687 ExecStartPre=/usr/bin/docker kill systemd_nginx (code=exited, status=0/SUCCESS) Main PID: 764 (code=exited, status=0/SUCCESS)
On s’assure que notre instance Nginx est bien présente :
$ curl --silent localhost:8080 | head -n 5 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style>
Sources et documentations complémentaires
Je poste ici mes sources, qui m’ont permis la rédaction de ce billet. Il y a également des liens annexes, pour approfondir la compréhension de systemd. Car oui, systemd est très très très très très très …. vaste ! 🙂