Erweiterte mehrstufige Build-Vorlagen

Bild


Mit der mehrstufigen Erstellungsfunktion in Dockerfiles können Sie kleine Container-Images mit einem höheren Caching-Level und weniger Schutz erstellen. In diesem Artikel zeige ich Ihnen einige erweiterte Vorlagen - etwas mehr als das Kopieren von Dateien zwischen Erstellen und Ausführen. Sie ermöglichen es Ihnen, Funktionen mit maximaler Effizienz zu erreichen. Wenn Sie jedoch ein Anfänger auf dem Gebiet der mehrstufigen Montage sind, ist es wahrscheinlich nicht verkehrt, zuerst das Benutzerhandbuch zu lesen.


Versionskompatibilität


Docker wurde in Version 17.05 um mehrstufige Build-Unterstützung erweitert. Alle Vorlagen funktionieren mit jeder nachfolgenden Version, aber einige sind dank der Linker , die die BuildKit- Serverseite verwenden, viel effizienter. Angenommen, BuildKit überspringt effektiv nicht verwendete Phasen und erstellt, wenn möglich, gleichzeitig Phasen (ich habe diese Beispiele separat hervorgehoben). BuildKit wird derzeit als experimentelles Backend für den Build zu Moby hinzugefügt und sollte in Docker CE v18.06 verfügbar sein. Es kann auch autonom oder als Teil des img- Projekts verwendet werden.




Bühnenvererbung


Der mehrstufige Build fügt mehrere neue Syntaxkonzepte hinzu. Zunächst können Sie der Stufe, die mit dem FROM Befehl AS stagename den Namen AS stagename und die --from=stagename im COPY um Dateien aus dieser Stufe zu kopieren. Tatsächlich haben der FROM Befehl und das Label --from viel mehr gemeinsam, nicht umsonst, dass sie denselben Namen haben. Beide verwenden dasselbe Argument, erkennen es und starten entweder ab diesem Punkt eine neue Phase oder verwenden es als Quelle zum Kopieren der Datei. Das heißt, um die vorherige Stufe in der ursprünglichen Bildqualität für die aktuelle Stufe zu verwenden, können Sie nicht nur --from=stagename , sondern auch den FROM stagename . Es ist nützlich, wenn Sie dieselben gemeinsamen Teile in mehreren Befehlen in der Docker-Datei verwenden: Es reduziert den allgemeinen Code und vereinfacht die Wartung, wobei die untergeordneten Schritte getrennt bleiben. Das Wiederherstellen einer Stufe wirkt sich daher nicht auf den Assemblycache für andere aus. Dementsprechend kann jede Stufe beim Aufrufen von docker build einzeln mit dem Label --target .


 FROM ubuntu AS base RUN apt-get update && apt-get install git FROM base AS src1 RUN git clone … FROM base as src2 RUN git clone … 

In diesem Beispiel werden die zweite und dritte Phase in BuildKit gleichzeitig erstellt.


Direkte Verwendung von Bildern


Anstatt Baugruppennamen in FROM Befehlen zu verwenden, die bisher nur --from unterstützten, können Sie Bilder direkt mit der Bezeichnung --from . Es stellt sich heraus, dass Dateien direkt von diesen Bildern kopiert werden. Beispielsweise linuxkit/ca-certificatesimage im folgenden Code die TLS-CA-Roots direkt in die aktuelle Phase.


 FROM alpine COPY --from=linuxkit/ca-certificates / / 

Allgemeiner Bildalias


Die Erstellungsphase enthält nicht unbedingt Befehle. Es kann aus einer einzelnen FROM Zeile bestehen. Wenn Sie das Bild an mehreren Stellen verwenden, vereinfacht dies das Lesen und macht es so, dass Sie nur eine Zeile ändern müssen, wenn Sie das Gesamtbild aktualisieren müssen.


 FROM alpine:3.6 AS alpine FROM alpine RUN … FROM alpine RUN … 

In diesem Beispiel ist jeder Ort, der das alpine Bild verwendet, tatsächlich alpine:3.6 , nicht alpine:latest . Wenn die Zeit für ein Upgrade auf alpine:3.7 , müssen Sie eine einzelne Zeile ändern, und es besteht kein Zweifel: Jetzt verwenden alle Elemente der Baugruppe eine aktualisierte Version.


Dies ist umso wichtiger, wenn das Build-Argument im Alias ​​verwendet wird. Das folgende Beispiel ähnelt dem vorherigen, ermöglicht dem Benutzer jedoch die Neudefinition aller Instanzen der Assembly, an denen das --build-arg ALPINE_VERSION=value beteiligt ist, indem die Option --build-arg ALPINE_VERSION=value . Denken Sie daran: Alle in FROM Befehlen verwendeten Argumente müssen vor der ersten Erstellungsphase ermittelt werden .


 ARG ALPINE_VERSION=3.6 FROM alpine:${ALPINE_VERSION} AS alpine FROM alpine RUN … 

Verwenden von Build-Argumenten in "- from"


Der in der Bezeichnung --from des COPY angegebene Wert darf keine Assembly-Argumente enthalten. Das folgende Beispiel ist beispielsweise ungültig.


 // THIS EXAMPLE IS INTENTIONALLY INVALID FROM alpine AS build-stage0 RUN … FROM alpine ARG src=stage0 COPY --from=build-${src} . . 

Dies liegt daran, dass die Abhängigkeiten zwischen den Stufen vor Beginn der Montage ermittelt werden müssen. Dann ist eine ständige Bewertung aller Teams nicht erforderlich. Beispielsweise kann eine in einem --from definierte Umgebungsvariable die Auswertung des Werts --from . Der Grund, warum wir die Argumente des FROM Befehls auswerten können, liegt darin, dass diese Argumente global definiert werden, bevor eine Phase beginnt. Wie wir bereits herausgefunden haben, reicht es glücklicherweise aus, die Stufe des Alias ​​mit einem FROM Befehl zu definieren und darauf zu verweisen.


 ARG src=stage0 FROM alpine AS build-stage0 RUN … FROM build-${src} AS copy-src FROM alpine COPY --from=copy-src . . 

Wenn Sie nun das Assembly-Argument src überschreiben, wechselt der erste Schritt für das letzte COPY Element. Bitte beachten Sie: Wenn einige Schritte nicht mehr verwendet werden, können sie nur von BuildKit-basierten Linkern effektiv übersprungen werden.


Bedingungen mit Build-Argumenten


Wir wurden gebeten, der Docker-Datei Unterstützung für IF/ELSE Bedingungen hinzuzufügen. Wir wissen noch nicht, ob wir etwas Ähnliches hinzufügen werden, aber in Zukunft werden wir versuchen, den Client-Support in BuildKit zu verwenden. Um ein ähnliches Verhalten zu erzielen, können Sie in der Zwischenzeit die aktuellen mehrstufigen Konzepte verwenden (mit etwas Planung).


 // THIS EXAMPLE IS INTENTIONALLY INVALID FROM alpine RUN … ARG BUILD_VERSION=1 IF $BUILD_VERSION==1 RUN touch version1 ELSE IF $BUILD_VERSION==2 RUN touch version2 DONE RUN … 

Das vorherige Beispiel zeigt Pseudocode zum Aufzeichnen von Bedingungen unter Verwendung von IF/ELSE . Um ein ähnliches Verhalten mit den aktuellen mehrstufigen Builds zu erzielen, müssen Sie möglicherweise verschiedene Verzweigungsbedingungen als separate Schritte definieren und ein Argument verwenden, um den richtigen Abhängigkeitspfad auszuwählen.


 ARG BUILD_VERSION=1 FROM alpine AS base RUN … FROM base AS branch-version-1 RUN touch version1 FROM base AS branch-version-2 RUN touch version2 FROM branch-version-${BUILD_VERSION} AS after-condition FROM after-condition RUN … 

Der letzte Schritt in der Docker-Datei basiert auf dem Schritt after-condition , bei dem es sich um den BUILD_VERSION (der anhand des Build- BUILD_VERSION erkannt wird). Abhängig vom Wert von BUILD_VERSION wird diese oder jene Stufe des Mittelteils ausgewählt.


Bitte beachten Sie: Nur BuildKit-basierte Linker können nicht verwendete Zweige überspringen. In den vorherigen Versionen der Linker wurden alle Phasen erstellt, aber bevor das endgültige Image erstellt wurde, wurden ihre Ergebnisse verworfen.


Entwicklungs- / Testassistent für die Mindestproduktionsphase


Lassen Sie uns abschließend ein Beispiel für das Kombinieren früherer Vorlagen betrachten, um zu demonstrieren, wie eine Docker-Datei erstellt wird, die ein minimales Produktionsabbild erstellt und dann deren Inhalt zum Testen und Erstellen eines Entwicklungsabbilds verwenden kann. Beginnen wir mit dem grundlegenden Dockerfile-Beispiel:


 FROM golang:alpine AS stage0 … FROM golang:alpine AS stage1 … FROM scratch COPY --from=stage0 /binary0 /bin COPY --from=stage1 /binary1 /bin 

Wenn ein minimales Produktionsabbild erstellt wird, ist dies eine recht häufige Option. Was aber, wenn Sie im Endstadium auch ein alternatives Entwickler-Image benötigen oder Tests mit diesen Binärdateien ausführen müssen? Das erste, was mir in den Sinn kommt, ist einfach, ähnliche Binärdateien in den Phasen des Testens und der Entwicklung zu kopieren. Das Problem ist folgendes: Es gibt keine Garantie dafür, dass Sie alle Produktions-Binärdateien in derselben Kombination testen. In der letzten Phase kann sich etwas ändern, aber Sie werden vergessen, ähnliche Änderungen in anderen Phasen vorzunehmen oder einen Fehler beim Kopieren von Binärdateien zu machen. Am Ende testen wir nicht eine separate Binärdatei, sondern das endgültige Bild.


Eine Alternative besteht darin, die Entwicklungs- und Testphase nach der Produktionsphase zu bestimmen und den gesamten Inhalt der Produktionsphase zu kopieren. Verwenden Sie dann einen FROM Befehl für den Produktionsschritt, um den Standardproduktionsschritt erneut zum letzten Schritt zu machen.


 FROM golang:alpine AS stage0 … FROM scratch AS release COPY --from=stage0 /binary0 /bin COPY --from=stage1 /binary1 /bin FROM golang:alpine AS dev-env COPY --from=release / / ENTRYPOINT ["ash"] FROM golang:alpine AS test COPY --from=release / / RUN go test … FROM release 

Standardmäßig erstellt diese Docker-Datei weiterhin das minimale Standard-Image, während beispielsweise eine Assembly mit der Option --target=dev-env ein Image mit einer Shell erstellt, die alle Binärdateien der endgültigen Version enthält.




Ich hoffe, dies war hilfreich und schlug vor, wie effizientere mehrstufige Docker-Dateien erstellt werden können. Wenn Sie an DockerCon2018 teilnehmen und mehr über mehrstufige Builds, Dockerfiles, BuildKit oder verwandte Themen erfahren möchten, melden Sie sich für den Hallway-Track- Linker an oder folgen Sie den internen Meetings der Docker-Plattform zu Contribute and Collaborate- oder Black Belt- Tracks.

Source: https://habr.com/ru/post/de433790/


All Articles