Journal Gestion des services avec runit

Posté par  . Licence CC By‑SA.
Étiquettes :
21
10
avr.
2019

Sommaire

Gestion des services avec runit

Tout le monde ici connaît plusieurs des grands intérêts de systemd, qui sont pour moi principalement, et sans ordre particulier:

  • description des services par déclaration, sans avoir à utiliser de scripts ultra-compliqués qui ont des dépendances dans tous les coins du système;
  • démarrage des services uniquement après que leurs dépendances soient prêtes;
  • activation au besoin;

Bon, je reconnais être un peu sceptique sur le 3ème, en vrai… je ne suis pas convaincu de l'intérêt actuel d'outils de type inetd, il faut dire que je ne suis pas admin, je n'ai probablement pas rencontré les cas ou il brille.

Je voudrais ici parler d'une manière alternative de réaliser, au moins en partie, les 2 autres, avec runit, et en évitant le "thundering herd problem" (de ce que j'ai compris, lancer un process avant qu'une ressource ne soit disponible, le process se mange un refus, se ferme, est relancé immédiatement, et ce jusqu'à mise à disposition de la ressource) reproché par nosh (cela dit, je ne parviens pas à retrouver la citation exacte) aux daemontools.

Je ne prétends pas répondre à tous les problèmes que systemd résoud, ni même que runit n'en cause aucun, c'est juste histoire de partager mon expérience sur cet outil. Je ne suis clairement pas un expert sur le sujet, comme n'importe qui devrait pouvoir le constater en lisant la suite.

Runit?

Runit est un système d'initialisation qui se base sur la mécanique des daemontools.
Contrairement à sysvinit ou rc.d, il ne «supporte» pas les runlevels et surveille ses enfants. Ceci se base sur l'idée que les enfants ne devraient pas se détacher de leur parent, ce qui est également à ma connaissance requis par systemd.

Si l'on regarde ce que contient le paquet Debian runit, on y voit plusieurs ELF (je ne cache pas que j'en découvre 2-3 en écrivant ceci):

  • /sbin/runit
  • /sbin/runit-init
  • /sbin/update-service
  • /usr/bin/chpst
  • /usr/bin/runsv
  • /usr/bin/runsvdir
  • /usr/bin/sv
  • /usr/bin/svlogd
  • /usr/bin/runsvchdir
  • /usr/bin/utmpset

Le binaire d'initialisation proprement dit est runit, qui est exécuté par runit-init (ne me demandez pas pourquoi, je m'en aperçois en fait en lisant les manpages…).

update-service sert à… ajouter, supprimer, lister ou vérifier l'existence d'un service. Son véritable intérêt est probablement juste de permettre de gérer les services sans connaître réellement
l'endroit du système où ils sont gérés, parce qu'en pratique on peut faire la même simplement à coup de ln, rm, ls… bon, je dirais qu'au moins c'est moins glissant d'utiliser update-service que de faire un rm en tant que root dans un dossier aussi critique…

chpst est un utilitaire qui permet de manipuler l'environnement de la commande suivante. Tout comme nice, il fonctionne sur l'idée du chaînage de commandes.

runsv est le watchdog, c'est lui le dernier maillon de la chaîne des processus avant le daemon lui-même, c'est aussi lui qui va rediriger la sortie standard du daemon dans un éventuel logger.

runsvdir est le «PID2», dans l'idée, même si l'appellation est mauvaise (il ne sera probablement pas PID 2): c'est lui qui va gérer la liste des services à lancer ou arrêter.

sv est la commande qui permet d'exercer un contrôle sur un ou plusieurs services. À noter que, tout comme systemd il permet d'en manipuler plusieurs d'un coup, contrairement au stupide service d'avant systemd.

svlogd est un logger. Si l'on veut stocker les logs d'un daemon, c'est l'outil que runit propose. Il est évidemment possible d'en utiliser un autre. À noter tout de même qu'il ne reprend absolument pas la logique de syslogd: une instance de logger par daemon géré, ce qui évite qu'un bug quelque part détruise ou corrompe les logs de l'ensemble du système (ou, du moins, réduit le risque). L'inconvénient, par contre, c'est qu'il n'est pas possible de récupérer les logs d'une machine sur le réseau qui ne les stockerait pas (j'ai le problème au boulot avec des routeurs que l'on embarque, contourné en 50 lignes de C, mais je me demanderais toujours s'il n'existe pas déjà un outil qui juste écoute sur un port UDP pour cracher le résultat sur la sortie standard…bref.) et la configuration se fait au cas par cas (pas plus mal, en vrai).
Cet outil lit l'entrée standard, applique divers traitement au texte, et écrit le tout dans un fichier. Si le fichier dépasse une taille ou un âge, ou si svlogd se prend un kill -ALRM, une
rotation des logs est déclenchée. Un logger, quoi.

runsvchdir change le dossier ciblé par runsvdir… une forme de runlevels, j'imagine, j'avoue ne pas en voir l'intérêt, mais bon…

utmpset interagit avec la base de données utmp/wtmp, je n'ai ici encore aucun cas d'usage en tête, sans doute parce que je n'ai jamais eu à travailler sur des machines réellement multi-utilisateurs.

Le lancement du système, sur une machine qui utiliserait la totalité des outils, est le suivant, grosso modo:

  1. le noyau lance runit-init, qui se remplace lui-même par runit
  2. runit lance le script /etc/runit/1
  3. runit lance le script /etc/runit/2, qui lance runsvdir et ne doit pas se fermer (c'est l'étape de fonctionnement normal de la machine)
  4. runsvdir examine le dossier qui lui est passé en paramètre et, pour chaque sous-dossier ou lien symbolique (max 1000) lance une instance de runsv. Si l'une de ces instances se ferme, il la relance, et si le dossier ou le lien est supprimé, il la ferme.
  5. runsv lance le fichier ./run de sa cible, ainsi qu'un éventuel ./log/run. Si l'un de ces fichiers se ferme, il exécute ./finish ou ./log/finish
  6. quand /etc/runit/2 se ferme, runit lance le script /etc/runit/3
  7. le système est éteint

Implémenter un script pour chaque daemon, vraiment?

Je pense que ce n'est pas nécessaire. Du moins, dans de nombreux cas, le shell nous donne tous les outils nécessaires l'éviter.

Par exemple, voici le fichier ./log/run que j'utilise:

LOG_DIR="/var/log/$(basename $(dirname $(pwd)))"
mkdir -p "${LOG_DIR}"
exec svlogd -tt "${LOG_DIR}"

Ce script extrait tout simplement le nom du dossier du daemon, crée un dossier spécifique pour les stocker (bon, ça peut péter, si l'on s'amuse à créer des noms avec des '/', mais en théorie celui qui utilise runit ne cherche pas à péter son système, si?), et lance le logger, le exec étant utilisé pour remplacer le process courant: nul besoin de forker ici après tout.

Et les dépendances?

Manifestement, dans les outils cités, il n'y à rien pour gérer les dépendances des services, ni même pour vérifier que tous les pré-requis pour lancer le daemon final sont présents.
Le seul outil qui permette d'éviter de lancer inutilement le processus final est donc l'exécutable ./run, qui est le plus souvent un script shell.

À titre personnel, j'implémente ces fichiers ./run comme une longue suite de vérifications qui sortent simplement du programme si toutes les conditions ne sont pas remplies.

Si une condition critique n'est pas remplie (une configuration erronée, par exemple, un matériel qui est absent, etc), je crée un fichier "down" dans le dossier géré par runsv, ce qui empêchera le
daemon d'être à nouveau démarré: si la config est foireuse, c'est inutile après tout… sinon, runsv attend une seconde et retente.
Rien n'empêcherait de boucler par une until, ce serait peut-être même plus robuste (sauf si entre temps une autre condition n'est plus remplie, mais même en revérifiant tout le risque existe), je compte de toute façon réécrire mes quelques helpers, pour corriger des points que j'avais mal compris ou ratés.

Il est possible de vérifier le statut d'un daemon géré par runsvdir par la commande sv status <nom du daemon>, mais de base, cette commande n'indique que l'âge et l'état du processus: dès lors que
le fichier ./run est en cours d'exécution, le daemon est considéré comme en ligne, ce qui est évidemment faux, puisqu'il peut très bien simplement être en train de vérifier l'état de ses dépendances…
La parade à ce problème, c'est le fichier ./check qu'il est possible de mettre dans un dossier de runsv: ce fichier permet un traitement afin de vérifier si vraiment le daemon est lancé.
Pour être franc, j'étais parti sur une autre solution très bancale à la base, en étant conscient de ses faiblesses, parce que cette information (le fichier ./check) est pour le moins noyée dans la
documentation…
Mais du coup, le problème est simplifié drastiquement: runsv crée, pour chaque daemon, un dossier supervise, qui contiens (entre autres, il y a aussi des fichiers pipe qui permettent d'émettre des
signaux pour le daemon, signaux qu'il est d'ailleurs également possible d'intercepter en écrivant des scripts bien nommés) un fichier pid, contenant la valeur de PID du process géré par
runsv.
Dans le cas le plus simple, il suffit donc d'avoir un fichier ./check dans ce goût la:

#!/bin/sh

. ./conf

test "${SV_CMD:?"SV_CMD not defined"}" != "$(ps -ocomm --pid $(cat supervise/pid))" && exit 1

exit 0

Ce fichier naïf dépend du fait que la variable SV_CMD soit définie, et correctement, mais d'un autre côté, je vois mal comment faire autrement, surtout si l'on veut éviter de ré-implémenter tous les scripts pour chaque service.
Si le daemon doit créer un socket, en plus, il est possible de vérifier que le socket est bien créé avec des commandes telles que test, find, ou autres.

Admettons, mais tout reste déclaratif, la, ce ne sont que des scripts…

Pas forcément, on pourrait les implémenter en prolog, ces fichiers… Je plaisante (quoique, techniquement, ce serait faisable…).

Jusqu'ici, j'ai toujours eu des implémentations spécifiques pour chaque fichier ./run, mais plus le temps passe, et plus ces implémentations ne sont en fait qu'une suite de fonctions qui sortent si un test n'est pas rempli…
Rien n'empêcherait en théorie de définir un certain nombre de variables pré-déterminées dans un fichier ./conf, qui serait sourcé par ./run, et gérer ainsi de manière déclarative (c'est la fonctionnalité de systemd que j'ai toujours regardé avec envie, vraiment! Mais à mes yeux elle ne compense pas points que je n'apprécie pas.) les dépendances, sans exécuter les processus à l'aveugle.

Compte tenu de mes besoins et connaissances actuels, je compte surtout implémenter ces quelques pré-requis:

  • vérifier/attendre qu'un daemon est «up»;
  • vérifier/attendre qu'un socket existe;
  • vérifier/attendre qu'une machine soit contactable;

Une implémentation sans trop de prise de tête ressemblerait à ceci:

#!/bin/sh

for daemon in ${CHECK_DAEMON}
do
    if test ! sv check $daemon
    then
        exit 0
    fi
done

for socket in ${CHECK_SOCKET}
do
    if test ! -S $socket
    then
        exit 0
    fi
done

for target in ${CHECK_REMOTE}
do
    #have to silent ping manually, netcat or nmap may avoid that
    if test ! ping -q -c $PING_COUNT $target 2>/dev/null
    then
        exit 0
    fi
done

exec chpst -u "${USER:-root}:${GROUP:-root}" $SV_CMD $SV_ARGS

Pour être franc, je n'ai eu cette idée qu'aujourd'hui, je vais sûrement expérimenter dessus dans les prochains jours…
En pratique, il faudrait ajouter pas mal de chaînage de commandes, et de la construction d'arguments dynamique sur l'exécution, le résultat final risque de prendre "quelques" lignes de plus si on veut avoir un truc avec une souplesse maximale.

Dans les connaissances que je n'ai pas et les besoins que j'ignore avoir, il y a clairement les cgroups et SElinux, et je sais que systemd gère déjà tout ça nativement, inutile de me le rappeler.

  • # Netcat?

    Posté par  (site web personnel) . Évalué à 10.

    je me demanderais toujours s'il n'existe pas déjà un outil qui juste écoute sur un port UDP pour cracher le résultat sur la sortie standard

    $ nc -u 12345 -l & echo "le résultat" | nc -u 127.0.0.1 12345
    [1] 16582
    le résultat
    
    • [^] # Re: Netcat?

      Posté par  . Évalué à 2.

      Maintenant que tu le dis, je me demande pourquoi j'ai pas pensé à netcat… après tout, le but était juste d'écouter un port pour sortir le résultat dans stdout… je me sens encore plus bête, du coup.

      • [^] # Re: Netcat?

        Posté par  (site web personnel) . Évalué à 5.

        Avec bash aussi:

        $ nc -u 12345 -l &  bash -c 'exec 3<>/dev/udp/127.0.0.1/12345; echo le résultat >&3;'
        [2] 16830
        le résultat
        
        • [^] # Re: Netcat?

          Posté par  . Évalué à 0.

          hum, entre un code C standard de 50 lignes et une ligne de bash "illisible" (de mon point de vue, ce concentré de caractères sans espaces est pénible à lire du moins) et qui risque de se retourner contre moi, je préfère les 50 lignes de C standard.
          En plus, ici netcat est toujours nécessaire in fine.
          Aussi, j'ai appris à me méfier d'echo, et une pratique que j'essaie de faire au max est de toujours utiliser printf, pour éviter les surprises.
          Ça doit être lié au fait que je suis un dev qui joue aux admins, et pas un vrai admin (au moins, j'en suis conscient).

          Par contre, je bloque sur la construction "foo & bar". Le '&' remplace le ';' c'est ça? Si oui, pourquoi ne pas mettre sur 2 lignes, que ce soit lisible?

          • [^] # Re: Netcat?

            Posté par  (site web personnel) . Évalué à 4. Dernière modification le 10 avril 2019 à 23:31.

            foo;bar => foo est exécuté, puis bar est exécuté une fois que foo est terminé
            foo&bar => foo est exécuté, bar est exécuté
            foo&&bar => foo est exécuté et si ça se passe bien (foo a retourné 0) bar aussi

            Donc notre cas il faut quand même que le netcat soit en écoute avant de pouvoir recevoir un message du réseau. Message qui est ensuite envoyé.

            • [^] # Re: Netcat?

              Posté par  . Évalué à 1.

              Certes, mais

              foo &
              bar

              me semble plus lisible et fait ce que fait foo & bar non?

          • [^] # Re: Netcat?

            Posté par  (site web personnel) . Évalué à 9. Dernière modification le 10 avril 2019 à 23:59.

            une ligne de bash "illisible" (de mon point de vue, ce concentré de caractères sans espaces est pénible à lire du moins) et qui risque de se retourner contre moi, je préfère les 50 lignes de C standard.

            Pour bien connaître (ou avoir connu) les deux, chacun se défend bien en termes d'illisibilité. Pour améliorer les choses quand on programme le shell, il faut utiliser des fonctions dont les noms sont explicatifs, je fais la traduction:

            listen_udp()
            {
              nc -u 12345 -l
            }
            
            sendto_udp()
            {
              # Sur ma version de NC j'ai besoin du -w 0
              #  pour que NC arrête d'essayer de lire STDIN après
              #  la fin du message.
              nc -w 0 -u 127.0.0.1 12345
            }

            Et le programme s'écrit

            listen_udp & echo "le résultat" | sendto_udp

            Cela démarre en arrière-plan (&) un serveur qui écrit tous les messages reçus sur UDP puis envoie un message sur ce serveur.

            Aussi, j'ai appris à me méfier d'echo, et une pratique que j'essaie de faire au max est de toujours utiliser printf, pour éviter les surprises.

            La “bonne pratique” est de n'utiliser echo que sur un texte constant (c'est le cas ici) qui de plus ne commence pas par un tiret. Pour tout le reste on utilise printf en utilisant une chaîne de format constante.

            a doit être lié au fait que je suis un dev qui joue aux admins, et pas un vrai admin

            On a le droit de bien connaître le shell même sans être admin. :-)

            • [^] # Re: Netcat?

              Posté par  . Évalué à 4.

              Pour améliorer les choses quand on programme le shell, il faut utiliser des fonctions dont les noms sont explicatifs

              Je crains que ça ne vaille pour tous les langages, ça :D

              La “bonne pratique” est de n'utiliser echo que sur un texte constant (c'est le cas ici) qui de plus ne commence pas par un tiret. Pour tout le reste on utilise printf en utilisant une chaîne de format constante.

              Le truc, c'est que j'essaie de cultiver des idiomes, et l'usage de printf me semble en être un bon: quand ça pose un problème de performance avéré alors j'utilise autre chose, mais si ce n'est pas le cas, une fonction qui as un comportement bien définit me semble préférable. J'applique la même politique en C et C++, quitte a ne pas utiliser certains conforts, si ça peut rendre mon code plus fiable et portable. Me suis fait avoir quelques fois déjà sur des flous de standard, alors maintenant, je me méfie.

              On a le droit de bien connaître le shell même sans être admin. :-)

              Je fais mon maximum pour être bon dans les deux domaines, mais je n'ai pas la prétention de l'être, ni dans ma spécialité, et encore moins dans ce que je sais ne pas être ma spécialité.
              Il me reste tant à apprendre, et ce n'est pas en me croyant bon que je le deviendrais.

              • [^] # Re: Netcat?

                Posté par  (site web personnel) . Évalué à 3.

                Le truc, c'est que j'essaie de cultiver des idiomes, et l'usage de printf me semble en être un bon: […]

                C'est exact, personnellement je préfère aussi utiliser printf systématiquement. echo n'a presque que des inconvénients… pourtant on l'utilise et le rencontre encore souvent.

                Il me reste tant à apprendre, et ce n'est pas en me croyant bon que je le deviendrais.

                Ce que je voulais dire est que le fait de programmer le shell n'a pas forcément à voir avec celui d'être admin! Les sources qui m'ont fait faire beaucoup de progrès sont la lecture des divers scripts shell qu'on trouve dans FreeBSD notamment.

            • [^] # Re: Netcat?

              Posté par  . Évalué à 1.

              On a le droit de bien connaître le shell même sans être admin. :-)

              Ah rien qu'en disant ça, tu avoue ne pas être admin (ou bossant dans l'exploit /prod) :
              Qu'un admin dise "il connait bien quelque chose", c'est en général astreinte sur astreinte, donc non, aucun admin ne connait bien quoique ce soit

  • # Type=forking

    Posté par  . Évalué à 5.

    Ceci se base sur l'idée que les enfants ne devraient pas se détacher de leur parent, ce qui est également à ma connaissance requis par systemd.

    Pas forcément, voir man systemd.service

    Type=

    Configures the process start−up type for this service unit. One of simple, exec, forking, oneshot, dbus, notify or idle:

    • If set to simple (the default if ExecStart= is specified but neither Type= nor BusName= are), the service manager will consider the unit started immediately after the main service process has been forked off. It is expected that the process configured with ExecStart= is the main process of the service. […]

    • If set to forking, it is expected that the process configured with ExecStart= will call fork() as part of its start−up. The parent process is expected to exit when start−up is complete and all communication channels are set up. The child continues to run as the main service process, and the service manager will consider the unit started when the parent process exits. This is the behavior of traditional UNIX services. […]

    • [^] # Re: Type=forking

      Posté par  . Évalué à 2.

      Intéressant. Du coup, comment ça marche pour relancer le daemon s'il se ferme? Je veux dire, me semble que coup de forker sers à se détacher du parent… c'est rattrapé par le PID1 qui le refourgue à la partie du système qui gère les daemons? Ou peut-être que c'est le PID qui le fait, et donc ça ne pose pas de problème?

      • [^] # Re: Type=forking

        Posté par  . Évalué à 2.

        C'est grace aux cgroup.
        Systemd crée (par défaut) un cgroup pour chaque service, il sait donc quels sont tous les processus qui ont été lancé par le service. Si ce dernier ne s'arrête pas correctement (typiquement grace à la commande ExecStop), tu peux faire un systemctl kill qui enverra un signal à tous les processus du cgroup associé au service.

        • [^] # Re: Type=forking

          Posté par  . Évalué à 2.

          Autrement dit, c'est lié à ce passage là de moi-même:

          Dans les connaissances que je n'ai pas et les besoins que j'ignore avoir, il y a clairement les cgroups et SElinux, et je sais que systemd gère déjà tout ça nativement, inutile de me le rappeler.

          En gros, me reste à savoir comment faire ça en shell (si je veux vraiment pouvoir créer une alternative).
          Bon, la ou je suis curieux, c'est sur comment nosh s'y prend, puisqu'il prétend être capable de porter les units systemd, et fonctionner sur du BSD… les BSD implémentent-ils des mécanismes de ce type?
          Si oui, existe-t-il un moyen portable, que ce soit en shell ou en C, d'être équi-fonctionnel?

  • # Void Linux

    Posté par  . Évalué à 2.

    Manifestement, dans les outils cités, il n'y à rien pour gérer les dépendances des services, ni même pour vérifier que tous les pré-requis pour lancer le daemon final sont présents.

    Sur quelle distribution utilises-tu runit ?
    Il me semble que Void Linux utilise runit nativement.

    Cette distribution peut donc être un bon choix si on veut utiliser runit (on peut supposer qu’il est déjà configuré, au moins en bonne partie).

    À défaut, ça peut toujours être intéressant de l’installer sur une machine virtuelle, pour regarder comment runit est configuré dessus. Ou même carrément d’en récupérer la configuration et les unités runit.

    (Tout ça, à moins que tu n’utilises déjà Void Linux et ne parles là que de ce qu’il reste à configurer ; dans ce cas Void Linux serait moins fini que ce que j’aurais pensé.)

    « Le fascisme c’est la gangrène, à Santiago comme à Paris. » — Renaud, Hexagone

    • [^] # Re: Void Linux

      Posté par  . Évalué à 2.

      Sur quelle distribution utilises-tu runit ?

      Debian (avec le paquet runit-sysv, du coup je n'utilise pas vraiment le système d'init, et pour l'anecdote, il existe un paquet runit-systemd, pour utiliser la gestion des daemons de runit au-dessus de systemd, comme quoi systemd n'est pas si monolithique que ça. On est vendredi, c'est permis :D), mais je l'utilise aussi sur Devuan et Void.
      Enfin, j'utilise runsvdir, parce qu'en vrai, à part sur void, je n'utilise pas l'init réellement, bien que je me souvienne avoir tenté de porter une de mes Debian perso sur runit.
      J'avais réussi, mais il restait pas mal de trucs sur lesquels je me basais sur les usines à gaz de scripts init.d de Debian et leurs dépendances spaghetti, vu que je n'avais pas (et n'ai toujours pas, en fait) assez de connaissances sur udev, principalement.

      Il me semble que Void Linux utilise runit nativement.

      Void utilise runit comme système d'initialisation et de gestion des daemons par défaut, oui.

      (Tout ça, à moins que tu n’utilises déjà Void Linux et ne parles là que de ce qu’il reste à configurer ; dans ce cas Void Linux serait moins fini que ce que j’aurais pensé.)

      J'aime beaucoup Void pour plusieurs raisons (déjà, elle implémente runit de base, et de manière minimale ce qui est excellent pour comprendre comment marche le système, contrairement au foutoir debianesque auquel je suis «habitué»… mais en plus, il est possible d'utiliser une variante musl, ce qui séduit vachement mon côté qui veut tout faire différemment des autres), mais elle à plusieurs défauts à mon goût:

      • je n'aime pas son système de paquets. Ou, pour être plus précis, je n'apprécie pas l'absence d'outils digne de ce nom pour se balader dans les paquets… Bien sûr, on peut toujours piper dans less et autres, mais je trouve personnellement qu'aptitude est un argument de poids pour utiliser Debian ou une de ses filles;
      • c'est une rolling release, et même si je n'ai jamais eu de problèmes avec void, je ne suis pas super fan de ce modèle, et je ne baserais jamais des systèmes embarqués sur du Void pour cette raison (Debian ne me dérange pas trop malgré quelques points, mais surtout parce que je la connaît plutôt bien et que je suis confiant en mes capacités de réparer la plupart des problèmes);
      • je m'inspire des scripts de void, mais il sont limités. Le seul exemple de logiciel libre qui me vienne à l'esprit et qui ait un vrai besoin de dépendances, c'est un serveur NFS. Si on prend le paquet nfs-utils de void, on constate que nfs-server dépend de statd qui dépend de rpcbind (via un grep -r "sv check "). Il est probable qu'un système qui démarre un serveur NFS se retrouve donc avec une courte phase de "yoyo" pendant laquelle plusieurs des services vont se lancer pour rien. Et NFS, c'est un schéma de dépendances simple, qui n'implique absolument pas que la machine soit capable d'en contacter une autre… auquel cas les choses pourraient être autrement plus chaotique.

      Tout ceci étant dit, je ne connaît pas tant que ça d'applications qui ont vraiment une forte liste de dépendances. En libre, je ne vois que NFS, et c'est parce que je me suis creusé la tête pour te donner un exemple pas trop mauvais…

      Si je parviens à mettre en place un système assez simple et efficace, il n'est pas dit que je ne le partagerai pas avec les gens de Void, bien au contraire.

      Il faut garder à l'esprit que c'est une petite distro relativement jeune (11 ans…) et peu connue, peut-être que personne n'a eu le temps, la motivation ou l'idée de proposer un tel mécanisme: après tout, une des idées les plus intéressantes de systemd est justement d'avoir une configuration déclarative, c'est à ma connaissance le 1er à le faire sous linux.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.