⚠️ Traduction non officielle - Cette documentation est une traduction communautaire non officielle de Docker.

Comprendre les couches de l'image

Explication

Comme vous l'avez appris dans Qu'est-ce qu'une image ?, les images de conteneur sont composées de couches. Et chacune de ces couches, une fois créée, est immuable. Mais, qu'est-ce que cela signifie réellement ? Et comment ces couches sont-elles utilisées pour créer le système de fichiers qu'un conteneur peut utiliser ?

Couches d'image

Chaque couche d'une image contient un ensemble de modifications du système de fichiers - ajouts, suppressions ou modifications. Examinons une image théorique :

  1. La première couche ajoute des commandes de base et un gestionnaire de paquets, comme apt.
  2. La deuxième couche installe un runtime Python et pip pour la gestion des dépendances.
  3. La troisième couche copie un fichier requirements.txt spécifique à une application.
  4. La quatrième couche installe les dépendances spécifiques à cette application.
  5. La cinquième couche copie le code source réel de l'application.

Cet exemple pourrait ressembler à ceci :

capture d'écran de l'organigramme montrant le concept des couches d'image

Ceci est bénéfique car cela permet de réutiliser les couches entre les images. Par exemple, imaginez que vous vouliez créer une autre application Python. Grâce à la superposition, vous pouvez exploiter la même base Python. Cela rendra les constructions plus rapides et réduira la quantité de stockage et de bande passante requise pour distribuer les images. La superposition d'images pourrait ressembler à ce qui suit :

capture d'écran de l'organigramme montrant les avantages de la superposition d'images

Les couches vous permettent d'étendre les images des autres en réutilisant leurs couches de base, vous permettant d'ajouter uniquement les données dont votre application a besoin.

Empiler les couches

La superposition est rendue possible par le stockage adressable par contenu et les systèmes de fichiers d'union. Bien que cela devienne technique, voici comment cela fonctionne :

  1. Une fois chaque couche téléchargée, elle est extraite dans son propre répertoire sur le système de fichiers de l'hôte.
  2. Lorsque vous exécutez un conteneur à partir d'une image, un système de fichiers d'union est créé où les couches sont empilées les unes sur les autres, créant une nouvelle vue unifiée.
  3. Lorsque le conteneur démarre, son répertoire racine est défini sur l'emplacement de ce répertoire unifié, à l'aide de chroot.

Lorsque le système de fichiers d'union est créé, en plus des couches d'image, un répertoire est créé spécifiquement pour le conteneur en cours d'exécution. Cela permet au conteneur d'apporter des modifications au système de fichiers tout en laissant les couches d'image d'origine intactes. Cela vous permet d'exécuter plusieurs conteneurs à partir de la même image sous-jacente.

Essayez-le

Dans ce guide pratique, vous allez créer de nouvelles couches d'image manuellement à l'aide de la commande docker container commit. Notez que vous créerez rarement des images de cette manière, car vous utiliserez normalement un Dockerfile. Mais, cela facilite la compréhension de son fonctionnement.

Créer une image de base

Dans cette première étape, vous allez créer votre propre image de base que vous utiliserez ensuite pour les étapes suivantes.

  1. Téléchargez et installez Docker Desktop.

  2. Dans un terminal, exécutez la commande suivante pour démarrer un nouveau conteneur :

    $ docker run --name=base-container -ti ubuntu
    

    Une fois l'image téléchargée et le conteneur démarré, vous devriez voir une nouvelle invite de shell. Elle s'exécute à l'intérieur de votre conteneur. Elle ressemblera à ce qui suit (l'ID du conteneur variera) :

    root@d8c5ca119fcd:/#
    
  3. À l'intérieur du conteneur, exécutez la commande suivante pour installer Node.js :

    $ apt update && apt install -y nodejs
    

    Lorsque cette commande s'exécute, elle télécharge et installe Node à l'intérieur du conteneur. Dans le contexte du système de fichiers d'union, ces modifications du système de fichiers se produisent dans le répertoire unique à ce conteneur.

  4. Validez si Node est installé en exécutant la commande suivante :

    $ node -e 'console.log("Hello world!")'
    

    Vous devriez alors voir un « Hello world! » apparaître dans la console.

  5. Maintenant que vous avez installé Node, vous êtes prêt à enregistrer les modifications que vous avez apportées en tant que nouvelle couche d'image, à partir de laquelle vous pouvez démarrer de nouveaux conteneurs ou créer de nouvelles images. Pour ce faire, vous utiliserez la commande docker container commit. Exécutez la commande suivante dans un nouveau terminal :

    $ docker container commit -m "Add node" base-container node-base
    
  6. Affichez les couches de votre image à l'aide de la commande docker image history :

    $ docker image history node-base
    

    Vous verrez une sortie similaire à la suivante :

    IMAGE          CREATED          CREATED BY                                      SIZE      COMMENT
    d5c1fca2cdc4   10 seconds ago   /bin/bash                                       126MB     Add node
    2b7cc08dcdbb   5 weeks ago      /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>      5 weeks ago      /bin/sh -c #(nop) ADD file:07cdbabf782942af0…   69.2MB
    <missing>      5 weeks ago      /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
    <missing>      5 weeks ago      /bin/sh -c #(nop)  ARG RELEASE                  0B
    

    Notez le commentaire « Add node » sur la première ligne. Cette couche contient l'installation de Node.js que vous venez de faire.

  7. Pour prouver que votre image a Node installé, vous pouvez démarrer un nouveau conteneur en utilisant cette nouvelle image :

    $ docker run node-base node -e "console.log('Hello again')"
    

    Avec cela, vous devriez obtenir une sortie « Hello again » dans le terminal, montrant que Node a été installé et fonctionne.

  8. Maintenant que vous avez terminé de créer votre image de base, vous pouvez supprimer ce conteneur :

    $ docker rm -f base-container
    

Définition de l'image de base

Une image de base est une base pour la construction d'autres images. Il est possible d'utiliser n'importe quelle image comme image de base. Cependant, certaines images sont intentionnellement créées comme des blocs de construction, fournissant une base ou un point de départ pour une application.

Dans cet exemple, vous ne déploierez probablement pas cette image node-base, car elle ne fait encore rien. Mais c'est une base que vous pouvez utiliser pour d'autres constructions.

Construire une image d'application

Maintenant que vous avez une image de base, vous pouvez étendre cette image pour créer des images supplémentaires.

  1. Démarrez un nouveau conteneur en utilisant l'image node-base nouvellement créée :

    $ docker run --name=app-container -ti node-base
    
  2. À l'intérieur de ce conteneur, exécutez la commande suivante pour créer un programme Node :

    $ echo 'console.log("Hello from an app")' > app.js
    

    Pour exécuter ce programme Node, vous pouvez utiliser la commande suivante et voir le message imprimé à l'écran :

    $ node app.js
    
  3. Dans un autre terminal, exécutez la commande suivante pour enregistrer les modifications de ce conteneur en tant que nouvelle image :

    $ docker container commit -c "CMD node app.js" -m "Add app" app-container sample-app
    

    Cette commande crée non seulement une nouvelle image nommée sample-app, mais ajoute également une configuration supplémentaire à l'image pour définir la commande par défaut lors du démarrage d'un conteneur. Dans ce cas, vous la définissez pour exécuter automatiquement node app.js.

  4. Dans un terminal en dehors du conteneur, exécutez la commande suivante pour afficher les couches mises à jour :

    $ docker image history sample-app
    

    Vous verrez alors une sortie qui ressemble à ce qui suit. Notez que le commentaire de la couche supérieure a « Add app » et que la couche suivante a « Add node » :

    IMAGE          CREATED              CREATED BY                                      SIZE      COMMENT
    c1502e2ec875   About a minute ago   /bin/bash                                       33B       Add app
    5310da79c50a   4 minutes ago        /bin/bash                                       126MB     Add node
    2b7cc08dcdbb   5 weeks ago          /bin/sh -c #(nop)  CMD ["/bin/bash"]            0B
    <missing>      5 weeks ago          /bin/sh -c #(nop) ADD file:07cdbabf782942af0…   69.2MB
    <missing>      5 weeks ago          /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  LABEL org.opencontainers.…   0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  ARG LAUNCHPAD_BUILD_ARCH     0B
    <missing>      5 weeks ago          /bin/sh -c #(nop)  ARG RELEASE                  0B
    
  5. Enfin, démarrez un nouveau conteneur en utilisant la toute nouvelle image. Puisque vous avez spécifié la commande par défaut, vous pouvez utiliser la commande suivante :

    $ docker run sample-app
    

    Vous devriez voir votre message d'accueil apparaître dans le terminal, provenant de votre programme Node.

  6. Maintenant que vous avez terminé avec vos conteneurs, vous pouvez les supprimer en utilisant la commande suivante :

    $ docker rm -f app-container
    

Ressources supplémentaires

Si vous souhaitez approfondir les sujets que vous avez appris, consultez les ressources suivantes :

Prochaines étapes

Comme nous l'avons laissé entendre plus tôt, la plupart des constructions d'images n'utilisent pas docker container commit. Au lieu de cela, vous utiliserez un Dockerfile qui automatise ces étapes pour vous.