web-dev-qa-db-fra.com

Dois-je minimiser le nombre de couches Docker?

Le documentation n'élabore pas beaucoup sur le sujet. Ça dit:

Minimisez le nombre de couches

Avant Docker 17.05, et plus encore, avant Docker 1.10, il était important de minimiser le nombre de couches dans votre image. Les améliorations suivantes ont atténué ce besoin:

Dans Docker 1.10 et supérieur, seules les instructions RUN, COPY et ADD créent des couches. D'autres instructions créent des images intermédiaires temporaires et n'augmentent plus directement la taille de la construction.

Docker 17.05 et versions ultérieures prennent en charge les versions multi-étapes, qui vous permettent de copier uniquement les artefacts dont vous avez besoin dans l'image finale. Cela vous permet d'inclure des outils et des informations de débogage dans vos étapes de génération intermédiaires sans augmenter la taille de l'image finale.

Il semble que les dernières versions de Docker ne résolvent pas le problème de la gestion de nombreuses couches. Ils s'efforcent plutôt de réduire leur nombre dans l'image finale. Plus important encore, les documents ne disent pas pourquoi de nombreux calques sont mauvais.

Je connais la limite AUFS de 42 couches. Il est logique de limiter le nombre de couches pour les images largement utilisées, car cela aide les autres images construites par-dessus à s'adapter à la restriction. Cependant, il existe un autre pilote de stockage et des images à d'autres fins.

Il est également bon de conserver des images de petite taille pour une raison évidente: elles occupent de l'espace disque et de la bande passante réseau. Cependant, je ne pense pas que chaîner des instructions RUN et donc écraser de nombreuses couches en une seule aide en général. Dans le cas où différents RUN mettent à jour différentes parties du système de fichiers, une couche et plusieurs couches doivent avoir approximativement la même taille.

D'autre part, de nombreuses couches permettent d'utiliser le cache et de reconstruire les images plus rapidement. Ils sont également tirés en parallèle.

Je travaille dans une petite équipe avec un registre Docker privé. Nous ne respecterons jamais la restriction des 42 couches et nous nous soucions principalement des performances et de la vitesse de développement.

Si oui, dois-je minimiser le nombre de couches Docker?

21
gukoff

Je travaille dans une petite équipe avec un registre Docker privé. Nous ne respecterons jamais la restriction des 42 couches et nous nous soucions principalement des performances et de la vitesse de développement.

Si oui, dois-je minimiser le nombre de couches Docker?

Dans votre cas, non.
Ce qui doit être minimisé est le temps de construction, ce qui signifie:

  • en vous assurant que les étapes les plus générales, et les plus longues sont d'abord, qui seront ensuite mises en cache, vous permettant de jouer avec les dernières lignes de votre Dockerfile (les commandes les plus spécifiques) tout en ayant un temps de reconstruction rapide.
  • s'assurer que la commande RUN la plus longue vient en premier et dans sa propre couche (à nouveau pour être mise en cache), au lieu d'être enchaînée avec d'autres commandes RUN: si l'une d'entre elles échoue, la commande longue devra être réexécutée. Si cette longue commande est isolée dans sa propre (ligne Dockerfile)/couche, elle sera mise en cache.

Cela étant dit, la documentation que vous mentionnez vient de docker/docker.github.io , précisément PR 4992 et PR 4854 , après un docker build LABEL section .
Cette section vient donc après une remarque similaire à propos de LABEL, et souligne simplement les commandes créant des calques.
Encore une fois, dans votre cas, ce ne serait pas important.

20
VonC

Je voulais juste voir quelles étaient les différences de 2 images, l'une construite avec plusieurs RUN et l'autre construite avec une seule commande de concaténation RUN.

Dans le premier cas, les images effectuent des opérations triviales (création et suppression de fichiers).

Contenu de l'image de calque "unique":

FROM busybox

RUN echo This is the 1 > 1 \
    && rm -f 1 \
    && echo This is the 2 > 2 \
    && rm -f 2 \
# ... for about 70 commands

Contenu de l'image multicouche:

FROM busybox

RUN echo This is the 1 > 1
RUN rm -f 1
RUN echo This is the 2 > 2
RUN rm -f 2
# ... for about 70 layers

Le temps de construction est très différent (multiple: 0m34,973s, singulier: 0m0,568s). Le temps de démarrage du conteneur est également différent mais moins perceptible (multiple: 0m0,435s, singulier: 0m0,378s). J'ai exécuté différentes fois les images mais les heures ne changent pas beaucoup.

En ce qui concerne l'espace, j'ai cherché exprès le pire des cas pour le cas des couches multiples et comme prévu, l'image multicouche est plus grande que la couche unique.

Dans un autre test, j'ai concaténé des calques qui ajoutent uniquement du contenu à l'image. Le temps de construction ne change pas par rapport au cas précédent, mais le cas d'exécution montre quelque chose d'un peu différent: l'image multicouche est plus rapide à démarrer que l'image monocouche. Concernant l'espace, mêmes résultats.

Je ne pense pas que cela prouve quoi que ce soit, mais je me suis amusé à le faire: P

17
Stefano

Réduire le nombre de couches est moins un objectif en soi. Vous devez plutôt vous concentrer sur la réduction du temps de construction et la réduction de la taille de l'image.

Le temps de construction est réduit en conservant les couches communes qui changent rarement en haut de votre Dockerfile ou dans une image de base. Cela permet à la couche d'être mise en cache et réutilisée dans les versions ultérieures. Il s'agit moins de réduire le nombre de couches et plus de bien organiser vos couches.

La réduction de la taille de l'image permet de réduire l'utilisation du disque sur les serveurs de registre, qui voient un grand succès sur le disque lorsque les images sont stockées pour chaque build sur un système CI. Cela réduit également le temps du réseau pour transférer l'image. Lorsque vous avez une couche qui télécharge un gros fichier temporaire et que vous le supprimez dans une autre couche, cela a pour résultat de laisser le fichier dans la première couche, où il est envoyé sur le réseau et stocké sur le disque, même lorsqu'il n'est pas visible à l'intérieur votre conteneur. La modification des autorisations sur un fichier entraîne également la copie du fichier dans la couche actuelle avec les nouvelles autorisations, doublant ainsi l'espace disque et la bande passante réseau de ce fichier.

La solution standard pour réduire la taille de l'image dans les scénarios ci-dessus consiste à chaîner les commandes RUN afin que les fichiers temporaires ne soient jamais stockés dans une couche d'image. Cela a pour effet secondaire de réduire le nombre de couches d'image.

Il y a un dernier problème, qui est la mise en cache excessive. Cela se voit généralement avec le apt-get update et apt-get install ... commandes dans les images Debian. Si vous ne chaînez pas ces commandes ensemble, une mise à jour de apt-get install la commande réutilisera un cache éventuellement périmé des couches précédentes apt-get update, et échouera des mois plus tard lorsqu'il ne trouvera pas les packages nécessaires. Par conséquent, vous devez chaîner ces commandes même si cela augmentera le temps de génération, car l'autre option consiste à avoir des échecs de génération à l'avenir.

Par conséquent, ce sont plus les effets secondaires de la réduction des calques que vous voulez, pas nécessairement la réduction des calques pour réduire les calques.

8
BMitch