Aller au contenu
Retour à Apprendre
Systèmes26 juillet 20266 min de lecture

Choisir un système d'init, et pourquoi 0dyssey utilise runit

Le système d'init est le premier processus de la machine et le parent de tous les autres. Voici la propriété sur laquelle nous avons jugé les candidats, ce que runit nous apporte et ce que ce choix a coûté.

Kushagra SharmaFondateur et ingénieur produit

Tout système d'exploitation commence par une base, et la partie de cette base dont on peut le moins se permettre de rater le choix est le système d'init. 0dyssey est construit sur Void Linux, qui utilise runit. Voici le raisonnement, et la moitié qui se généralise : la propriété sur laquelle nous avons jugé les candidats vaut que vous touchiez ou non un jour à Void.

Le système d'init est la fondation, traitez-le comme telle

Le système d'init est le premier processus de la machine et le parent de tous les autres. Il ne disparaît jamais. S'il est complexe, cette complexité vit pour toujours à la racine de votre arbre de processus, et chaque défaillance que vous déboguerez ensuite passera par lui.

systemd est le choix par défaut presque partout, et il fait énormément de choses. C'est précisément la propriété à peser. Il est à la fois système d'init, gestionnaire de services, démon de journalisation, gestionnaire de périphériques, configurateur réseau, suivi de sessions de connexion et planificateur de minuteries, réunis en un tout étroitement couplé qui veut posséder le PID 1 et l'essentiel de ce qui tourne au-dessus. Pour une distribution de bureau généraliste, c'est un compromis raisonnable : cela fonctionne, et presque personne n'a besoin de le lire. Pour une base sur laquelle on veut construire un produit cohérent, c'est beaucoup de comportements que l'on ne maîtrise pas et que l'on ne comprend pas entièrement.

La propriété à juger : l'état est-il lisible ?

La question à laquelle nous revenions sans cesse n'est pas de savoir quel système d'init est le plus rapide ou a le plus de fonctionnalités. C'est de savoir si vous pouvez répondre, depuis la machine elle-même et sans manuel, à trois questions : ce qui tourne, pourquoi cela a démarré et ce qui se passe quand cela meurt.

Un système d'init réussit ce test lorsque son état vit à un endroit que vous pouvez lire : un répertoire, un fichier, un lien symbolique. Il échoue lorsque son état est un graphe de résolution calculé au démarrage à partir de fichiers d'unité, de surcharges, de générateurs et de préréglages, et que le seul moyen d'inspecter le résultat est de demander à l'outil qui l'a calculé. Le second cas n'est pas forcément mauvais, mais il fait de l'outil le seul témoin de son propre comportement.

Un service supervisé est un dossier. Pour l'activer, vous créez un lien symbolique vers ce dossier. Pour le vérifier, vous posez la question. Il n'y a pas d'état caché, pas de générateurs, pas de graphe de résolution de fichiers d'unité : ce que vous avez écrit est ce qui s'exécute.

À quoi ressemble vraiment runit

runit est assez petit pour se lire de bout en bout en un après-midi. Un service est un répertoire contenant un script run. La supervision est un lien symbolique vers le répertoire des services actifs. C'est tout le modèle mental, et il vaut la peine de voir un cycle de vie complet dans un seul bloc.

# un service est un répertoire avec un script run, et rien d'autre. un exemple
# minimal, /etc/sv/sshd/run, tient en trois lignes : fusionner stderr dans stdout, puis exec
# le démon au premier plan pour que runit supervise le processus qu'il a lancé
#!/bin/sh
exec 2>&1
exec /usr/bin/sshd -D

# installer le paquet. xbps est le gestionnaire de paquets de Void
$ sudo xbps-install -S openssh

# l'activer : un lien symbolique place le répertoire dans l'ensemble supervisé
$ sudo ln -s /etc/sv/sshd /var/service/

# demander son état. sv indique s'il tourne, et son pid
$ sudo sv status sshd

# démarrer, arrêter, redémarrer : tout est explicite, tout est synchrone
$ sudo sv restart sshd
$ sudo sv stop sshd

# désactiver la supervision : supprimer le lien symbolique. Il n'y a pas de daemon-reload
$ sudo rm /var/service/sshd

Pas de sections [Unit] / [Service] / [Install]. Pas d'étape de rechargement qui laisse silencieusement la configuration en cours d'exécution désynchronisée du fichier que vous venez de modifier. Un service est activé quand le lien symbolique existe et supervisé quand runit le voit. Le système de fichiers est l'état, ce qui fait de ls un outil de débogage.

Quand vous pouvez lire votre système d'init en un après-midi, vous pouvez raisonner sur chacun de ses modes de défaillance. Pour un système que nous comptons livrer et maintenir, ce n'est pas un luxe. C'est un prérequis, et c'est la raison pour laquelle cette décision a été prise avant presque toutes les autres.

Ce que ce choix a coûté

Aucune base n'est gratuite. Une décision qui mérite d'être documentée dit ce qu'elle a coûté avant d'affirmer ce qu'elle a apporté, voici donc l'addition :

  • runit est inconnu de la plupart des utilisateurs de Linux : notre documentation doit donc porter un poids qu'un système basé sur systemd aurait hérité du reste de l'écosystème.
  • Les projets amont livrent des unités systemd, pas des scripts run pour runit. Tout ce que nous empaquetons et qui suppose systemd est un travail de paquetage que nous faisons nous-mêmes.
  • Le dépôt de paquets de Void est plus petit que celui de Debian ou d'Arch, ce qui nous oblige parfois à compiler nous-mêmes des logiciels amont.
  • Une communauté plus restreinte, c'est moins de réponses à copier-coller à trois heures du matin quand quelque chose casse.

Nous avons accepté les quatre, parce que l'alternative était d'hériter d'un poids que nous aurions passé des années à essayer de retirer.

Il est plus facile d'ajouter avec discernement à une base minimale que de soustraire à une base maximale. Cette asymétrie a tranché.

Pas un fork, une composition

0dyssey n'est pas un fork de Void et n'est l'habillage d'aucun autre système. C'est une composition soignée de couches éprouvées : le noyau Linux, runit pour l'init et la supervision, xbps pour les paquets, i3 pour la gestion des fenêtres, sur une base Void, avec notre propre couche d'expérience utilisateur par-dessus. Chacune fait son travail et passe proprement la main à la suivante.

Cette façon de présenter les choses est délibérée, pas modeste. Un fork hérite de toute la charge de maintenance d'un projet et de sa politique interne. Une composition n'hérite que des interfaces, ce qui laisse chaque couche remplaçable le jour où le raisonnement qui l'a fait choisir ne tient plus. Écrire ce raisonnement est ce qui rend cela possible : une décision que l'on ne peut pas reconstituer est une décision que l'on ne pourra jamais réexaminer.

Il n'y a rien à télécharger. 0dyssey est en développement, et ceci est la trace d'une décision, pas une note de version. Ce que l'on peut publier aujourd'hui, c'est la décision et l'argument qui la sous-tend, ce qui est aussi la partie qui mérite d'être discutée.

Partager cet article

Besoin de faire construire un produit ?

Décrivez le problème avec vos propres mots. Vous aurez une réponse franche sur ce que demande réellement sa construction et sur le déroulement d'une mission.