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 jede RUN
Zeile dem Bild eine Ebene hinzufügt. Bei der Ausgabe handelt es sich buchstäblich um die Änderungen des Dateisystems, mit denen Sie docker 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.