Dockerfile.1
führt mehrere aus 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
schließt sich ihnen an:
FROM busybox
RUN echo This is the A > a &&\
echo This is the B > b &&\
echo This is the C > c
Jeder RUN
erstellt eine Ebene, daher habe ich immer angenommen, dass weniger Ebenen besser und damit Dockerfile.2
besser sind.
Dies ist offensichtlich der Fall, wenn a RUN
etwas entfernt, das von einem vorherigen hinzugefügt wurde RUN
(dh yum install nano && yum clean all
), aber in Fällen, in denen jeder RUN
etwas hinzufügt, müssen wir einige Punkte berücksichtigen:
Ebenen sollten nur einen Unterschied über dem vorherigen hinzufügen. Wenn also die spätere Ebene nicht etwas entfernt, das in einer vorherigen Ebene hinzugefügt wurde, sollte zwischen beiden Methoden nicht viel Speicherplatz gespart werden ...
Ebenen werden parallel von Docker Hub gezogen, sodass sie
Dockerfile.1
, obwohl sie wahrscheinlich etwas größer sind, theoretisch schneller heruntergeladen werden.Wenn ein vierter Satz (dh
echo This is the D > d
) hinzugefügt und lokal neu erstellt wirdDockerfile.1
, wird er dank des Caches schneller erstellt, muss jedochDockerfile.2
alle 4 Befehle erneut ausführen.
Also die Frage: Was ist ein besserer Weg, um eine Docker-Datei zu erstellen?
quelle
Antworten:
Wenn möglich, füge ich Befehle, die Dateien erstellen, immer mit Befehlen zusammen, die dieselben Dateien in einer einzigen
RUN
Zeile löschen . Dies liegt daran, dass jedeRUN
Zeile dem Bild eine Ebene hinzufügt. Bei der Ausgabe handelt es sich buchstäblich um die Änderungen des Dateisystems, mit denen Siedocker diff
auf dem von ihm erstellten temporären Container anzeigen können . Wenn Sie eine Datei löschen, die in einer anderen Ebene erstellt wurde, registriert das Union-Dateisystem lediglich die Dateisystemänderung in einer neuen Ebene. Die Datei ist noch in der vorherigen Ebene vorhanden und wird über das Netzwerk versendet und auf der Festplatte gespeichert. Wenn Sie also Quellcode herunterladen, extrahieren, in eine Binärdatei kompilieren und am Ende die TGZ- und Quelldateien löschen, möchten Sie wirklich, dass dies alles in einer einzigen Ebene erfolgt, um die Bildgröße zu verringern.Als Nächstes habe ich Ebenen persönlich aufgeteilt, basierend auf ihrem Potenzial zur Wiederverwendung in anderen Bildern und der erwarteten Caching-Nutzung. Wenn ich 4 Bilder habe, die alle dasselbe Basis-Image haben (z. B. Debian), kann ich eine Sammlung allgemeiner Dienstprogramme für die meisten dieser Bilder in den ersten Ausführungsbefehl ziehen, damit die anderen Bilder vom Caching profitieren.
Die Reihenfolge in der Docker-Datei ist wichtig, wenn Sie die Wiederverwendung des Bildcaches betrachten. Ich sehe mir alle Komponenten an, die sehr selten aktualisiert werden, möglicherweise nur, wenn das Basis-Image aktualisiert wird, und stelle diese hoch oben in die Docker-Datei. Gegen Ende der Docker-Datei füge ich alle Befehle hinzu, die schnell ausgeführt werden und sich häufig ändern können, z. B. das Hinzufügen eines Benutzers mit einer hostspezifischen UID oder das Erstellen von Ordnern und das Ändern von Berechtigungen. Wenn der Container interpretierten Code (z. B. JavaScript) enthält, der aktiv entwickelt wird, wird dieser so spät wie möglich hinzugefügt, sodass bei einer Neuerstellung nur diese einzelne Änderung ausgeführt wird.
In jeder dieser Änderungsgruppen konsolidiere ich so gut ich kann, um Ebenen zu minimieren. Wenn es also 4 verschiedene Quellcode-Ordner gibt, werden diese in einem einzelnen Ordner abgelegt, sodass er mit einem einzigen Befehl hinzugefügt werden kann. Alle Paketinstallationen von apt-get werden nach Möglichkeit zu einem einzigen RUN zusammengeführt, um den Aufwand für den Paketmanager (Aktualisierung und Bereinigung) zu minimieren.
Update für mehrstufige Builds:
Ich mache mir viel weniger Sorgen um die Reduzierung der Bildgröße in den nicht endgültigen Phasen eines mehrstufigen Builds. Wenn diese Phasen nicht markiert und an andere Knoten gesendet werden, können Sie die Wahrscheinlichkeit einer Wiederverwendung des Caches maximieren, indem Sie jeden Befehl in eine separate
RUN
Zeile aufteilen.Dies ist jedoch keine perfekte Lösung, um Ebenen zu quetschen, da Sie zwischen den Phasen nur die Dateien kopieren und nicht die restlichen Bild-Metadaten wie Einstellungen der Umgebungsvariablen, Einstiegspunkt und Befehl. Wenn Sie Pakete in einer Linux-Distribution installieren, sind die Bibliotheken und andere Abhängigkeiten möglicherweise im gesamten Dateisystem verteilt, was das Kopieren aller Abhängigkeiten schwierig macht.
Aus diesem Grund verwende ich mehrstufige Builds als Ersatz für das Erstellen von Binärdateien auf einem CI / CD-Server, sodass auf meinem CI / CD-Server nur das
docker build
Tool zum Ausführen erforderlich ist und kein JDK, NodeJS, Go und Alle anderen installierten Kompilierungswerkzeuge.quelle
Offizielle Antwort in ihren Best Practices aufgeführt (offizielle Bilder müssen diese einhalten)
Da Docker 1.10 die
COPY
,ADD
undRUN
Aussagen fügen Sie eine neue Ebene zu Ihrem Bild. Seien Sie vorsichtig, wenn Sie diese Aussagen verwenden. Versuchen Sie, Befehle in einer einzigenRUN
Anweisung zu kombinieren . Trennen Sie dies nur, wenn es für die Lesbarkeit erforderlich ist.Weitere Informationen: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#/minimize-the-number-of-layers
Update: Mehrstufig im Docker> 17.05
Bei mehrstufigen Builds können Sie mehrere
FROM
Anweisungen in Ihrer Docker-Datei verwenden. JedeFROM
Aussage ist eine Bühne und kann ein eigenes Basisbild haben. In der letzten Phase verwenden Sie ein minimales Basis-Image wie alpine, kopieren die Build-Artefakte aus früheren Phasen und installieren die Laufzeitanforderungen. Das Endergebnis dieser Phase ist Ihr Image. Hier sorgen Sie sich also um die zuvor beschriebenen Ebenen.Wie üblich verfügt Docker über hervorragende Dokumente zu mehrstufigen Builds. Hier ist ein kurzer Auszug:
Einen großartigen Blog-Beitrag dazu finden Sie hier: https://blog.alexellis.io/mutli-stage-docker-builds/
Um Ihre Punkte zu beantworten:
Ja, Ebenen sind wie Unterschiede. Ich glaube nicht, dass Ebenen hinzugefügt werden, wenn es absolut keine Änderungen gibt. Das Problem ist, dass Sie etwas, das Sie in Schicht 2 installiert / heruntergeladen haben, in Schicht 3 nicht mehr entfernen können. Sobald also etwas in eine Ebene geschrieben ist, kann die Bildgröße nicht mehr verringert werden, indem diese entfernt wird.
Obwohl Ebenen parallel gezogen werden können, wodurch sie möglicherweise schneller werden, erhöht jede Ebene zweifellos die Bildgröße, selbst wenn sie Dateien entfernen.
Ja, Caching ist nützlich, wenn Sie Ihre Docker-Datei aktualisieren. Aber es funktioniert in eine Richtung. Wenn Sie 10 Ebenen haben und Ebene 6 ändern, müssen Sie immer noch alles von Ebene 6 bis 10 neu erstellen. Es kommt also nicht allzu oft vor, dass der Erstellungsprozess beschleunigt wird, aber die Größe Ihres Bildes wird garantiert unnötig vergrößert.
Vielen Dank an @Mohan , der mich daran erinnert hat, diese Antwort zu aktualisieren.
quelle
Es scheint, dass die obigen Antworten veraltet sind. Anmerkung der Dokumentation:
https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/#minimize-the-number-of-layers
und
https://docs.docker.com/engine/userguide/eng-image/multistage-build/
Best Practice scheint sich dahingehend geändert zu haben, mehrstufige Builds zu verwenden und das
Dockerfile
s lesbar zu halten.quelle
docker image build --squash
Option außerhalb des experimentellen Bereichs liegt.squash
, ob ich nicht experimentell bin . Es hat viele Gimmicks und machte erst vor mehrstufigen Builds Sinn. Bei mehrstufigen Builds müssen Sie nur die Endstufe optimieren, was sehr einfach ist.Dies hängt davon ab, was Sie in Ihre Bildebenen aufnehmen.
Der entscheidende Punkt ist, so viele Ebenen wie möglich zu teilen:
Schlechtes Beispiel:
Dockerfile.1
Dockerfile.2
Gutes Beispiel:
Dockerfile.1
Dockerfile.2
Ein weiterer Vorschlag ist, dass das Löschen nur dann nicht so nützlich ist, wenn es auf derselben Ebene wie die Aktion zum Hinzufügen / Installieren erfolgt.
quelle
RUN yum install big-package
From-Cache teilen ?