Que sont les «calques» d'image Docker?

165

Je suis nouveau sur Docker et j'essaie de comprendre exactement ce qu'est une image Docker . Chaque définition unique d'une image Docker utilise le terme «couche», mais ne semble pas définir ce que l'on entend par couche .

À partir de la documentation officielle de Docker :

Nous avons déjà vu que les images Docker sont des modèles en lecture seule à partir desquels les conteneurs Docker sont lancés. Chaque image se compose d'une série de couches. Docker utilise les systèmes de fichiers union pour combiner ces couches en une seule image. Les systèmes de fichiers Union permettent aux fichiers et répertoires de systèmes de fichiers séparés, appelés branches, d'être superposés de manière transparente, formant un seul système de fichiers cohérent.

Alors je demande, qu'est-ce qu'une couche (exactement); quelqu'un peut-il en donner quelques exemples concrets? Et comment ces couches «s'emboîtent-elles» pour former une image?

smeeb
la source

Réponses:

133

Je suis peut-être en retard, mais voici mes 10 cents (en complément de la réponse d'Ashishjain):

Fondamentalement, un calque ou un calque d' image est un changement sur une image ou une image intermédiaire . Chaque commande que vous spécifiez ( FROM, RUN, COPY, etc.) dans votre Dockerfile , l'image précédente au changement, créant ainsi une nouvelle couche. Vous pouvez considérer cela comme une étape des changements lorsque vous utilisez git: vous ajoutez la modification d'un fichier, puis une autre, puis une autre ...

Considérez le Dockerfile suivant:

FROM rails:onbuild
ENV RAILS_ENV production
ENTRYPOINT ["bundle", "exec", "puma"]

Tout d'abord, nous choisissons une image de départ:, rails:onbuildqui à son tour comporte de nombreuses couches . Nous ajoutons un autre calque au-dessus de notre image de départ, en définissant la variable d'environnement RAILS_ENVavec la ENVcommande. Ensuite, nous disons à docker de s'exécuter bundle exec puma(qui démarre le serveur rails). C'est une autre couche.

Le concept de couches est utile au moment de la construction d'images. Étant donné que les couches sont des images intermédiaires, si vous apportez une modification à votre Dockerfile, docker ne créera que la couche qui a été modifiée et les suivantes. C'est ce qu'on appelle la mise en cache des couches.

Vous pouvez en savoir plus ici .

David Castillo
la source
13
Si vous modifiez ou ajoutez une couche, Docker construira également toutes les couches suivantes, car elles pourraient être affectées par le changement.
Adam
Merci d'expliquer la raison derrière le concept de couches qui manque dans les autres réponses.
Seeta Somagani
@David, dans l'exemple ci-dessus, combien de couches seront ajoutées? 2? ou 1?
Gourav Singla
1
@GouravSingla Cela devrait être 2. Changer ENV est aussi un changement. On dirait que la couche est le commit de git.
PokerFace
Le dernier lien ( https://labs.ctl.io/caching-docker-images/) est rompu. Quelqu'un a-t-il des suggestions pour un remplacement?
Johnny Utahh
72

Une image de conteneur Docker est créée à l'aide d'un dockerfile . Chaque ligne d'un fichier docker crée un calque. Prenons l'exemple factice suivant:

FROM ubuntu             #This has its own number of layers say "X"
MAINTAINER FOO          #This is one layer 
RUN mkdir /tmp/foo      #This is one layer 
RUN apt-get install vim #This is one layer 

Cela créera une image finale où le nombre total de couches sera X + 3

Ashishjain
la source
32
Bien que je n'ai pas voté contre, je suppose que cela explique comment créer les couches, mais ne répond en aucun cas à la question de savoir ce qu'est une couche.
Lasse V.Karlsen
2
Je suis d'accord avec @ LasseV.Karlsen, ashishjain. Je ne vous ai pas critiqué et je vous vote en fait pour avoir essayé de m'aider (donc +1) - mais pour que je puisse vous donner le chèque vert, j'ai besoin de comprendre ce qu'est réellement une couche! Merci encore, continuez!
smeeb
3
meilleure réponse imo. pour beaucoup d'entre nous qui passent à "l'utilisation de docker", cela nous donne l'essentiel du fonctionnement des couches.
dtc le
6
"Chaque ligne dans un fichier docker va créer un calque" - cela m'a été très utile de le savoir
akirekadu
2
@akirekadu Ce n'est pas l'histoire complète. La plupart des lignes créeront un calque, mais seules les instructions ADD, COPY ou RUN créeront des calques qui augmenteront la taille de l'image de conteneur résultante. J'ai dit la plupart des lignes parce que si vous enchaînez des commandes ou échappez aux nouvelles lignes avec une barre oblique inverse, la séquence de commandes chaînées / de nouvelles lignes échappées formera une seule commande.
Scott Simontis le
41

Ils ont le plus de sens pour moi avec un exemple ...

Examen des couches de votre propre construction avec Docker Diff

Prenons un exemple artificiel de Dockerfile:

FROM busybox

RUN mkdir /data
# imagine this is downloading source code
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one 
RUN chmod -R 0777 /data
# imagine this is compiling the app
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two 
RUN chmod -R 0777 /data
# and now this cleans up that downloaded source code
RUN rm /data/one 

CMD ls -alh /data

Chacune de ces ddcommandes génère un fichier de 1 Mo sur le disque. Permet de construire l'image avec un indicateur supplémentaire pour enregistrer les conteneurs temporaires:

docker image build --rm=false .

Dans la sortie, vous verrez chacune des commandes en cours d'exécution se produire dans un conteneur temporaire que nous conservons maintenant au lieu de supprimer automatiquement:

...
Step 2/7 : RUN mkdir /data
 ---> Running in 04c5fa1360b0
 ---> 9b4368667b8c
Step 3/7 : RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
 ---> Running in f1b72db3bfaa
1024+0 records in
1024+0 records out
1048576 bytes (1.0MB) copied, 0.006002 seconds, 166.6MB/s
 ---> ea2506fc6e11

Si vous exécutez un docker diffsur chacun de ces ID de conteneur, vous verrez quels fichiers ont été créés dans ces conteneurs:

$ docker diff 04c5fa1360b0  # mkdir /data
A /data
$ docker diff f1b72db3bfaa  # dd if=/dev/zero bs=1024 count=1024 of=/data/one
C /data
A /data/one
$ docker diff 81c607555a7d  # chmod -R 0777 /data
C /data
C /data/one
$ docker diff 1bd249e1a47b  # dd if=/dev/zero bs=1024 count=1024 of=/data/two
C /data
A /data/two
$ docker diff 038bd2bc5aea  # chmod -R 0777 /data
C /data/one
C /data/two
$ docker diff 504c6e9b6637  # rm /data/one
C /data
D /data/one

Chaque ligne précédée d'un signe Aajoute le fichier, Cindique une modification apportée à un fichier existant et Dindique une suppression.

Voici la partie TL; DR

Chacun de ces systèmes de fichiers de conteneur diffs ci-dessus va dans une "couche" qui est assemblée lorsque vous exécutez l'image en tant que conteneur. Le fichier entier se trouve dans chaque couche lorsqu'il y a un ajout ou une modification, de sorte que chacune de ces chmodcommandes, malgré le simple changement d'un bit d'autorisation, entraîne la copie du fichier entier dans la couche suivante. Le fichier supprimé / data / one est toujours dans les couches précédentes, 3 fois en fait, et sera copié sur le réseau et stocké sur le disque lorsque vous tirez l'image.

Examen des images existantes

Vous pouvez voir les commandes qui entrent dans la création des couches d'une image existante avec la docker historycommande. Vous pouvez également exécuter un docker image inspectsur une image et voir la liste des couches sous la section RootFS.

Voici l'historique de l'image ci-dessus:

IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
a81cfb93008c        4 seconds ago       /bin/sh -c #(nop)  CMD ["/bin/sh" "-c" "ls -…   0B
f36265598aef        5 seconds ago       /bin/sh -c rm /data/one                         0B
c79aff033b1c        7 seconds ago       /bin/sh -c chmod -R 0777 /data                  2.1MB
b821dfe9ea38        10 seconds ago      /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
a5602b8e8c69        13 seconds ago      /bin/sh -c chmod -R 0777 /data                  1.05MB
08ec3c707b11        15 seconds ago      /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
ed27832cb6c7        18 seconds ago      /bin/sh -c mkdir /data                          0B
22c2dd5ee85d        2 weeks ago         /bin/sh -c #(nop)  CMD ["sh"]                   0B
<missing>           2 weeks ago         /bin/sh -c #(nop) ADD file:2a4c44bdcb743a52f…   1.16MB

Les couches les plus récentes sont répertoriées en haut. À noter, il y a deux couches en bas qui sont assez anciennes. Ils proviennent de l'image busybox elle-même. Lorsque vous créez une image, vous héritez de tous les calques de l'image que vous spécifiez dans la FROMligne. Des couches sont également ajoutées pour modifier les métadonnées de l'image, comme la CMDligne. Ils prennent à peine de la place et servent davantage à enregistrer les paramètres qui s'appliquent à l'image que vous exécutez.

Pourquoi des couches?

Les couches ont quelques avantages. Premièrement, ils sont immuables. Une fois créé, ce calque identifié par un hachage sha256 ne changera jamais. Cette immuabilité permet aux images de se construire en toute sécurité et de se séparer les unes des autres. Si deux fichiers docker ont le même ensemble initial de lignes et sont construits sur le même serveur, ils partageront le même ensemble de couches initiales, économisant de l'espace disque. Cela signifie également que si vous reconstruisez une image, avec seulement les dernières lignes du Dockerfile subissant des modifications, seules ces couches doivent être reconstruites et le reste peut être réutilisé à partir du cache de couches. Cela peut accélérer la reconstruction des images du docker.

À l'intérieur d'un conteneur, vous voyez le système de fichiers image, mais ce système de fichiers n'est pas copié. En plus de ces couches d'image, le conteneur monte sa propre couche de système de fichiers en lecture-écriture. Chaque lecture d'un fichier passe par les couches jusqu'à ce qu'elle atteigne une couche qui a marqué le fichier pour suppression, a une copie du fichier dans cette couche, ou la lecture manque de couches à rechercher. Chaque écriture apporte une modification dans la couche lecture-écriture spécifique au conteneur.

Réduire le gonflement de la couche

L'un des inconvénients des couches est la création d'images qui dupliquent des fichiers ou expédient des fichiers supprimés dans une couche ultérieure. La solution consiste souvent à fusionner plusieurs commandes en une seule RUNcommande. En particulier, lorsque vous modifiez des fichiers existants ou supprimez des fichiers, vous souhaitez que ces étapes s'exécutent dans la même commande où elles ont été créées pour la première fois. Une réécriture du Dockerfile ci-dessus ressemblerait à ceci:

FROM busybox

RUN mkdir /data \
 && dd if=/dev/zero bs=1024 count=1024 of=/data/one \
 && chmod -R 0777 /data \
 && dd if=/dev/zero bs=1024 count=1024 of=/data/two \
 && chmod -R 0777 /data \
 && rm /data/one

CMD ls -alh /data

Et si vous comparez les images résultantes:

  • busybox: ~ 1 Mo
  • première image: ~ 6 Mo
  • deuxième image: ~ 2 Mo

Simplement en fusionnant quelques lignes dans l'exemple artificiel, nous avons obtenu le même contenu résultant dans notre image et avons réduit notre image de 5 Mo au fichier de 1 Mo que vous voyez dans l'image finale.

BMitch
la source
Traverser les couches pendant les lectures de fichiers entraîne une surcharge, non? Pour économiser cette surcharge, est-il judicieux de combiner plusieurs commandes (qui doivent de toute façon être exécutées ensemble) en un seul RUN?
SergiyKolesnikov le
@SergiyKolesnikov dépend du temps que vous souhaitez consacrer prématurément à l'optimisation. Le risque est de passer des heures de temps aux développeurs, des gigs de bande passante et de stockage supplémentaires, pour économiser des millisecondes de temps d'exécution. Comme pour beaucoup de choses liées à la performance, il y a des extrêmes, et il est nécessaire de mesurer le problème avant de faire des efforts pour le résoudre.
BMitch
19

Depuis Docker v1.10, avec l'introduction du stockage adressable de contenu, la notion de «couche» est devenue assez différente. Les calques n'ont aucune notion d'image ou d'appartenance à une image, ils deviennent simplement des collections de fichiers et de répertoires qui peuvent être partagés entre les images. Les couches et les images se sont séparées.

Par exemple, sur une image construite localement à partir d'une image de base, disons ubuntu:14.04, la docker historycommande donne la chaîne d'images, mais certains des ID d'image seront affichés comme `` manquants '' car l'historique de construction n'est plus chargé. Et les couches qui composent ces images peuvent être trouvées via

docker inspect <image_id> | jq -r '.[].RootFS'

Le contenu de la couche est stocké dans /var/lib/docker/aufs/diffsi la sélection du pilote de stockage est aufs. Mais les couches sont nommées avec un ID de cache généré aléatoirement, il semble que le lien entre une couche et son ID de cache n'est connu que de Docker Engine pour des raisons de sécurité. Je cherche toujours un moyen de le savoir

  1. La relation correspondante entre une image et ses calques de composition
  2. Emplacement et taille réels d'une couche sur le disque

Ce blog a fourni beaucoup d'informations.

Ruifeng Ma
la source
Dans cette entrée SO, j'ai posté une façon plutôt naïve de répondre aux deux questions que j'ai postées.
Ruifeng Ma
13

Selon les spécifications d'image de Docker via le projet Moby :

Les images sont composées de couches. Chaque couche est un ensemble de modifications du système de fichiers. Les calques n'ont pas de métadonnées de configuration telles que des variables d'environnement ou des arguments par défaut - ce sont des propriétés de l'image dans son ensemble plutôt que d'un calque particulier.

Donc, essentiellement, une couche n'est qu'un ensemble de modifications apportées au système de fichiers.

Aditya Patawari
la source
Il ne m'a fallu que quelques heures pour le trouver, mais avec cette réponse simple et élégante, je comprends enfin ce qu'est une couche: "Each [Docker] layer is a set of filesystem changes."(En supposant que cela soit vrai.) Pour une raison quelconque, je n'ai pas compris ce point fondamental lors de la lecture de nombreux autres documents / blogs / Q + A's / etc, et je suppose que la limitation était la leur et non la mienne. Quoi qu'il en soit, bravo Aditya pour être entré dans le vif du sujet.
Johnny Utahh
12

Je pense que le document officiel donne une explication assez détaillée: https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/ .


(source: docker.com )

Une image se compose de nombreuses couches qui sont généralement générées à partir de Dockerfile, chaque ligne de Dockerfile créera une nouvelle couche et le résultat est une image, qui est indiquée par le formulaire repo:tag, comme ubuntu:15.04.

Pour plus d'informations, veuillez lire la documentation officielle ci-dessus.

cizix
la source
2

Merci @David Castillo pour les informations utiles . Je pense que le calque est un changement binaire ou une instruction d'une image qui peut être fait ou défait facilement. Ils sont effectués étape par étape, ce qui équivaut à un calque sur un calque, nous appelons donc «calque».

Pour plus d'informations, vous pouvez voir "l'historique du docker" comme ceci:

images docker - arbre
Attention: '--tree' est obsolète, il sera bientôt supprimé. Voir l'utilisation.
└─511136ea3c5a Taille virtuelle: 0 B Tags: scratch: dernier
  └─59e359cb35ef Taille virtuelle: 85,18 Mo
    └─e8d37d9e3476 Taille virtuelle: 85,18 Mo Tags: debian: wheezy
      └─c58b36b8f285 Taille virtuelle: 85,18 Mo
        └─90ea6e05b074 Taille virtuelle: 118,6 Mo
          └─5dc74cffc471 Taille virtuelle: 118,6 Mo Tags: vim: dernier

hiproz
la source
5
trouvé une nouvelle information sur les couches : lorsque Docker monte le rootfs, il démarre en lecture seule, comme dans un démarrage Linux traditionnel, mais ensuite, au lieu de changer le système de fichiers en mode lecture-écriture, il profite d'un montage union pour ajouter un système de fichiers en lecture-écriture sur le système de fichiers en lecture seule. En fait, il peut y avoir plusieurs systèmes de fichiers en lecture seule empilés les uns sur les autres. Nous considérons chacun de ces systèmes de fichiers comme une couche .
hiproz
1

Ma compréhension personnelle est que nous pouvons comparer la couche docker à github commit. Pour votre image de base (votre nouveau référentiel maître), vous effectuez plusieurs commits, chaque commit change votre statut de maître, c'est la même chose dans le menu fixe, chaque couche effectue une opération basée sur la couche intermédiaire précédente. Et puis, cette couche devient une nouvelle couche intermédiaire à la couche suivante.

KevinZhou
la source
0

J'avais l'habitude de penser qu'ils sont comme des différences sur les couches précédentes. Après avoir lu certaines des réponses ici, je n'étais pas si sûr; ils sont décrits comme des ensembles de modifications du système de fichiers . J'ai écrit des fichiers Docker pour montrer qu'ils ressemblent plus à des diffs, c'est-à-dire qu'ils dépendent vraiment des couches précédentes.

Compte tenu de ces deux fichiers Docker

FROM bash
RUN mkdir /data
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/three

et

FROM bash
RUN mkdir /data
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/three
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/two
RUN dd if=/dev/zero bs=1024 count=1024 of=/data/one

on s'attendrait au même ensemble de couches s'il s'agissait simplement de modifications du système de fichiers, mais ce n'est pas le cas:

$ docker history img_1
IMAGE               CREATED             CREATED BY                                      SIZE
30daa166a9c5        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
4467d16e79f5        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
c299561fd031        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
646feb178431        6 minutes ago       /bin/sh -c mkdir /data                          0B
78664daf24f4        2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<more missing...>

et

$ docker history img_2
IMAGE               CREATED             CREATED BY                                      SIZE
f55c91305f8c        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
29b3b627c76f        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
18360be603aa        6 minutes ago       /bin/sh -c dd if=/dev/zero bs=1024 count=102…   1.05MB
646feb178431        6 minutes ago       /bin/sh -c mkdir /data                          0B
78664daf24f4        2 weeks ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
<more missing...>

Vous pouvez voir comment, même si les modifications apportées au système de fichiers sont les mêmes dans les deux cas, l'ordre est important.

olepinto
la source