Linux Fu : Démarrer avec Systemd

Je vais l'avouer. J'ai commencé à écrire cet article sur quelques astuces stupides de Systemd. Cependant, je voulais d'abord expliquer un peu systemd, et cela a fini par être plus long que les astuces. Ce Linux Fu contiendra donc des informations système très fondamentales. Le prochain contiendra quelques exemples, notamment comment monter automatiquement un Raspberry Pi Pico. Bien sûr, à la fin de cet article, vous n'aurez qu'effleuré la surface de systemd, mais je voulais vous donner un peu de contexte pour lire le reste.

Comme beaucoup d'utilisateurs Unix de longue date, je ne suis pas un grand fan de systemd. Là encore, j'attends aussi que toute la mode « fenêtres, icône, souris, pointeur » disparaisse. Qu'on le veuille ou non, systemd est là et probablement là pour rester dans un avenir prévisible. Je ne veux pas me lancer dans une guerre des flammes à propos de systemd. Aimez-le ou détestez-le, c’est une réalité de la vie. Je dirai qu'il a des fonctionnalités intéressantes. Je dirai également que la documentation s'est améliorée avec le temps. Mais je dirai également que cela a apporté de nombreux changements qui n’étaient peut-être pas nécessaires et a rendu certaines choses simples plus compliquées qu’elles ne le devraient.

Autrefois, nous utilisions des « scripts d'initialisation » et vous pouvez toujours le faire si vous êtes vraiment motivé. Ils n'étaient pas non plus bien documentés, mais il était assez facile de comprendre les scripts shell qui s'exécuteraient, et nous savons tous comment écrire des scripts shell. La méthode systemd consiste à utiliser des services qui ne sont pas définis par des scripts shell. Cependant, systemd essaie également de faire beaucoup d’autres choses. Il peut remplacer cron et exécuter des tâches périodiquement. Il peut remplacer inetd, syslog et de nombreux autres services traditionnels. C'est un avantage ou un inconvénient, selon votre point de vue.

(Note de l'éditeur : Et cette fonctionnalité de journalisation était exactement ce qui a été abusé dans la porte dérobée liblzma / ssh insensée de la semaine dernière.)

La configuration de systemd vous oblige à créer des fichiers dans l'un des nombreux emplacements. Dans le jargon systemd, ce sont des « unités ». Pour les besoins de ce Linux Fu, nous n'examinerons que quelques types d'unités : les services, les montages et les minuteries. Les services vous permettent d'exécuter des programmes en réponse à quelque chose comme le démarrage du système. Vous pouvez exiger que certains autres services soient déjà en cours d'exécution ou ne soient pas en cours d'exécution, ainsi que de nombreuses autres options. Si le service meurt, vous pouvez demander à systemd de le redémarrer automatiquement ou non. Les minuteries peuvent déclencher un service à un moment donné, un peu comme le fait cron. Une autre unité que vous rencontrerez sont les sockets qui représentent – ​​vous l’aurez deviné – une prise réseau.

Les bases

Si vous n'avez pas utilisé systemd, l'interface principale est systemctl (pas sysctl, ce qui est différent). Avec lui, vous pouvez activer et désactiver les « unités », qui sont généralement des « services ». Ainsi, par exemple, mon serveur ssh est une unité de service. En définissant une unité, quelqu'un pourrait dire : « Eh bien, si vous démarrez en mode multi-utilisateur, attendez que le réseau soit disponible et exécutez le serveur ssh. » Ou, un peu comme inetd, exécutez le serveur ssh lorsque quelqu'un ouvre une connexion sur le port 22. Toutes les unités ne sont pas des services. Certaines sont des prises réseau et d’autres des minuteries. Il en existe d'autres types également. Une minuterie est comme une tâche cron. Vous pouvez les configurer pour qu'ils s'exécutent de temps en temps.

Systemd gère deux ensembles d'unités. Un ensemble est destiné au système et vous devez être root pour travailler avec ceux-ci. Mais il gère également les éléments au niveau de l'utilisateur. Par exemple, votre serveur audio, probablement pulseaudio ou pipewire, dispose d'une unité de service systemd. Non seulement il lance le service, mais il le redémarre s'il meurt. Si vous modifiez un fichier unité, vous devez dire à systemd de relire tous les fichiers avec systemctl daemon-reload. Vous pouvez également activer, désactiver, démarrer et arrêter des services et d'autres unités avec la commande systemctl. Il existe également un moyen de masquer et de démasquer les unités, ce qui s'apparente à un super désactivation.

Bien que la documentation se soit améliorée au fil des années, le format des unités reste assez complexe car il existe de nombreuses options disponibles. La plupart du temps, vous n’avez besoin que d’un petit sous-ensemble des nombreuses options disponibles.

Par exemple

Voici une unité de service assez simple :

[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D $SSHD_OPTS
ExecReload=/usr/sbin/sshd -t
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
Alias=sshd.service

Vous pouvez probablement comprendre la plupart de ces éléments. Voici une unité de service très compliquée :

[Unit]
Description=Entropy Daemon based on the HAVEGE algorithm
Documentation=man:haveged(8) http://www.issihosts.com/haveged/
DefaultDependencies=no
After=apparmor.service systemd-tmpfiles-setup.service systemd-tmpfiles-setup-dev.service
Before=sysinit.target shutdown.target
Conflicts=shutdown.target
# RNDADDENTROPY ioctl requires host-level CAP_SYS_ADMIN, fails in unprivileged container
ConditionVirtualization=!container

[Service]
EnvironmentFile=-/etc/default/haveged
ExecStart=/usr/sbin/haveged --Foreground --verbose=1 $DAEMON_ARGS
Restart=always
SuccessExitStatus=137 143
SecureBits=noroot-locked
CapabilityBoundingSet=CAP_SYS_ADMIN
PrivateTmp=true
PrivateDevices=true
PrivateNetwork=true
ProtectSystem=full
ProtectHome=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelModules=true
RestrictNamespaces=true
RestrictRealtime=true

LockPersonality=true
MemoryDenyWriteExecute=true
SystemCallArchitectures=native
SystemCallFilter=@basic-io @file-system @io-event @network-io @signal
SystemCallFilter=arch_prctl brk ioctl mprotect sysinfo

[Install]
WantedBy=sysinit.target


Ce formulaire en ligne simplifie la rédaction de ce service purement fictif (lien dans le texte).

Waouh ! Il y a beaucoup de choses à analyser là-bas. Vous pouvez bien sûr retrouver toute la documentation. Mais beaucoup de gens copient un service de démarrage et le modifient. Une autre option consiste à utiliser un assistant pour vous aider à créer vos fichiers d'unité. Par exemple, vous pouvez en trouver en ligne. Remplissez les formulaires à gauche et observez le dossier à droite. Les instructions d'installation sont en haut. Si vous ne savez pas ce qu'un champ demande, il y a un petit bouton d'information pour vous donner un texte d'aide. Vous pouvez souvent choisir des éléments dans une liste déroulante. Bien sûr, vous pouvez tout écrire vous-même, mais cela rend les choses un peu plus faciles.

Si vous souhaitez créer une minuterie, vous avez besoin d'un fichier de service et d'un fichier de minuterie. Il existe également un assistant en ligne pour cela. Ce n'est pas aussi utile et vous devez comprendre comment systemd représente les intervalles de temps. C'est un peu plus compliqué que cron car vous pouvez définir des heures relatives à l'activation du minuteur, à l'heure de démarrage du système ou à la dernière activation du minuteur. Vous pouvez également définir des dates et des heures spécifiques, ajouter un délai aléatoire ou faire persister les minuteries.

Cette dernière option revient à utiliser anacron. Supposons que vous ayez une minuterie réglée pour fonctionner quotidiennement à 1 heure du matin sur un ordinateur portable. Le problème est qu'à 1 heure du matin, l'ordinateur portable est probablement éteint. Une minuterie persistante se rendra compte que lorsque vous allumez l'ordinateur portable à 8 heures du matin, il aurait dû exécuter le déclencheur de 1 heure du matin, puis le fera.

Il y a plus…

Une page Web similaire peut également créer vos minuteries.

Il y a tellement plus à savoir sur les unités. Une partie de cela est liée aux fonctionnalités. Une partie est liée à des bizarreries. Par exemple, les commentaires ne peuvent pas être placés en fin de ligne : ils doivent figurer sur leur propre ligne. Pour un autre exemple, les caractères spéciaux dans les noms de fichiers reçoivent des échappements hexadécimaux (cela sera important plus tard). Pour compliquer encore les choses, il existe des moyens de créer des modèles et d'ajouter des éléments. Tout cela dépasse le cadre de cet article, mais sachez que je dresse le tableau le plus simple possible de l'univers systemd.

L'autre problème est de savoir exactement où placer vos fichiers d'unité. Ils sont dispersés partout, et même s’il y a une bonne raison à l’endroit où ils vivent, cela reste ennuyeux.

La version courte est que vous devriez probablement placer les unités système dans /etc/systemd/system à moins que vous n'ayez une bonne raison de les placer ailleurs. Les unités pour tous les utilisateurs peuvent être placées dans /etc/systemd/user. Si vous voulez une unité pour un seul utilisateur, essayez ~/.config/systemd/user. Si vous recherchez l’emplacement d’une unité existante, « systemctl status xxx.service » vous le dira généralement. Sinon, essayez « systemctl show -P FragmentPath xxx.service ».

Si vous souhaitez lire la documentation actuelle :

Répertoires des unités système

Le gestionnaire système systemd lit la configuration de l'unité à partir de différents répertoires. Les packages qui souhaitent installer des fichiers unitaires doivent les placer dans le répertoire renvoyé par pkg-config systemd –variable=systemdsystemunitdir. Les autres répertoires vérifiés sont /usr/local/lib/systemd/system et /usr/lib/systemd/system. La configuration utilisateur est toujours prioritaire. pkg-config systemd –variable=systemdsystemconfdir renvoie le chemin du répertoire de configuration du système. Les packages doivent modifier le contenu de ces répertoires uniquement avec les commandes d'activation et de désactivation de l'outil systemctl(1). La liste complète des répertoires est fournie dans systemd.unit(5).

Répertoires des unités utilisateur

Des règles similaires s'appliquent aux répertoires des unités utilisateur. Cependant, ici, la spécification XDG Base Directory est suivie pour rechercher des unités. Les applications doivent placer leurs fichiers unité dans le répertoire renvoyé par pkg-config systemd –variable=systemduserunitdir. La configuration globale s'effectue dans le répertoire signalé par pkg-config systemd –variable=systemduserconfdir. Les commandes d'activation et de désactivation de l'outil systemctl(1) peuvent gérer à la fois l'activation/désactivation globale (c'est-à-dire pour tous les utilisateurs) et privée (pour un utilisateur) des unités. La liste complète des répertoires est fournie dans systemd.unit(5).

Astuce stupide n°0 : exécuter un programme au démarrage

Ce n'est pas vraiment une astuce, mais je voulais cette fois au moins un exemple pour vous montrer à quel point un service homebrew peut être simple.

Dans un article précédent, j'ai utilisé un « écran intelligent » bon marché pour afficher le flux RSS de Hackaday. Si vous souhaitez que cela s'exécute au démarrage – ou si vous souhaitez simplement que le code Python normal obtienne l'affichage de l'état du système – vous devez l'exécuter quelque part. Bien sûr, vous pouvez l'exécuter manuellement ou le placer dans vos fichiers de démarrage. Mais la façon systemd de le faire est d'utiliser une unité. Voici la mienne:

[Unit] 
Description=[Operate Smart Display] 

[Service] 
Type=simple 
StandardOutput=journal 
ExecStart=/home/alw/apps/turing-smart-screen-python-3.1.0/service 

[Install] 
WantedBy=default.target

C'est assez simple. Il définit un service simple qui génère des sorties dans le journal. Il démarre par défaut. Part de gâteau. La prochaine fois, nous verrons quelques exemples plus simples et cela vous incitera peut-être à écrire vos propres fichiers unitaires. Surveillez-le !

François Zipponi
Je suis François Zipponi, éditorialiste pour le site 10-raisons.fr. J'ai commencé ma carrière de journaliste en 2004, et j'ai travaillé pour plusieurs médias français, dont le Monde et Libération. En 2016, j'ai rejoint 10-raisons.fr, un site innovant proposant des articles sous la forme « 10 raisons de... ». En tant qu'éditorialiste, je me suis engagé à fournir un contenu original et pertinent, abordant des sujets variés tels que la politique, l'économie, les sciences, l'histoire, etc. Je m'efforce de toujours traiter les sujets de façon objective et impartiale. Mes articles sont régulièrement partagés sur les réseaux sociaux et j'interviens dans des conférences et des tables rondes autour des thèmes abordés sur 10-raisons.fr.