270 votes

Plusieurs RUN vs seul enchaîné EXÉCUTER dans Dockerfile, ce qui est mieux?

Dockerfile.1 exécute plusieurs RUN:

FROM busybox
RUN echo This is the A > a
RUN echo This is the B > b
RUN echo This is the C > c

Dockerfile.2 rejoint:

FROM busybox
RUN echo This is the A > a &&\
    echo This is the B > b &&\
    echo This is the C > c

Chaque RUN crée une couche, donc j'ai toujours supposé que les moins de couches est de meilleure qualité et donc Dockerfile.2 , c'est mieux.

C'est évidemment le cas lorsqu'un RUN supprime quelque chose à ajouter à une précédente RUN (c - yum install nano && yum clean all), mais dans les cas où chaque RUN y ajoute quelque chose, il ya quelques points que nous devons considérer:

  1. Les couches sont censés il suffit d'ajouter une diff au-dessus de la précédente, de sorte que si la dernière couche ne pas enlever quelque chose à ajouter dans la précédente, il devrait y avoir pas beaucoup d'espace disque de gain entre les deux méthodes...

  2. Les couches sont tirés en parallèle à partir de Docker Hub, donc, Dockerfile.1, mais probablement un peu plus grand, en théorie, téléchargement plus rapide.

  3. Si l'ajout d'un 4e phrase (c - echo This is the D > d) et localement à la reconstruction de, Dockerfile.1 serait de construire plus rapide grâce à un cache, mais Dockerfile.2 aurait pour exécuter tous les 4 commandes à nouveau.

Donc, la question: Qui est une meilleure façon de faire un Dockerfile?

197voto

BMitch Points 3744

Lorsque c'est possible, j'ai toujours fusionner ensemble des commandes qui créent des fichiers avec les commandes que supprimer ces fichiers en un seul RUN ligne de. C'est parce que chaque RUN ligne en rajoute une couche à l'image, le résultat est tout à fait littéralement les modifications au système de fichiers que vous pouvez afficher avec docker diff sur le temporaire récipient qu'il crée. Si vous supprimez un fichier qui a été créé dans un calque différent, tout le système de fichiers union n'est d'inscrire le changement de système de fichiers dans un nouveau calque, le fichier existe toujours dans la couche précédente et est livré sur le réseau et stocké sur le disque. Donc, si vous téléchargez le code source, l'extraire, de les compiler dans un binaire, puis supprimez le fichier tgz et des fichiers source à la fin, tu le veux vraiment tout faire en une seule couche pour réduire la taille de l'image.

Ensuite, personnellement, j'ai divisé les couches en fonction de leur potentiel de réutilisation dans d'autres images et attendus de la mise en cache d'utilisation. Si j'ai 4 images, tous avec la même image de base (par exemple debian), j'ai peut tirer une collection d'utilitaires pour la plupart de ces images dans la première manche de commande alors que les autres images de bénéficier de la mise en cache.

De l'ordre dans le Dockerfile est important lorsque l'on regarde l'image du cache de la réutilisation. Je regarde tous les composants qui sera mise à jour très rarement, peut-être seulement quand l'image de base, mises à jour et de mettre ceux-ci en haut dans le Dockerfile. Vers la fin de la Dockerfile, je inclure toutes les commandes qui s'exécutent rapidement et peuvent changer fréquemment, par exemple, l'ajout d'un utilisateur avec un hôte spécifique UID ou la création de dossiers et la modification des autorisations. Si le conteneur comprend le code interprété (ex: JavaScript) qui est activement développée, qui s'ajoute aussi tard que possible, de sorte que la reconstruction ne fonctionne que seul changement.

Dans chacun de ces groupes de changements, j'ai consolider mieux que je peux pour minimiser les couches. Donc si il y a 4 différents code source de dossiers, ceux placés à l'intérieur d'un dossier unique de sorte qu'il peut être ajouté en une seule commande. Un paquet installe à partir de quelque chose comme apt-get sont fusionnées en une seule fois dès que possible afin de minimiser la quantité de gestionnaire de paquets, les frais généraux (mise à jour et de nettoyage).


Mise à jour pour le multi-étape:les versions

Je m'inquiète beaucoup moins sur la réduction de la taille de l'image dans le non-dernières étapes du processus de plusieurs étapes de construction. Lorsque ces étapes ne sont pas étiquetés et envoyés à d'autres nœuds, vous pouvez maximiser la probabilité d'un cache de réutilisation par le fractionnement de chaque commande séparé RUN ligne de.

Cependant, ce n'est pas une solution parfaite pour l'écrasement des couches depuis tous vous copie entre les étapes sont les fichiers, et pas le reste de l'image des méta-données comme paramètres des variables d'environnement, point d'entrée et de commande. Et lorsque vous installez les paquets dans une distribution linux, les bibliothèques et autres dépendances peuvent être dispersés à travers le système de fichiers, la création d'une copie de toutes les dépendances difficile.

De ce fait, j'utilise le multi-stade construit comme un remplacement pour la construction des binaires sur un CI/CD serveur, de sorte que mon CI/CD serveur n'a besoin que de l'outillage à exécuter docker build, et ne pas avoir un jdk, nodejs, aller, et tout autres outils de compilation installé.

70voto

Menzo Wijmenga Points 356

Réponse officielle figurant dans leurs meilleures pratiques ( les images officielles DOIVENT se conformer à celles-ci )

Minimiser le nombre de couche

Vous avez besoin de trouver l'équilibre entre la lisibilité (et donc la maintenance à long terme) de la Dockerfile et en minimisant le nombre de couches qu'il utilise. Être stratégique et prudent sur le nombre de couches que vous utilisez.

Depuis le panneau 1.10 l' COPY, ADD et RUN états ajouter un nouveau calque sur votre image. Être prudent lors de l'utilisation de ces déclarations. Essayez de combiner des commandes dans un seul RUN déclaration. Séparer ce, seulement si c'est nécessaire pour des raisons de lisibilité.

Plus d'infos: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#/minimize-the-number-of-layers

Mise à jour: Multi scène dans le panneau >17.05

Avec multi-étape de builds vous pouvez utiliser plusieurs FROM des déclarations dans votre Dockerfile. Chaque FROM déclaration est une étape et d'avoir sa propre image de base. Dans la phase finale vous utilisez un minimum d'image de base comme le ski alpin, la copie de l'accumulation des objets des étapes précédentes et installer le runtime exigences. Le résultat final de cette étape est de votre image. C'est donc là que vous vous inquiétez au sujet des couches comme décrit précédemment.

Comme d'habitude, docker a de grands docs sur multi-étape s'appuie. Voici un petit extrait:

Avec multi-stade construit, vous utilisez plusieurs des déclarations dans votre Dockerfile. Chaque instruction peut utiliser une base différente, et chaque d'entre eux commence une nouvelle étape de la construction. Vous pouvez choisir de copier les artefacts d'une étape à l'autre, laissant derrière eux tout ce que vous ne voulez pas dans l'image finale.

Un super blog post à ce sujet peuvent être trouvées ici: https://blog.alexellis.io/mutli-stage-docker-builds/

Pour répondre à vos points:

  1. Oui, les couches sont un peu comme des diffs. Je ne pense pas qu'il y a des couches ajoutées, s'il n'y a absolument aucun changement. Le problème est qu'une fois que vous installer / télécharger quelque chose dans la couche n ° 2, vous ne pouvez pas l'enlever dans la couche n ° 3. Donc, une fois que quelque chose est écrit dans une couche, la taille de l'image ne peut pas être diminué plus en retrait.

  2. Bien que les couches peuvent être mises en parallèle, rendant potentiellement plus rapide, chaque couche sans aucun doute augmente la taille de l'image, même si elles sont de la suppression des fichiers.

  3. Oui, la mise en cache est utile si vous êtes à la mise à jour de votre panneau de fichier. Mais ça marche que dans un sens. Si vous avez 10 couches, et que vous changez la couche n ° 6, vous aurez toujours besoin de tout reconstruire à partir de la couche n ° 6-n ° 10. Il n'est pas trop souvent que cela permettra d'accélérer le processus de construction, mais il est garanti pour augmenter inutilement la taille de votre image.


Merci à @Mohan pour me rappeler de mettre à jour cette réponse.

35voto

Mohan Points 215

Il semble que les réponses ci-dessus sont dépassées. Les docs note:

Avant Docker 17.05, et même plus, avant de Docker 1.10, il est important de minimiser le nombre de couches dans votre image. L' améliorations suivantes ont atténué ce besoin:

[...]

Docker 17.05 supérieur et d'ajouter le support du multi-stade construit, qui permet de copier uniquement les objets dont vous avez besoin dans l'image finale. Ceci vous permet d'inclure des outils et des informations de débogage dans votre intermédiaire étapes de génération sans augmenter la taille de la finale image.

https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#minimize-the-number-of-layers

et

Notez que cet exemple aussi artificiellement compresse deux d'EXÉCUTER des commandes à l'aide du Bash && opérateur, pour éviter de créer une autre calque dans l'image. C'est sujets aux pannes et difficiles à maintenir.

https://docs.docker.com/engine/userguide/eng-image/multistage-build/

Meilleure pratique semble avoir changé à l'aide de plusieurs étages construit et de maintien de l' Dockerfiles lisible.

9voto

xdays Points 452

Cela dépend de quel vous inclure dans vos calques de l'image.

Le point clé est de partager autant de couches que possible:

Mauvais Exemple:

Dockerfile.1

RUN yum install big-package && yum install package1

Dockerfile.2

RUN yum install big-package && yum install package2

Bon Exemple:

Dockerfile.1

RUN yum install big-package
RUN yum install package1

Dockerfile.2

RUN yum install big-package
RUN yum install package2

Une autre suggestion est la suppression n'est pas si utile que si elle se fait sur le même calque que l'ajoutant/installation d'action.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X