Docker : comment les conteneurs fonctionnent vraiment sous Linux
Sommaire
En bref
- Les conteneurs ne sont pas une primitive Linux unique, mais cinq mécanismes du noyau assemblés : espaces de noms, cgroups, et isolation réseau.
- Les images Docker sont simplement des répertoires que le démon place sur le disque, puis remonte avec `chroot` ou `pivot_root`.
- La conception de Docker présente des compromis architecturaux peu évidents : le démon requiert généralement root, et runc (écrit en Go) doit contourner les limites du langage avec des appels C bas niveau pour gérer les syscalls Linux.
- Le succès de Docker n'a jamais reposé sur la technologie des conteneurs elle-même (chroot existait depuis 20 ans), mais sur l'écosystème : Dockerfile, registre d'images, et expérience développeur unifiée.
Ce que dit la source
L'auteur, en implémentant son propre runtime de conteneurs, découvre que Docker repose sur des choix architecturaux contre-intuitifs. Le système n'est pas une primitive Linux monolithique, mais une combinaison de cinq éléments distincts (espaces de noms, cgroups, isolation réseau) souvent peu documentée. Docker requiert root sur Linux pour l'accès aux API noyau, les images sont des répertoires ordinaires, et le runtime runc doit jongler avec les contraintes du Go (runtime multi-thread natif, absence de `fork` véritable).
- Les conteneurs sont des processus Linux avec restrictions, pas des entités kernel isolées : vous pouvez retrouver le processus dans `/proc`.
- `runc`, le runtime Docker écrit en Go, contient un module C qui s'exécute avant l'initialisation du runtime Go pour faire les appels syscall bas niveau que Go ne peut pas gérer seul dans un environnement multi-thread.
- Go n'a pas de vrai `fork`, donc runc le simule en relançant `/proc/self/exe` avec un argument de ligne de commande spécifique pour identifier le processus enfant.
- Les images Docker sont des répertoires ordinaires téléchargés et placés sur le disque ; le conteneur devient le processus lancé après un `chroot` ou `pivot_root` vers ce répertoire.
- La configuration réseau des conteneurs rootless doit réimplémenter toute la pile réseau en espace utilisateur pour offrir les mêmes fonctionnalités, ce qui ajoute de la complexité.
Dans les commentaires
Débat équilibré, axé sur la nuance technique. Si beaucoup reconnaissent la justesse des observations, plusieurs commentateurs soulignent que ces « bizarreries » sont en réalité des décisions architecturales sensées face à l'évolution du noyau Linux. Le créateur de Docker (Solomon Hykes) intervient brièvement, donnant du crédit au ton exploratoire sans défendre chaque choix.
- Plusieurs commentateurs font remarquer que décrire Docker comme « bizarre » ne reflète pas vraiment les compromis : chaque élément listé (root requis, runtime Go, absence de daemon) est soit une conséquence logique des capacités du noyau à l'époque, soit un choix de conception raisonnée pour offrir une bonne expérience utilisateur.
- Un commentateur qui a contribué à runc note que dire qu'il est « écrit en Go » est techniquement inexact : le code critique est en C, le module Go encapsulant simplement la logique de haut niveau.
- Plusieurs citations pointent que le vrai succès de Docker n'était pas la technologie des conteneurs (chroot fonctionnait depuis des années), mais le package complet : Dockerfile, registre centralisé d'images, et écosystème.
- Un autre commentateur soulève que les conteneurs n'ont jamais offert une sécurité suffisante pour les environnements mutualisés, forçant les déploiements en production à ajouter une couche d'isolation supplémentaire (KVM, gVisor), ce qui crée une redondance inefficace.
- Quelques commentateurs mentionnent des alternatives plus légères : Podman (sans daemon, sans root) et d'autres runtimes expérimentaux (Range, bocker) qui éliminent certaines bizarreries en redessinant les priorités.
Alternatives citées : Podman (mentionné plusieurs fois, particulièrement la version rootless pour éviter le daemon et root), bocker (100 lignes de bash pour démontrer les mêmes principes), Range (daemon-free, registry-free), gVisor et KVM pour isolation multi-tenant en production.
Notre lecture
Article d'exploration honnête et utile pour comprendre ce qui se cache sous Docker. Les observations sont justes, mais elles décrivent des choix architecturaux defensibles plutôt que des erreurs : le succès de Docker a toujours reposé sur l'écosystème et l'expérience développeur, pas sur une innovation au niveau kernel. Pour une équipe ayant opéré Docker en production, rien de nouveau ; pour les développeurs junior découvrant les internals, c'est pédagogique. Les alternatives légères (Podman rootless, Range) existent maintenant pour éviter certains de ces compromis, mais le coût de migration est à peser. Intéressant pour la curiosité technique, pas de conséquence immédiate sur les choix d'infrastructure existants.