- La vue du système de fichiers dans les processus conteneurisés
- Le rôle du Mount Namespace
- Images de conteneurs et rootfs
- Noyau partagé et dépendances d’application dans les conteneurs
- Le concept de couches dans les images de conteneurs
- Conception incrémentale des couches dans les images de conteneurs
- Superposition dans les conteneurs
- Avantages de la conception en couches des images de conteneurs
- L’impact des images de conteneurs sur les workflows de développement logiciel
La vue du système de fichiers dans les processus conteneurisés
À quoi ressemble le système de fichiers pour les processus s’exécutant à l’intérieur d’un conteneur ? On pourrait immédiatement penser que cela concerne le Mount Namespace : les processus à l’intérieur d’un conteneur devraient voir un système de fichiers complètement indépendant. Ainsi, ils peuvent effectuer des opérations dans les répertoires du conteneur, comme /tmp, sans aucune influence de la machine hôte ou d’autres conteneurs. Est-ce réellement le cas ?
Le rôle du Mount Namespace
Le Mount Namespace fonctionne légèrement différemment des autres namespaces : son effet sur la vision du système de fichiers par le processus conteneurisé ne s’active qu’avec une opération de montage. Cependant, en tant qu’utilisateurs ordinaires, nous souhaitons un scénario plus convivial : à chaque création d’un nouveau conteneur, nous voulons que le processus conteneurisé voie un système de fichiers qui soit un environnement isolé, plutôt qu’hérité de l’hôte. Comment y parvenir ? Il n’est pas difficile d’imaginer que nous pourrions remonter l’intégralité du répertoire racine « / » avant de démarrer le processus conteneurisé. Grâce au Mount Namespace, ce montage serait invisible pour l’hôte, permettant au processus conteneurisé de fonctionner librement à l’intérieur. Dans le système d’exploitation Linux, il existe une commande appelée chroot qui peut accomplir cette tâche facilement dans un shell. Comme son nom l’indique, elle vous aide à « changer de système de fichiers racine », redirigeant le répertoire racine du processus vers un emplacement spécifié.
Images de conteneurs et rootfs
En réalité, le Mount Namespace a été inventé sur la base d’améliorations continues de chroot et est le premier Namespace sous Linux. Pour rendre ce répertoire racine plus « réel » pour les conteneurs, nous montons généralement un système de fichiers complet d’un système d’exploitation sous cette racine, comme une ISO Ubuntu 16.04. Par conséquent, après le démarrage du conteneur, exécuter ls / à l’intérieur du conteneur révèle tous les répertoires et fichiers d’Ubuntu 16.04. Ce système de fichiers monté sur le répertoire racine du conteneur, fournissant un environnement d’exécution isolé pour les processus conteneurisés, est appelé « image de conteneur ». Il porte également un terme plus technique : rootfs (root file system). Le /bin/bash exécuté après être entré dans le conteneur est le fichier exécutable du répertoire /bin, complètement distinct du /bin/bash de l’hôte. Vous devriez maintenant comprendre que le principe fondamental des projets Docker consiste essentiellement à configurer les Linux Namespace pour le processus utilisateur à créer, à définir des paramètres Cgroups spécifiques et à changer le répertoire racine (Change Root) du processus. Ainsi, un conteneur complet est né.
Noyau partagé et dépendances d’application dans les conteneurs
Cependant, Docker préfère utiliser l’appel système pivot_root pour la dernière étape du changement, en recourant à chroot si le système ne supporte pas pivot_root. Bien que ces deux appels système aient des fonctionnalités similaires, il existe des différences subtiles. De plus, il est essentiel de clarifier que rootfs ne comprend que les fichiers, configurations et répertoires d’un système d’exploitation, mais pas le noyau. Sous Linux, ces deux parties sont stockées séparément, l’image du noyau d’une version spécifique n’étant chargée qu’au démarrage. Par conséquent, rootfs ne contient que la « coque » du système d’exploitation, pas son « âme ».
Où se trouve donc « l’âme » du système d’exploitation pour les conteneurs ? En réalité, tous les conteneurs d’une même machine partagent le noyau du système d’exploitation hôte. Cela signifie que si votre application doit configurer des paramètres du noyau, charger des modules supplémentaires du noyau ou interagir directement avec le noyau, vous devez noter que ces opérations et dépendances ciblent le noyau du système d’exploitation hôte, qui est une « variable globale » pour tous les conteneurs de cette machine. C’est l’un des principaux inconvénients des conteneurs par rapport aux machines virtuelles : ces dernières disposent non seulement d’un matériel simulé comme bac à sable, mais exécutent également un système d’exploitation invité complet dans chaque bac à sable pour les applications. Néanmoins, grâce à l’existence de rootfs, les conteneurs possèdent une caractéristique importante largement vantée : la cohérence.
Le concept de couches dans les images de conteneurs
Qu’est-ce que la « cohérence » des conteneurs ? En raison des différences entre les environnements cloud et locaux, le processus d’empaquetage des applications a toujours été l’une des étapes les plus « douloureuses » lors de l’utilisation de PaaS. Cependant, avec les conteneurs, ou plus précisément avec les images de conteneurs (c’est-à-dire rootfs), ce problème a été élégamment résolu. Puisque rootfs empaquette non seulement l’application mais l’intégralité des fichiers et répertoires du système d’exploitation, il encapsule toutes les dépendances nécessaires à l’exécution de l’application. En fait, pour la plupart des développeurs, leur compréhension des dépendances d’application s’est limitée au niveau du langage de programmation, comme Godeps.json pour Golang. Cependant, un fait longtemps négligé est que, pour une application, le système d’exploitation lui-même est la « bibliothèque de dépendances » la plus complète dont elle a besoin pour fonctionner.
Avec la capacité des images de conteneurs à « empaqueter le système d’exploitation », cet environnement de dépendance fondamental devient enfin partie intégrante du bac à sable de l’application. Cela confère aux conteneurs leur cohérence tant vantée : que ce soit sur une machine locale, dans le cloud ou ailleurs, les utilisateurs n’ont qu’à décompresser l’image du conteneur pour recréer l’environnement d’exécution complet nécessaire à l’application.
Conception incrémentale des couches dans les images de conteneurs
Cette cohérence au niveau du système d’exploitation comble le fossé entre le développement local et les environnements d’exécution distants pour les applications. Cependant, vous avez peut-être remarqué un autre problème délicat : devons-nous recréer rootfs à chaque fois que nous développons une nouvelle application ou mettons à jour une application existante ? Une solution intuitive pourrait consister à sauvegarder un rootfs après chaque opération « significative » lors de sa création, permettant aux collègues d’utiliser le rootfs dont ils ont besoin. Cette solution n’est cependant pas évolutive. La raison en est que si les collègues modifient ce rootfs, il n’y a plus de relation entre l’ancien et le nouveau rootfs, ce qui entraîne une fragmentation extrême. Puisque ces modifications sont basées sur un ancien rootfs, peut-on rendre ces changements incrémentaux ? L’avantage de cette approche est que chacun ne doit maintenir que le contenu incrémental par rapport au rootfs de base, plutôt que de créer une « fourche » à chaque modification.
La réponse est bien sûr oui. C’est précisément pourquoi Docker n’a pas suivi le processus standard de création de rootfs lors de l’implémentation des images Docker, mais a plutôt réalisé une petite innovation : Docker a introduit le concept de couches dans la conception de ses images. Chaque opération que les utilisateurs effectuent pour créer une image génère une couche, qui est un rootfs incrémental. Cette idée n’est pas sortie de nulle part, mais a utilisé une capacité appelée Union File System (UnionFS), dont la fonction principale est de monter en union (union mount) plusieurs répertoires provenant de différents emplacements en un seul répertoire.
Superposition dans les conteneurs

Superposition dans les conteneurs
Partie 1 : Couches en lecture seule. Ce sont les cinq couches inférieures du rootfs de ce conteneur, correspondant aux cinq couches de l’image ubuntu:latest. Elles sont montées en lecture seule (ro+wh, c’est-à-dire readonly+whiteout). Chaque couche contient de manière incrémentale une partie du système d’exploitation Ubuntu.
Partie 2 : Couche en lecture-écriture. C’est la couche supérieure du rootfs de ce conteneur (6e3be5d2ecccae7cc), montée en rw, c’est-à-dire lecture-écriture. Avant toute écriture de fichier, ce répertoire est vide. Dès qu’une opération d’écriture est effectuée dans le conteneur, les modifications apparaissent de manière incrémentale dans cette couche. Cependant, avez-vous réfléchi à ce qui se passe si vous souhaitez supprimer un fichier de la couche en lecture seule ? Pour réaliser cette suppression, AuFS crée un fichier whiteout dans la couche en lecture-écriture pour « masquer » le fichier de la couche en lecture seule. Par exemple, supprimer un fichier nommé foo de la couche en lecture seule crée en réalité un fichier nommé .wh.foo dans la couche en lecture-écriture. Ainsi, lorsque ces couches sont montées en union, le fichier foo est masqué par le fichier .wh.foo et « disparaît ». Cette fonctionnalité est ce que signifie la méthode de montage ro+wh, c’est-à-dire lecture seule plus whiteout.
Partie 3 : Couche Init. C’est une couche interne générée par le projet Docker, se terminant par -init, placée entre les couches en lecture seule et en lecture-écriture. La couche Init est spécifiquement utilisée pour stocker des informations comme /etc/hosts et /etc/resolv.conf. La nécessité d’une telle couche vient du fait que ces fichiers appartiennent à l’image Ubuntu en lecture seule, mais nécessitent souvent des valeurs spécifiques, comme le nom d’hôte, à écrire au démarrage du conteneur. Par conséquent, des modifications sont nécessaires dans la couche en lecture-écriture. Cependant, ces modifications ne s’appliquent généralement qu’au conteneur actuel et ne sont pas destinées à être incluses dans la couche en lecture-écriture lors de l’exécution de docker commit. Docker choisit donc de monter ces fichiers modifiés dans une couche séparée. Lorsque les utilisateurs exécutent docker commit, seule la couche en lecture-écriture est incluse, à l’exclusion de ce contenu.
Avantages de la conception en couches des images de conteneurs
Grâce à la conception des « images en couches », avec les images Docker au cœur, des techniciens de différentes entreprises et équipes sont étroitement connectés. De plus, comme les opérations sur les images de conteneurs sont incrémentales, le contenu téléchargé ou poussé à chaque fois est beaucoup plus petit que plusieurs systèmes d’exploitation complets ; les couches partagées signifient que l’espace total nécessaire pour toutes ces images de conteneurs est inférieur à la somme de chaque image individuellement. Cette agilité de collaboration basée sur les images de conteneurs dépasse de loin celle des images de disques de machines virtuelles, qui peuvent peser plusieurs Go.
Plus important encore, une fois qu’une image est publiée, son téléchargement n’importe où dans le monde donne exactement le même contenu, reproduisant intégralement l’environnement d’origine créé par le fabricant de l’image.
L’impact des images de conteneurs sur les workflows de développement logiciel
L’invention des images de conteneurs ne comble pas seulement chaque étape du processus « développement - test - déploiement », mais signifie également que les images de conteneurs deviendront la méthode dominante de distribution de logiciels à l’avenir. Cette méthode de distribution offre des avantages tels que la légèreté, une cohérence élevée et une collaboration facilitée, rendant le développement et le déploiement de logiciels plus efficaces et fiables. Grâce à sa légèreté, sa cohérence et son efficacité, la technologie des conteneurs devient de plus en plus un outil essentiel dans le développement et les opérations logicielles. À mesure que la technologie continue d’évoluer et d’innover, on a des raisons de croire que la technologie des conteneurs jouera un rôle encore plus important à l’avenir.
Novita AI, la plateforme tout-en-un pour une créativité illimitée qui vous donne accès à plus de 100 API. De la génération d’images au traitement du langage, en passant par l’amélioration audio et la manipulation vidéo, un paiement à l’utilisation bon marché, elle vous libère des contraintes de maintenance des GPU tout en construisant vos propres produits. Essayez-la gratuitement.
