Un aperçu des composants des moteurs de conteneurs

Sommaire

Histoire des moteurs de conteneurs

Mes connaissances sur l’histoire de la conteneurisation sont assez réduites, car je m’y suis mis assez tardivement. J’ai commencé à me renseigner sur LXC lors de la sortie de la version 2, autour de 2017, alors que Docker venait d’abandonner le support de LXC et était déjà passé sur runc. En m’intéressant à LXC j’ai découvert le travail impressionnant de Stéphane Graber et Christian Brauner sur l’implémentation des espaces de noms du noyau Linux. C’est, selon moi, le travail auquel on doit la paternité de la conteneurisation, bien que FreeBSD avait déjà l’appel système, très ressemblant à ce que font les espaces de noms sous Linux, jail dans les années 2000 (Linux introduira un appel système équivalent, unshare, qu’en 2006, avec la sortie de la version 2.6.16).

Prenons la création de Docker comme point de référence historique.

Avant Docker, il y avait LXC, qui était capable d’isoler des processus et qui disposait d’une interface en ligne de commande. LXC couvrait 100% des capacités d’isolation fournies par les espaces de noms de Linux, ce qui en fit un candidat idéal pour l’intégrer comme composant des premières versions de Docker. Ce dernier a apporté ce qu’il manquait à LXC ; la gestion du réseau, le redémarrage automatique, la gestion de la sortie standard, tout en simplifiant l’utilisation de points de montage, la construction d’une hiérarchie de fichiers racine, et bien d’autres améliorations qui ont largement contribuées à rendre plus accessible la conteneurisation.

Autour de 2015, pendant que Docker devenait populaire, et probablement à cause de l’apparition de moteurs de containers qui répondaient à un besoin que ne couvrait pas Docker, un effort de normalisation est apparu, dirigé par Microsoft, Red Hat, Docker (la société), Huawei et probablement d’autres sociétés qui ne disaient pas leur nom à l’époque, ainsi que quelques individus qui n’affichaient aucune affiliation. La spécification Open Container Format (abrégé “OCF”) est née. Celle-ci engendrera le moteur d’éxécution de conteneurs runc et l’organisation Open Container Initiative (abrégé “OCI”). Quelques mois plus tard, l’OCF sera ré-organisée en l’ensemble des spécifications qu’on connait aujourd’hui : la Runtime Specification et la Image Format Specification.

Parallèlement, la version 1 de Kubernetes est publiée par Google, et on voit naître le moteur de conteneurs rkt, qui vient directement concurrencer Docker.

À partir de 2015, au cours deux ou trois ans, Docker se modularise de plus en plus. Les projets containerd, libnetwork et buildkit naissent de la base de code de Docker, et le dépôt Git de Docker est séparé en deux : un pour l’interface en ligne de commande et un autre pour le démon. Enfin, le projet Moby est créé par Docker (la société), concluant la modularisation de Docker en tout ce qui pouvait être ré-utilisé par d’autres moteurs de conteneurs. Puisque j’ai attribué la paternité de la conteneurisation à LXC, je dois attribuer la paternité de la conteneurisation moderne à Docker.

Une des fonctionnalités fortement demandée par de gros exploitants de conteneurs était leur orchestration. C’est précisément à ce besoin que répondait Kubernetes, qui introduisit plusieurs concepts qui rendirent plus manipulables les applications multi-processus, tout en permettant l’évolutivité de la conteneurisation. Dès ses premières versions, Kubernetes est capable d’utiliser les moteurs de conteneurs Docker et rkt. Rapidement, le projet CRI-O est lancé, avec pour objectif de fournir un moteur de conteneurs plus petit et taillé pour le besoin de Kubernetes. Un peu plus tard, le support pour containerd est ajouté.

Aujourd’hui, grâce à tous les efforts de modularisation de la conteneurisation, nous disposons de normes et d’outils ré-utilisables qui permettent une inter-opérabilité exemplaire.

L’état actuel de l’écosystème

Les normes

  • La Runtime Specification normalise l’environnement d’exécution, la configuration et le cycle de vie d’un conteneur. Cette norme est accompagnée d’une implémentation de référence : runc.

  • La Image Format Specification normalise le format des images à partir desquelles sont créés les conteneurs.

  • La Container Network Interface Specification normalise la configuration, la modularité et l’inter-opérabilité de l’environnement réseau des conteneurs.

  • La Distribution Specification normalise la façon dont sont distribuées les images. Le projet à l’origine de cette spécification est Distribution, un projet donné “à la communauté” par Docker (la société).

Les moteurs d’exécution de conteneurs

Les moteurs d’exécution de conteneurs sont chargés de gérer la configuration et le cycle de vie d’un conteneur. En voici une liste non exhaustive :

  • runc

    Un moteur d’exécution de conteneurs écrit en Go qui a pour objectif d’être l’implémentation de référence de la Runtime Specification.

  • containerd

    Un moteur d’exécution de conteneurs écrit en Go et basé sur runc. Il apporte les fonctionnalités supplémentaires suivantes :

    • Gestion des images (téléchargement, téléversement et stockage).

    • Création automatique des hiérarchies de fichiers racine à partir d’images.

    • Manipulations avancées des conteneurs (gel/dégel et transfert entre hôtes).

    • Extensible par greffons via une API gRPC.

  • crun

    Un moteur d’exécution de conteneurs écrit en C conforme à la Runtime Specification.

  • youki

    Un moteur d’exécution de conteneurs écrit en Rust conforme à la Runtime Specification.

  • CRI-O

    Un moteur d’exécution de conteneurs basé sur runc, qui a pour objectif de répondre spécifiquement aus besoins de Kubernetes. Il sert d’interface, via la CRI, entre les projets conformes aux normes de l’OCI et Kubernetes.

Les moteurs de conteneurs

Les moteurs de conteneurs sont chargés de paramétrer l’environnement et créer, configurer et exécuter des conteneurs.

  • Docker

    Le moteur de conteneur à l’origine de tout cet écosystème.

  • rkt

    Un moteur de conteneurs mort en 2020 après l’annonce de l’abandon du projet CoreOS par Red Hat. Ce projet avait lancé la App Container Specification, une norme très proche de la Runtime Specification et la Image Format Specification.

  • Podman

    Une alternative à Docker qui n’emploie pas de démon central. Souhaite être utilisé en lieu et place de l’interface en ligne de commande de Docker de façon compatible. Ses principes sont très proches de ceux de Docker. Une différence notable est le fait que Podman rassemble plusieurs containers qui doivent partager certains espaces de noms dans des “pods”, un concept similaire aux “pods” de Kubernetes.

Les constructeurs d’images

Comme leur nom l’indique, les constructeurs d’image servent à construire des images.

Les auxilliaires

Dans cette catégorie, j’ai placé des projets qui ne servent pas à grand-chose à eux seuls. Ce sont surtout de bibliothèques logicielles.

  • containers/image

    Une librairie en Go capable de manipuler des images ; téléchargement, téléversement, lecture et écriture.

  • containers/storage

    Une librairie en Go capable de gérer des couches de hiérarchies de fichiers d’images et de conteneurs, et d’exposer, ainsi, la hiérarchie de fichiers d’une image ou d’un conteneur.

  • distribution

    Un dépôt d’images. Il est à la base de la plupart des dépôt publiques d’images : Docker Hub, GitHub Container Registry et GitLab Container Registry entre autres.

  • netavark

    Une librairie en Rust capable de gérer la couche réseau pour des conteneurs. Utilisée par Podman.

  • aardvark-dns

    Un serveur DNS faisant autorité en Rust destiné à répondre à des requêtes DNS provenant de conteneurs.

  • libnetwork

    Une librairie en Go capable de gérer la couche réseau pour des conteneurs. Elle fait partie du projet Moby.

Les outils

  • umoci

    Un logiciel capable de modifier des images.

  • Skopeo

    Un logiciel capable de convertir, télécharger et téléverser des images.

Les inclassables

  • Kubernetes

    Un orchestrateur de conteneurs. On pourrait dire que Kubernetes est à la fois un moteur de conteneurs et un moteur de moteurs de conteneurs. Techniquement, kubelet, un de ses composants, est un pur moteur de conteneurs.

  • K3s

    Une alternative plus légère à Kubernetes qui vise l’embarqué.

  • k0s

    Une alternative plus légère à Kubernetes qui vise à simplifier la création d’une grappe de serveurs.

  • Moby

    Le squelette de Docker. Inutilisable en l’état, mais peut servir de base à d’autres moteurs de conteneurs.