URL: https://linuxfr.org/news/systemd-pour-les-administrateurs-parties-3-4-et-5 Title: systemd pour les administrateurs, parties 3, 4 et 5 Authors: Médéric RIBREUX Benoît Sibaud, palm123, NeoX, Ontologia et Nils Ratusznik Date: 2014年09月30日T15:11:02+02:00 License: CC By-SA Tags: systemd, administrateur, administration_système, opensuse, mageia, fedora et lennart_poettering Score: 55 On vous parle depuis longtemps de systemd. On vous dit que c’est très bien. De nombreuses distributions l’ont adopté (dont Fedora, openSUSE, Mageia, Frugalware et ArchLinux), vont l’adopter (Debian, Ubuntu) ou vous permettent de l’utiliser de manière optionnelle (Gentoo par exemple). Mais savez‐vous l’utiliser ? Voici la suite d'[une série d’articles](/news/systemd-pour-les-administrateurs-partie-1-et-2) didactiques pour apprendre à utiliser systemd et vous permettre de mieux l’appréhender et de comprendre les avantages qu’il apporte par rapport aux systèmes précédents. Les informations ci‐dessous sont tirées, traduites et adaptées du [blog de Lennart Poettering](http://0pointer.de/blog/) et sont accessibles dans la langue de Shakespeare aux adresses ci‐dessous : ---- [systemd for Administrators, Part III](http://0pointer.net/blog/projects/systemd-for-admins-3.html) [systemd for Administrators, Part IV](http://0pointer.net/blog/projects/systemd-for-admins-4.html) [systemd for Administrators, Part V](http://0pointer.net/blog/projects/three-levels-of-off.html) ---- # Partie 3: Convertir un script d'init SysV en fichier de service systemd ? Traditionnellement, les services Unix et Linux (_les démons_) sont démarrés par des scripts d'init SysV. Il s'agit de scripts pour le shell Bourne qui résident généralement dans un répertoire tel que `/etc/rc.d/init.d/` et qui, lorsqu'ils sont appelés avec un des quelques arguments standards (verbes) tels que `start`, `stop` ou `restart`, respectivement démarrent, arrêtent ou relancent le service en question. Pour le démarrage, cela implique généralement d'invoquer le binaire du démon qui forke un processus en tâche de fond (plus précisément, qui devient un démon). Les scripts shell ont tendance à être lents, assez lourds à lire, très verbeux et fragiles. Bien qu'ils soient immensément flexibles (après tout, ce n'est jamais que du code), certaines choses sont difficiles à réaliser avec des scripts shell, comme mettre en ordre une exécution en parallèle, superviser correctement des processus ou encore simplement configurer les contextes d'exécution dans leurs moindres détails. Systemd fournit des éléments de compatibilité avec ces scripts shell mais, en raison des points négatifs invoqués précédemment, il est recommandé d'installer des fichiers de service systemd pour l'ensemble des démons installés. De plus, en contraste avec les scripts d'init SysV qui ont besoin d'être adaptés à la distribution, les fichiers de service systemd sont compatibles avec n'importe quelle distribution exécutant systemd (ce qui arrive de plus en plus fréquemment ces derniers temps...). Dans ce qui suit, vous trouverez un guide succinct sur comment convertir un script d'init SysV en un fichier de service natif systemd. Dans l'idéal, les projets en amont devraient distribuer et installer des fichiers de service dans leur archives tar. Si vous avez converti avec succès un script SysV en suivant les recommandations, il serait de bon ton de soumettre un patch au projet amont. La préparation d'un tel patch sera discutée lors d'une prochaine session et il suffit de vous informer que la page de manuel de [daemon(7)](http://0pointer.de/public/systemd-man/daemon.html), distribuée avec systemd contient de nombreuses informations utiles sur ce sujet. ## Plongeons-nous dedans À titre d’exemple, nous allons convertir le script d'init du démon ABRT en fichier de service systemd. ABRT est un composant standard de toute installation de Fedora et il s'agit d'un acronyme pour Automatic Bug Reporting Tool, ce qui décrit bien mieux ce dont il s'agit, à savoir, un service pour collecter les dumps de crash. [Le fichier de script SysV est disponible ici](http://0pointer.de/public/abrtd). La première étape à suivre pour convertir un tel script consiste simplement à le lire (!) et à récupérer l'information essentielle distillée tout au long de ce script volumineux. Dans la majorité des cas, le script est formé d'un ensemble de code qui est assez similaire dans tous les scripts d'init et il est généralement copié-collé d'un script à l'autre. Extrayons maintenant l'information essentielle du script ci-dessus: * Une chaîne de caractère qui décrit le service: "_Daemon to detect crashing apps_". Les commentaires de l'en-tête du script présentent plusieurs chaînes de description, certaines décrivant davantage le script d'init réalisant le démarrage du service que le service en lui-même. Les services systemd ont également besoin d'une description et ils devraient décrire le service et non le fichier de service. * L'en-tête LSB[^1] contient les informations de dépendance. Grâce à son architecture basée sur l'activation par socket, systemd n'a généralement pas besoin (ou un tout petit peu) de définir manuellement les dépendances. (Pour plus d'informations sur l’activation par socket [lisez l'article originel du blog](http://0pointer.de/blog/projects/systemd.html).) Dans ce cas, la dépendance vis-à-vis de `$syslog` (qui indique que arbtd a besoin d'un démon syslog) est la seule information d'intérêt. Même si l'en-tête indique une autre dépendance (`$local_fs`), celle-ci est redondante dans systemd car les services normaux systemd sont toujours démarrés lorsque tous les systèmes de fichiers locaux sont disponibles. * L'en-tête LSB suggère que ce service doit être démarré dans les runlevels 3 (multi-utilisateur) et 5 (graphique). * Le binaire du démon est `/usr/sbin/abrtd`. Et c'est déjà tout ! Le reste de ce script de 115 lignes est simplement du code générique ou redondant: du code qui gère la synchronisation et l'ordonnancement du démarrage (du code qui gère les fichiers de lock) ou qui génère des messages d'état (le code qui appelle echo), ou simplement qui analyse les arguments (le gros bloc du case). À partir de l'information extraite ci-dessus, nous pouvons maintenant écrire notre fichier de service systemd: ```ini [Unit] Description=Daemon to detect crashing apps After=syslog.target [Service] ExecStart=/usr/sbin/abrtd Type=forking [Install] WantedBy=multi-user.target ``` ## Un peu d'explications du contenu de ce fichier ### La section `[Unit]` Elle contient de l'information générique sur le service. Systemd gère des services systèmes mais également des périphériques, des points de montage, des timers, et d'autres composants du système. Le terme générique pour tous ces objets dans systemd est une unité (_Unit_). La section `[Unit]` stocke l'information qui s'applique non seulement aux services mais également à tous les autres types d'unité systemd. Dans notre cas, nous ajoutons les paramètres d'unité suivants: nous ajoutons une chaîne de caractère de description et nous configurons que le démon doit être lancé après Syslog^2, de la même manière à ce qui est indiqué dans l'en-tête LSB du script d'init originel. Pour gérer cette dépendance à Syslog, nous créons une dépendance de type `After=` sur l'unité systemd nommée `syslog.target`. Cette dernière est une unité particulière et elle représente le nom standard pour l'implémentation de syslog dans systemd. Pour plus d'informations sur ces noms standardisés, consultez la page de manuel [systemd.special(7)](http://0pointer.de/public/systemd-man/systemd.special.html). Notez qu'une dépendance du type `After=` représente seulement une suggestion d'ordre de démarrage; elle ne se traduit pas par le démarrage de syslog lorsque abrtd démarre. C'est exactement ce que nous voulons puisque abrtd fonctionne correctement, même lorsque syslog n'est pas disponible. Néanmoins, si les deux sont démarrés (c'est généralement le cas), alors l'ordre dans lequel ils sont lancés est contrôlé avec cette dépendance. ### La section `[Service]` Elle s'occupe de l'information sur le service en lui-même. Elle contient tous les paramètres qui s'appliquent uniquement à des services et non aux autres types d'unité systemd (points de montage, périphériques, timers, ...). Deux paramètres sont utilisés ici: `ExecStart=` qui stocke le chemin vers le binaire pour l'exécuter lorsque le service doit être démarré. Avec `Type=`, on configure la manière dont le service notifie le système d'init qu'il a terminé son démarrage. Étant donné que les démons traditionnels Unix le font en émettant un code de retour au processus parent après avoir forké et initialisé un démon en tâche de fond, nous utilisons le type forking ici. Cela indique à systemd d'attendre jusqu'à ce que le binaire de démarrage envoie un code retour et de gérer les processus qui tournent toujours après ceux du démon. ### La dernière section est `[Install]` Elle stocke l'information sur comment devrait être l'installation suggérée, c’est-à-dire, dans quelles circonstances et par quels déclencheurs le service devrait être démarré. Dans notre cas, nous indiquons simplement que le service doit être démarré lorsque l'Unit `multi-user.target` est activée. Il s'agit également d'une Unit spéciale qui prend globalement le rôle du Runlevel 3[^3] de SysV. Le paramètre `WantedBy=` a peu d'effet sur le fonctionnement courant du démon. Il est uniquement lu par la commande `systemctl enable` qui est le moyen recommandé d'installer un service dans systemd. Cette commande s'assure simplement que notre service est automatiquement activé dès que l'Unit `multi-user.target` est requise, ce qui est le cas lors des séquences de boot normales[^4]. Et c'est tout ! Nous avons maintenant un fichier de service systemd fonctionnel et simple. Pour le tester, il faut le copier dans `/etc/systemd/system/abrtd.service` et lancer `systemctl daemon-reload`. Cela permettra à systemd de prendre en compte notre fichier et dès cet instant, nous pouvons démarrer ce service en lançant: `systemctl start abrtd.service`. Nous pouvons en vérifier l'état grâce à `systemctl status abrtd.service`. Et nous pouvons arrêter le service via `systemctl stop abrtd.service`. Finalement, nous pouvons l'installer de manière à ce qu'il soit activé par défaut lors des prochains boots avec la commande `systemctl enable abrtd.service`. Le fichier de service ci-dessus, bien que suffisant et représentant une traduction globale du script d'init SysV, peut encore être amélioré. En voici une petite mise à jour: ```ini [Unit] Description=ABRT Automated Bug Reporting Tool After=syslog.target [Service] Type=dbus BusName=com.redhat.abrt ExecStart=/usr/sbin/abrtd -d -s [Install] WantedBy=multi-user.target ``` Voyons ce qui a changé. Deux choses: nous avons amélioré la description et, plus important, nous avons changé le type de service à dbus et configuré le nom D-Bus du service. Pourquoi avoir fait cela ? Comme déjà évoqué précédemment, les services classiques SysV deviennent des démons après le démarrage ce qui implique généralement un double fork et le fait de se détacher de tout terminal. Bien que cette approche soit utile et nécessaire lorsque les démons sont lancés par un script, elle est non nécessaire (et lente) ainsi que contre-productive lorsqu'un système efficace de gestion des processus tel que systemd est employé. La raison à cela est que le processus du démon qui a forké n'a généralement plus de lien avec le processus démarré par systemd (la procédure de transformation en démon consiste à supprimer ce lien), ce qui rend difficile pour systemd de distinguer, après le fork, dans les processus appartenant au service, lequel est le processus principal et quels sont les processus auxiliaires. Cette information est pourtant cruciale pour disposer d'une gestion de processus aux petits oignons, c’est-à-dire pour superviser un processus, le relancer automatiquement lors des arrêts anormaux, collecter l'information de crash et les codes de sortie. Pour que systemd puisse facilement repérer quel est le processus principal, nous avons changé le type de service à dbus. La syntaxe de ce type de service est faite pour tous les services qui prennent un nom sur le bus système D-Bus comme dernière étape de leur initialisation [^5]. ABRT est un de ces services. Avec ce paramètre, systemd lancera le processus ABRT qui ne forkera plus (configuré via les options `-d -s` du démon) et systemd considérera le service comme complètement démarré dès que `com.redhat.abrt` apparaîtra sur le bus. Ainsi, le processus lancé par systemd sera le processus principal du démon et systemd dispose d'un moyen fiable pour vérifier si le démon est complètement démarré; systemd pourra le superviser plus facilement. Et c'est tout ce qu'il y a besoin de faire. Nous avons un simple fichier de service systemd qui fournit plus d'information dans 10 lignes que le script SysV originel en 115 lignes. Dès maintenant, il reste encore une grande marge d'amélioration en utilisant plus de fonctionnalités de systemd. Par exemple, nous pourrions configurer `Restart=restart-always` pour indiquer à systemd de relancer automatiquement le service lorsque celui-ci échoue. Ou encore, nous pourrions utiliser `OOMScoreAdjust=-500` pour demander au noyau de laisser ce processus lorsque OOM killer est employé. Ou bien, nous pourrions utiliser `CPUSchedulingPolicy=idle` pour s'assurer qu'abrtd traite les traces de crash en tâche de fond uniquement, en autorisant le noyau à donner sa préférence à tout ce qui fonctionne et qui a besoin de temps CPU. Pour plus d'informations sur les options de configuration mentionnées ci-dessus, consultez les pages de manuel respectives [systemd.unit(5)](http://0pointer.de/public/systemd-man/systemd.unit.html), [systemd.service(5)](http://0pointer.de/public/systemd-man/systemd.service.html), [systemd.exec(5)](http://0pointer.de/public/systemd-man/systemd.exec.html). Ou bien, consultez [toutes les pages de manuel systemd](http://0pointer.de/public/systemd-man/). Bien sûr, tous les scripts SysV ne se convertissent pas aussi facilement que celui que nous avons étudié. Néanmoins une grande majorité devrait pouvoir l'être. C'est tout pour aujourd'hui, à bientôt pour la prochaine session de cette série. # Partie 4: Tuer des services # Tuer un service, c'est simple non ? Ou pas ? Bien entendu, tant que votre démon est constitué d'un seul processus, c'est généralement vrai. Vous tapez `killall rsyslogd` et le démon syslog n'est plus. Néanmoins, c'est un peu sale de faire ainsi étant donné que cela tuera tous les démons qui s'appellent ainsi, incluant ceux qu'un utilisateur malchanceux aurait nommé ainsi par accident. Une version plus correcte aurait été de lire le fichier `.pid`, c'est-à-dire ```kill $(cat /var/run/syslogd.pid)```. Cela nous avance un peu mais néanmoins est-ce vraiment ce que nous souhaitons ? Dans la majorité des cas en fait, cela ne se passera pas ainsi. Considérons des services tels qu'Apache, crond ou atd qui, dans leur fonctionnement courant, engendrent des processus fils. Généralement, il s'agit de processus fils configurables par l'utilisateur tels que des tâches cron ou at ou encore des scripts CGI, y compris des serveurs d'application complets. Si vous tuez le processus principal Apache/crond/atd cela pourra ou non tuer l'ensemble des processus fils également et c'est à chacun de ces processus de savoir s'ils veulent continuer à tourner ou s'ils doivent s'arrêter. Dans la pratique, cela signifie que mettre fin à Apache pourrait très bien laisser ces scripts CGI fonctionner, réaffectés comme enfants du processus init, ce qui est difficile à tracer. [Systemd](http://www.freedesktop.org/wiki/Software/systemd) vient à la rescousse: avec `systemctl kill`, vous pouvez facilement envoyer un signal à tous les processus d'un service. Par exemple: ```shell # systemctl kill crond.service ``` Cela assurera que SIGTERM est envoyé à tous les processus du service crond, pas uniquement au processus principal. Bien entendu, vous pouvez également envoyer un signal différent si vous le souhaitez. Par exemple, si vous êtes mal luné, vous aurez peut-être envie d'envoyer SIGKILL de cette manière: ```shell # systemctl kill -s SIGKILL crond.service ``` Et voilà, le service sera complètement stoppé brutalement, peu importe combien de fois il a été forké ou qu'il essaye d'échapper à la supervision par un fork double ou par un bombardement de forks. Parfois, vous avez juste besoin d'envoyer un signal spécifique au processus principal d'un service, par exemple parce que vous voulez déclencher un rechargement du service par le signal SIGHUP. A la place de retrouver le fichier de PID, voici un moyen plus simple d'y parvenir: ```shell # systemctl kill -s HUP --kill-who=main crond.service ``` Encore une fois, qu'y-a-t-il de nouveau et de fantaisiste dans la manière de tuer des processus avec systemd ? Eh bien, pour la première fois sous Linux, nous pouvons le faire proprement. Les précédentes solutions dépendaient toutes de la bonne coopération des démons pour qu'ils arrêtent tous les processus qu'ils avaient engendrés lorsqu'ils devaient se terminer. Néanmoins si vous voulez employer SIGTERM ou SIGKILL, vous le faites parce qu'ils ne coopèrent pas correctement avec vous. Qu'est-ce-que ça a à voir avec `systemctl stop` ? `kill` envoie directement un signal à chacun des processus situés dans le groupe; `stop`, pour sa part, utilise le moyen officiellement configuré pour arrêter le service, c'est-à-dire qu'il lance la commande configurée avec `ExecStop=` dans le fichier de service. En général, `stop` devrait être suffisant. `kill` reste la méthode forte à utiliser dans les cas ou vous ne voulez pas utiliser la commande `shutdown` d'un service ou bien lorsque le service est complètement en carafe. (C'est à vous bien entendu d'indiquer ou non les noms de signaux avec le préfixe SIG avec ou sans l'option -s. Les deux fonctionnent.) C'est assez surprenant d'être parvenu jusqu'ici sous Linux sans disposer d'un moyen efficace de tuer des services. Systemd permet pour la première fois de le faire proprement. # Partie 5: Trois niveaux de "Off" # Dans systemd, il y a trois niveaux pour arrêter un service (ou d'autres unités). Voyons voir quels sont-ils: ## Arrêter un service Cela termine simplement l'instance du service qui fonctionne et cela ne fait que ça. Si pour d'autres raisons d'activation (telles que le lancement manuel, l'activation par socket, par le bus, par le boot du système ou par un interrupteur machine) le service est demandé après cet arrêt, il sera à nouveau lancé. Arrêter un service est donc une opération simple, temporaire et superficielle. Voici un exemple avec le service NTP: ```shell $ systemctl stop ntpd.service ``` C'est globalement équivalent à la commande traditionnelle disponible sur la plupart des systèmes basés sur SysV: ```shell $ service ntpd stop ``` Dans les faits, sur Fedora 15, si vous exécutez cette dernière commande, elle sera convertie de manière transparente en la première. ## Désactiver un service Cela détache le service de ses déclencheurs. Cela signifie que, selon votre service, il ne sera plus activé au démarrage de la machine, par socket, par bus ou par un interrupteur machine (ou tout autre déclencheur qui s'y applique). Néanmoins, vous pouvez quand même le lancer manuellement si vous le désirez. S'il y a déjà une instance du service démarrée, désactiver un service ne l'arrêtera pas. Voici un exemple de comment désactiver un service: ```shell $ systemctl disable ntpd.service ``` Sur les systèmes traditionnels Fedora, c'est globalement l'équivalent de la commande qui suit: ```shell $ chkconfig ntpd off ``` Ici également, sur Fedora 15, la commande précédente sera convertie de manière transparente en la première, si nécessaire. Bien souvent, vous souhaitez combiner arrêt et désactivation du service, de manière à supprimer l'instance courante et faire en sorte que le service ne soit pas relancé (sauf par action manuelle): ```shell $ systemctl disable ntpd.service $ systemctl stop ntpd.service ``` Les commandes précédentes sont lancées par exemple lors de la désinstallation du paquet d'un service systemd sur Fedora. Désactiver un service est un changement permanent; tant que vous ne le réactivez pas, ce changement sera conservé même après le redémarrage de la machine. ## Masquer un service. C'est comme le désactiver mais en plus fort. Cela fait en sorte d'être sûr que le service ne sera plus jamais démarré automatiquement mais assure également qu'un service ne puisse plus être démarré manuellement. C'est une fonctionnalité cachée dans systemd puisqu'elle n'est pas utilisé couramment et qu'elle peut être mal interprétée par un utilisateur. Néanmoins, voilà comment vous devriez procéder: ```shell $ ln -s /dev/null /etc/systemd/system/ntpd.service $ systemctl daemon-reload ``` En créant un lien symbolique d'un fichier de service vers `/dev/null`, vous indiquez à systemd de ne jamais démarrer le service en question et vous bloquez complètement son exécution. Les fichiers d'unité stockés dans `/etc/systemd.system` remplacent ceux qui sont situés dans `/lib/systemd/system` qui portent le même nom. Le premier répertoire relève de l'administrateur système, le second relève du responsable de paquet. En installant un lien symbolique dans `/etc/systemd/system/ntpd.service`, vous pouvez être sûr que systemd ne lira jamais le fichier de service situé dans `/lib/systemd/system/ntpd.service`. Systemd reconnaîtra les unités liées vers `/dev/null` et les indiquera comme étant masquées. Si vous essayez de lancer de tels services manuellement (via `systemctl start` par exemple), cela se terminera par une erreur. Un mécanisme similaire n'existe pas (officiellement) pour les systèmes SysV. Néanmoins, il existe quelques trucs officieux comme éditer le script d'init et en indiquant un exit 0 au début ou bien encore en enlevant le bit exécutable. Néanmoins ces solutions présentent différents inconvénients comme le fait qu'elles interfèrent avec ce que le responsable de paquet a prévu. Masquer un service est un changement permanent, un peu comme désactiver un service. Maintenant que nous savons comment gérer l'arrêt de services sur ces trois niveaux, il reste encore une question: commet les réactiver. Eh bien, c'est assez similaire. Utilisez `systemctl start` pour revenir en arrière de la commande `systemctl stop`. Utilisez `systemctl enable` pour revenir en arrière de la commande `systemctl disable` et utilisez `rm` pour supprimer les liens symboliques. C'est tout pour aujourd'hui, Merci de votre attention ! # Notes de bas de page [^1]: L'en-tête LSB des scripts d'init est une convention qui permet d'inclure des métadonnées sur le service dans des blocs de commentaires des scripts d'init SysV. Elle est [définie dans la Linux Standard Base](http://refspecs.freestandards.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/initscrcomconv.html). L'objectif était de standardiser les scripts d'init parmi les différentes distributions. Bien que la majorité des distributions ont adopté ce schéma, la gestion des en-têtes varie beaucoup d'une distribution à l'autre et dans les faits, il est souvent nécessaire d'adapter chaque script d'init pour chacune des distributions. La spécification LSB sur ce point n'a jamais atteint la promesse qu'elle s'était fixée au départ. [^2]: D'un point de vue strict, cette dépendance n'a pas besoin d'être écrite ici car elle est redondante dans un système où le démon Syslog est activé par socket. Les systèmes modernes de syslog (par exemple rsyslog v5) ont été patchés en amont pour être activables par socket. Si un tel système d'init est utilisé, la configuration de la dépendance `After=syslog.target` est redondante car implicite. Néanmoins, pour conserver de la compatibilité avec des services syslog qui n'ont pas été mis à jour, nous incluons quand même cette dépendance. [^3]: Au moins de la manière utilisée pour sa définition dans Fedora. [^4]: Veuillez noter que dans systemd, le boot graphique (`graphical.target` qui prend le rôle du RunLevel 5 de SysV) est un sur-ensemble de la séquence de boot dédiée au mode console seule (`multi-user.target`, c’est-à-dire le RunLevel 3). Cela signifie que rattacher un service dans cette dernière le rattachera également à la première séquence de boot (`graphical.target). [^5]: En fait, la majorité des services de l'installation par défaut de Fedora utilisent maintenant un nom sur le bus après démarrage. Note du rédacteur: ce serait bien que l'ensemble des traductions relatives à systemd du blog de Lennart Poettering puissent être traduites sur LinuxFr.org (sauf peut-être celles sur journald qui est un composant optionnel de systemd). Cela permettrait de rendre plus accessible et démystifier un peu ce composant système devenu maintenant quasi-incontournable ainsi que d'apporter quelques articles techniques (pas forcément de haut niveau) sur LinuxFr.org.

AltStyle によって変換されたページ (->オリジナル) /