Quis custodiet ipsos custodes?

Mais qui gardera ces gardiens ?

Où il sera question de Linux, de processus, de conteneurs et de choses gravitant autour.

Processus et daemon

Un serveur regroupe des process, et le premier d’entre eux, celui avec le pid 1 a la responsabilité de lancer tous les autres lors du démarrage.

Certains sont des daemons, des programmes qui tournent en tache de fond, sans interaction directe. Un daemon a la responsabilité d’abandonner ses privilèges, de changer d’utilisateur et de racine (chroot), de causer dans un journal, de noter son PID, et de se détacher, de que décrit si bien Zed Shaw dans Lust.

Init

Historiquement, le rôle d’init est dévolu à init.d, qui accuse méchamment le poids de son âge.

Son principe, finalement simpliste alors qu’il se prétendait simple, est que chaque service est lancé par un script shell, en répondant à quelques commandes : start, stop, status, restart, reload.

Dans les faits, les efforts de l’application sont laborieux, et la qualité de ces scripts est variable pour des applications packagés par le système. Pour des applications métiers, la qualité est tout simplement atroce. Le shell n’a tout simplement pas les commandes nécessaires, et le nébuleux start-stop-daemon est une punition à débuguer.

Il y a eut un peu de tuning, comme le passage de bash à dash pour grappiller du temps, et des efforts de parallélisation. Rien qui n’a pu sauver un init.d finalement en phase terminale.

Superviseur

Des tentatives laborieuses ont été explorées, côté utilisateur, comme daemontools ou supervisor. Ces bricolages permettent de se passer de la danse du daemon, et de se contenter de lancer directement l’application, l’emballage se chargeant du reste. Deux drames UNIX ont perturbé cette volonté de simplification :

  • Pour utiliser des ports réseaux < 1024, il faut être root, par ce que.
  • Un utilisateur ne peut pas changer d’utilisateur, ça, c’est du plus facile à justifier. Mais si vous pouvez utiliser un superviseur, qui tourne avec l’utilisateur root, paf, vous pouvez lancer des commandes en son nom.

L’idée du superviseur n’a jamais été traitée complètement, et ces outils inaboutis finiront par vous mordre, tôt ou tard. Supervisor, le meilleur des produits disponibles, dépend de bibliothèques mortes depuis des années, impose des rechargements par grappe, et utilise des actions bien séquentielles.

Pourtant, le Procfile, un simple format déclaratif, est devenus un standard de fait, et est maintenant sanctifié par les 12 facteurs , par le chapitre VI précisément.

Au-delà de chroot

Pour limiter la possibilité de faire des bêtises, un serveur doit avoir un utilisateur, un chroot si on est poli, et … c’est à peu près tout, une limitation sur le nombre de fichiers ouvert? Depuis peu, d’autres possibilités de restrictions sont apparues, comme Apparmor/SELinux, les cgroups, les namespaces, seccomp, les capabilities … Plein de très belles choses permettant de cloisonner proprement les applications. Techniquement, c’est à l’application de gérer tout ça, ou presque, seules les cgroups sont faciles à manipuler depuis l’extérieur.

Plutôt que d’espérer vainement que les applications gèrent proprement toutes ces fonctionnalités, il est nettement plus efficace de reprendre l’idée simpliste des superviseurs, et d’emballer chaque process.

Cette approche, qui sépare l’application de l’isolation de son contexte, permet d’auditer simplement la sécurité, et d’avoir des politiques systématiques. LMCTFY, “Laisse-moi contenariser ça pour toi”, comme on disait chez Google, pionnier de cette approche.

Il suffit de rajouter un système de fichier par couche pour avoir un chroot propre qui prends peu de place, et voilà, vous avez un système de conteneur.

La collision avec Systemd

Parallèlement avec l’apparition des outils systèmes permettant la création des containers est arrivé Systemd, le nouvel init standard pour Linux.

Après quelques concurrents timides à init.d, Systemd a débarqué avec son gros bulldozeur, en choisissant de remettre à plat la fonction d’init, en incluant la supervision et moult fonctions liées. Avec une diplomatie brutale, peu de respect pour les dogmes, et une grande ambition, Systemd est arrivé à se faire haïr comme peu de logiciels avant. En plus, il est promu (et développé) par Red Hat.

Mais bon, les réécritures timides d’init.d n’avait aucune chance, Upstart s’étant vautré, il ne restait plus beaucoup d’alternatives. L’apparition du Cloud a forcé le destin, par ce qu’il consomme énormément d’init, et annihile le culte incompréhensible du dieu uptime. Il est indispensable d’avoir des cycles de start/stop avec les dépendances qui vont bien, rapides et prévisibles.

Debian a sifflé la fin de la récré en incluant systemd malgré le peu d’enthousiasme de ses mainteneurs, suivi par Ubuntu qui a ainsi acté la mort du pénible Upstart.

Le choc avec Docker

Systemd a débloqué plein de choses, mais il a renâclé sur la notion de conteneur, son nspawn étant officiellement un jouet “for debugging, testing and building”. C’est ballot.

Docker a démontré que les outils systèmes étaient valide pour créer des conteneurs, sans suivre la fausse bonne idée qu’est LXC.

Docker, grisé par son succès pense qu’il va être le prochain init, et qu’il faut une guerre ouverte avec Systemd. “Je dis non à tout patch spécifique à systemd” voilà la signature de Jess Frazelle, core dev charismatique et influente, sur son étiquette pour une conférence Dockercon. D’ailleurs, elle qualifie Systemd de 🍑

Forcé à faire des concessions par les applications s’utilisant (ou son concurrent, Rkt), Docker a été contraint d’écrire des specs, Open Containers,plutôt que de tout défoncer à chaque release majeur. Fair-play, ils ont créé une implémentation de référence, runc, qu’ils utilisent maintenant comme couche basse pour leur outil (depuis la 1.11).

Systemd, surtout dans sa version Debian stable (Jessie, donc) n’implémente pas toutes les possibilités d’isolation du kernel Linux, mais collabore très bien avec runc, qui est par concept peu intrusif et plus facile à mettre à jour.

Le déplacement du conflit

Systemd et Docker sont en fait très proche : ils permettent de manipuler des process sur un serveur.

La notion d’application, qui n’a jamais vraiment été autonome est maintenant remplacé par une composition de services. Il est primordial que cette composition soit la même en dev, en test, en préprod et en production.

Autre grande évolution conceptuelle, la notion de serveurs, qu’ils soient virtuels ou “bare metal”, est en train de fondre. Pour pouvoir prolonger la densification, utiliser toujours plus de ressources, et profiter de la fluidité du Cloud, il ne faut plus lier les process à un serveur. Une application est composée d’une arborescence de services. Il y a maintenant un pool de ressources qui seront alloués par un orchestrateur, responsable de palier au crash des serveurs, et de recâbler les services entre eux, de manière dynamique.

Docker est le standard de fait pour la conteneurisation. Docker-Compose est bien placé pour la description de compositions, et Docker, dans sa version 1.12 a décidé de s’attaquer à la couche suivante, avec Docker-Swarm, ce qui a fait hurler tous les produits positionnés sur cette couche-là, la seule permettant de proposer des produits financièrement viables. Docker s’est attaqué ainsi à Kubernetes, du dieu Google, avec un produit mal fini.

Entre cet affront, le clash avec Systemd, le refus de se brimer en suivant des specs, de stabiliser son cycle de vie, des drames de harcèlement moral en interne et surtout l’importance que représente cette nouvelle étape dans le développement informatique, il va y avoir un drame.

Comme un fork.

blogroll

social