Étude — systemd : qualités, défauts, alternatives ; et le comparatif avec le launchd d’Apple
Statut : note de travail. Ne fait autorité sur rien ; sert de matière à une décision ultérieure. Aucune décision n’est prise ici.
Pourquoi maintenant. ADR-005 (« Intégration systemd comme socle système, D-Bus
optionnel ») fait de systemd une dépendance dure et nomme sd-bus, sd-event,
sd-notify, sd-journal, sd-id128, libudev, logind et systemd --user. Dans les
faits, Air a réimplémenté les protocoles en Rust pur sans jamais lier les
bibliothèques C, et trois de ces intégrations (sd-bus, logind, systemd --user)
ne sont pas commencées. Par ailleurs, le projet anticipe depuis longtemps un superviseur
maison : le trait ServiceHost d’air-service est explicitement le seam
v1 (systemd) → v2 (air-launchd), et ADR-041 (« Coexistence /etc ») renvoie
l’enforcement dur à air-launchd. Avant de trancher quoi que ce soit, il faut savoir ce
qu’on garde, ce qu’on rejette, et ce que les autres ont appris.
1. systemd — ce qu’il fait réellement bien
À charge de reconnaître ce qui, dans systemd, relève de l’avancée technique et non de la mode. Beaucoup de critiques portent sur son périmètre, rarement sur ces points-là.
1.1 La supervision par cgroups — le vrai saut
C’est le différenciateur, et de loin le plus sous-estimé. Un service = un cgroup. Le noyau, et non l’init, tient la liste des processus appartenant au service. Conséquences :
- l’arrêt est fiable. Un démon qui double-forke, qui
setsid(), qui laisse des enfants orphelins : tout est dans le cgroup, tout est tué. Les scripts SysV ne savaient pas faire — ils traquaient un PID dans un fichier, et se trompaient dès qu’un processus s’échappait ; - la comptabilité est exacte (CPU, mémoire, I/O par service) ;
- les limites sont applicables sans coopération du service ;
- l’attribution des logs est infalsifiable :
_SYSTEMD_UNITest renseigné par le noyau via le cgroup, un service ne peut pas mentir sur son identité dans le journal.
Aucune alternative citée en §3 n’offre l’équivalent avec la même rigueur.
1.2 Le hardening déclaratif
Sans doute la fonctionnalité la plus utile en pratique, et la moins discutée dans les
polémiques. On durcit un service sans écrire une ligne de code :
NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp, PrivateDevices,
RestrictAddressFamilies, CapabilityBoundingSet, SystemCallFilter (seccomp),
MemoryDenyWriteExecute, DynamicUser, ProtectKernelModules, namespaces divers.
Un service tiers non coopératif devient confinable par configuration. C’est un modèle
dont Air ferait bien de s’inspirer — d’autant qu’Air a déjà les briques (air-sandbox,
ADR-112 : compilateur seccomp maison et Landlock, en Rust safe).
1.3 L’activation à la demande et le readiness typé
- Socket activation : le socket est créé par l’init, le service ne démarre qu’au premier client, et les dépendances de démarrage s’effacent (le client bloque sur le socket au lieu d’échouer). Idée empruntée à launchd, ce que Poettering a reconnu explicitement dès « Rethinking PID 1 » (2010).
Type=notify: le service dit lui-même « je suis prêt » viasd_notify. Cela supprime la classe de bugs dessleep 5et des courses sur fichier PID.- Watchdog : le service doit battre régulièrement, sinon il est redémarré.
1.4 Le modèle déclaratif et l’uniformité
Une unité est un fichier INI parsable, introspectable, diffable, générable. Un script shell ne l’est pas. Surtout, la même unité fonctionne sur toutes les distributions : c’est un effet de réseau considérable, et la principale raison de l’adoption — un éditeur livre une unité, pas sept scripts d’init.
1.5 Le reste, en bref
- Ordonnancement explicite (
Wants/Requires/After/Before) et parallélisation du démarrage. - Journal structuré : des champs, pas des lignes de texte à regexper ; corrélation par unité, par démarrage, par curseur.
- Timers : dépendances, persistance (
Persistent=truerattrape une exécution manquée), délais aléatoires — ce que cron ne sait pas faire. systemd --user: les mêmes primitives pour la session utilisateur.logind: sessions, sièges (seats), inhibiteurs — la base sur laquelle reposent tous les environnements de bureau modernes.- Introspection :
systemd-analyze blame,critical-chain,systemctl statusqui agrège état et logs.
2. systemd — ce qu’on lui reproche
Il faut séparer trois registres, souvent mélangés dans les débats.
2.1 Critiques techniques fondées
- Périmètre. systemd a absorbé la résolution DNS (
resolved), le réseau (networkd), l’horloge (timesyncd), les comptes (homed), le boot (systemd-boot), l’initrd… La qualité est inégale :systemd-resolveden particulier a accumulé les reproches (comportements de repli surprenants, gestion du DNSSEC). Chaque composant absorbé est une surface de plus. - Complexité sémantique du langage d’unité.
Requires/Requisite/BindsTo/PartOf/Wantsont des sémantiques proches mais distinctes, et l’ordonnancement (After) est orthogonal à la dépendance (Requires) — confusion classique. Les cycles d’ordonnancement se diagnostiquent mal. - Journal binaire. Format indexé, donc rapide et structuré, mais corruptible, et
inaccessible sans
journalctl. Beaucoup d’exploitants rebranchent un syslog derrière, ce qui annule une partie du bénéfice. - Couplage de fait. Les composants sont modulaires en binaires, mais l’usage réel
suppose D-Bus (le contrôle de PID 1 passe par
sd-bus),journald,udev. « D-Bus est optionnel » est vrai sur le papier, pénible en pratique. - Surface de PID 1. Même si beaucoup de fonctions vivent hors du PID 1, le processus reste gros pour un composant dont la défaillance est fatale à la machine. L’historique de CVE n’est pas vide.
- Debug du démarrage précoce (initrd, avant le journal) reste ingrat.
- Adhérence Linux forte (cgroups, namespaces,
epoll,signalfd) : non portable. Pour Air, ce point est neutre, voire favorable — ADR-004 assume Linux-only.
2.2 Ruptures de comportement mal vécues
Réelles, mais souvent défendables techniquement : KillUserProcesses=yes par défaut
(systemd 230, 2016) qui a cassé nohup/screen ; les noms d’interfaces réseau
« prévisibles » (utile, mais rupture brutale) ; tmpfiles.d qui efface des répertoires
qu’on croyait à soi. Le grief n’est pas la décision, c’est la façon dont elle a été
imposée.
2.3 Griefs culturels — à connaître, à ne pas surpondérer
- « Viole la philosophie Unix. » Argument faible en l’état : systemd est bien découpé en binaires. Le reproche pertinent est le couplage, pas la monolithie.
- Gouvernance perçue comme peu à l’écoute, et effet de verrouillage de
l’écosystème (GNOME dépend de
logind; s’en passer coûte cher — cf.elogind, extraction delogindmaintenue par les distributions sans systemd).
Ce qu’il faut en retenir pour une décision : les critiques sérieuses portent sur le périmètre et le couplage, presque jamais sur les mécanismes du §1. Un remplaçant crédible doit reprendre les mécanismes et refuser le périmètre.
3. Les alternatives (hors scripts rc.d)
3.1 Superviseurs purs — « faire une seule chose »
| Projet | Auteur / distribution | Caractère |
|---|---|---|
| daemontools | D. J. Bernstein | L’ancêtre (1990s). Un répertoire par service, run/log. Simplicité radicale, aujourd’hui historique. |
| runit | Void Linux | Héritier direct de daemontools, PID 1 inclus, ~ quelques milliers de lignes. Robuste, trivial à comprendre. Pas de socket activation, pas de cgroups, dépendances rudimentaires. |
| s6 / s6-rc | Laurent Bercot (skarnet) | La conception la plus rigoureuse du lot : composable, primitives minimales et orthogonales, s6-rc ajoute un graphe de dépendances compilé, s6-linux-init fait le PID 1. Courbe d’apprentissage raide, écosystème réduit, documentation dense mais exigeante. À lire absolument avant de concevoir un superviseur. |
| perp, nosh | — | Confidentiels. nosh est étonnamment complet et porte une culture BSD assumée. |
3.2 Systèmes d’init complets
| Projet | Où | Ce qu’il apporte / ce qui manque |
|---|---|---|
| OpenRC | Gentoo, Alpine | Dépendances, démarrage parallèle, portable (BSD). Scripts shell : lisible, mais on retrouve les limites de l’impératif. Supervision déléguée (supervise-daemon), suivi des processus sans cgroups par défaut. |
| Dinit | Chimera Linux | Init et superviseur en C++, dépendances, conçu explicitement comme un systemd léger. Le plus crédible des « petits » aujourd’hui. |
| GNU Shepherd | Guix | Écrit en Guile : la configuration est du code Scheme, donc programmable. Original et cohérent avec Guix ; adhérence forte à son écosystème. |
| finit | Embarqué | Léger, orienté systèmes contraints. |
| procd | OpenWrt | Superviseur + hotplug + ubus (leur bus léger, à la place de D-Bus). Intéressant comme preuve qu’on peut avoir un bus de contrôle sans D-Bus. |
| BusyBox init | Embarqué | Minimal, sans supervision réelle. |
| Upstart | Ubuntu (abandonné) | Modèle événementiel plutôt que dépendanciel. Mort, mais l’échec est instructif : l’événementiel pur rend l’état global difficile à raisonner. |
| SMF | Solaris, aujourd’hui illumos | Service Management Facility (2005) : manifestes XML, graphe de dépendances, « restarters » enfichables, intégration au diagnostic matériel, instantanés de configuration avec retour arrière. Très en avance sur son temps ; à étudier pour ses idées, pas pour son ergonomie. |
3.3 Le cas des conteneurs
tini, dumb-init, s6-overlay ne sont pas des inits système : ils existent parce qu’un
PID 1 doit moissonner les zombies et propager les signaux, et que rien d’autre ne
le fait dans un conteneur. Utile comme rappel du noyau irréductible du rôle.
3.4 Ce qu’aucune alternative n’offre
En l’état, aucune ne fournit simultanément : le hardening déclaratif par service
(§1.2), la supervision par cgroups v2 (§1.1), un logind intégré, et l’uniformité
inter-distributions. C’est précisément pourquoi systemd n’est pas délogé, indépendamment
de ce qu’on pense de lui.
4. systemd contre launchd (celui d’Apple)
Levée d’ambiguïté — de quel
launchdon parle. Dans toute cette section, « launchd » désigne le launchd d’Apple, le PID 1 de macOS. Il ne s’agit pas d’air-launchd, le futur superviseur d’Air, qui n’existe pas encore et dont le nom est seulement réservé (ADR-041 « Coexistence/etc», et le seamServiceHostd’air-service). Le rapprochement des noms est un hommage, pas une équivalence : rien de ce qui suit ne préjuge de ce que feraair-launchd.
launchd (Apple, apparu avec Mac OS X 10.4 « Tiger », 2005, conçu par Dave Zarzycki)
mérite l’examen : c’est l’ancêtre conceptuel de l’activation à la demande — systemd lui
a explicitement emprunté la socket activation.
Réserve d’honnêteté. launchd a été publié sous APSL dans les premières versions de Darwin, mais les versions modernes ne le sont plus. Ce qui suit repose sur la documentation publique, les en-têtes et le comportement observable, pas sur le code actuel. À vérifier avant d’en tirer une décision fine.
4.1 Comparaison par axe
| Axe | systemd | launchd |
|---|---|---|
| Rôle | PID 1 + une famille de démons satellites | PID 1 et gestionnaire des domaines utilisateur, un seul programme |
| Description | Fichier INI (.service, .socket, .timer, .target…) | plist (XML), un « job » unique pour tous les cas |
| Modèle mental | Plusieurs types d’unités, un graphe de dépendances | Tout est un job — daemon, agent, tâche périodique : un seul concept |
| Activation | Socket, chemin, D-Bus, calendrier, périphérique | Socket, port Mach / XPC, chemin (WatchPaths, QueueDirectories), calendrier |
| Suivi des processus | cgroups — attribution et arrêt fiables | PID + kqueue ; pas d’équivalent robuste au cgroup kill |
| Readiness | Type=notify (sd_notify) | Implicite (le service écoute son socket / son port Mach) |
| Sessions utilisateur | systemd --user, monde partiellement distinct | Domaines (system, user, gui) — modèle homogène et mieux pensé |
| Journalisation | journald, structuré, binaire | ASL puis unified logging (os_log) — composant séparé |
| Confinement | Déclaratif dans l’unité (seccomp, namespaces, capabilities) | Hors du plist : profils sandbox (Seatbelt), entitlements, signature de code |
| Contrôle | sd-bus / D-Bus | Ports Mach / XPC |
| Périmètre | Large et croissant (DNS, réseau, horloge, boot…) | Étroit — launchd ne fait pas DNS ni réseau |
| Ouverture | Open source, écosystème vaste | Propriétaire de fait, spécifique à Apple |
4.2 Ce que launchd fait mieux
- L’unicité du modèle. Un seul concept — le job — couvre démons système, agents utilisateur, tâches périodiques et services à la demande. systemd multiplie les types d’unités et sépare imparfaitement le monde système du monde utilisateur.
- L’activation par IPC, native. Un client ouvre une connexion XPC : le service est démarré par ce seul fait, sans qu’il ait à connaître launchd. C’est plus propre que l’activation D-Bus de systemd, parce que l’IPC et l’activation sont pensés ensemble plutôt qu’assemblés après coup.
- Le service peut ne jamais tourner. Le design pousse le paresseux à l’extrême : démarrage à la première sollicitation, arrêt quand il n’y a plus rien à faire.
- La retenue de périmètre. launchd ne s’est pas mis à faire du DNS.
- L’ergonomie développeur : un service XPC s’embarque dans le bundle d’une application, avec son cycle de vie géré.
4.3 Ce que systemd fait mieux
- Le suivi et l’arrêt des processus (cgroups) — l’écart est net et structurel.
- Le confinement déclaratif : chez Apple, le durcissement vit ailleurs (profils sandbox, entitlements, signature). C’est plus fragmenté ; on peut lancer un job sans le confiner, et rien ne le rappelle.
- La comptabilité et les limites de ressources.
- Le journal structuré et corrélé à l’unité, infalsifiable via le cgroup.
- Les timers persistants avec rattrapage.
- L’ouverture : documentation, écosystème, réutilisabilité. launchd n’est pas réutilisable hors d’Apple.
4.4 Ce qu’on reproche à launchd
Diagnostic historiquement pauvre (messages d’erreur peu exploitables), rupture d’interface
de launchctl (l’API historique dépréciée au profit d’un modèle par domaines, migration
douloureuse), plist XML verbeux, et une documentation publique qui a longtemps été
maigre.
5. Ce qu’Air peut en retenir
Rien n’est décidé ici ; ce sont les éléments à mettre sur la table.
À reprendre.
- Le suivi par cgroup v2, sans équivalent. C’est ce qui rend l’arrêt d’un service fiable et l’attribution des logs infalsifiable.
- Le confinement déclaratif par service — et Air part avec un avantage :
air-sandbox(ADR-112) fournit déjà un compilateur seccomp maison et Landlock, en Rust safe. Là où systemd fait bien et launchd fait ailleurs, Air peut faire mieux et sûrement. - Le readiness explicite plutôt que les courses sur fichier PID :
air-servicele fait déjà via le protocolesd_notify, sans lier libsystemd. - L’activation à la demande pensée avec l’IPC, à la launchd plutôt qu’à la systemd. Air a les briques : capability = fd (ADR-010), AirCom en SEQPACKET avec passage de fd. Un service AirCom démarré par le fait qu’un client ouvre un canal serait l’équivalent propre de l’activation XPC.
- Le modèle homogène de launchd (un seul concept, des domaines) plutôt que la prolifération de types d’unités.
À éviter.
- L’absorption de périmètre. C’est le reproche le plus solide fait à systemd.
- Le journal binaire fragile comme unique voie.
- Un langage de description qui dérive vers des dizaines de directives à sémantique subtile. Air a déjà tranché en faveur de la configuration binaire (ADR-073), ce qui change la donne : le schéma est typé, versionné, et le codec texte n’est fourni que pour les autres.
- Le couplage à un bus généraliste pour le contrôle.
procd/ubussur OpenWrt montre qu’un bus de contrôle léger et dédié suffit.
Questions ouvertes, à trancher explicitement.
sd-bus: Air doit-il parler le protocole D-Bus pour piloter systemd,logind, NetworkManager ? Réimplémenter D-Bus en Rust pur pour cela, alors qu’ADR-001 refuse D-Bus comme transport natif, est une tension à assumer et non à subir.logind: intégrer l’existant ou écrire l’équivalent Air ? Les distributions sans systemd maintiennentelogind, une extraction delogind— preuve que c’est faisable, et qu’aucune n’a voulu le réécrire.air-launchd: quel périmètre exact ? Superviseur seul, ou superviseur + activation- confinement ? La réponse détermine si ADR-005 reste une intégration ou devient une transition.
- Coexistence. Tant qu’Air tourne sur une distribution systemd, les deux
superviseurs cohabitent. ADR-041 (« Coexistence
/etc») a déjà rencontré le problème.
Références à consulter avant décision
- Lennart Poettering, « Rethinking PID 1 » (2010) — le texte fondateur, où l’emprunt à launchd est explicite.
- Documentation
skarnetde s6 — la réflexion la plus rigoureuse sur ce qu’est une primitive de supervision. - Documentation Apple sur les domaines
launchdet le cycle de vie XPC. - SMF (illumos) pour ses instantanés de configuration et ses restarters enfichables.
elogind— ce que coûte réellement l’extraction delogind.
Licence du document : MPL 2.0 Statut : note de travail, sans autorité.