Untersuchen mehrstufiger Dockerfiles

Abgeschlossen

Was sind mehrstufige Dockerfiles? Mehrstufige Builds bieten die Vorteile des Builder-Musters, ohne dabei drei separate Dateien verwalten zu müssen.

Sehen wir uns ein mehrstufiges Dockerfile an.

FROM mcr.microsoft.com/dotnet/core/aspnetcore:3.1 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /src
COPY ["WebApplication1.csproj", ""]
RUN dotnet restore "./WebApplication1.csproj"
COPY . .
WORKDIR "/src/."
RUN dotnet build "WebApplication1.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "WebApplication1.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "WebApplication1.dll"]

Zunächst sieht es einfach so aus, als ob mehrere Dockerfiles einfach zusammengeheftet wären. Mehrstufige Dockerfiles können geschichtet oder geerbt werden.

Wenn Sie genauer hinschauen, gibt es einige wichtige Dinge zu erkennen.

Beachten Sie die dritte Phase.

FROM build AS publish

build ist kein Image, das aus einer Registrierung gepullt wurde. Es ist das Image, das wir in Phase 2 definiert haben, wo wir das Ergebnis unseres Buildimages (SDK) als „Builder“ bezeichnet haben. Docker build erstellt ein benanntes Image, auf das später verwiesen werden kann.

Wir können auch die Ausgabe von einem Image in ein anderes kopieren. Das ist die eigentliche Leistung, unseren Code mit einem SDK-Basisimage (mcr.microsoft.com/dotnet/core/sdk:3.1) zu kompilieren, ung gleichzeitig ein Produktionsimage auf Grundlage eines optimierten Laufzeitimages (mcr.microsoft.com/dotnet/core/aspnet:3.1) zu erstellen. Beachten Sie die Zeile.

COPY --from=publish /app/publish .

Das Verzeichnis „/app/publish“ wird aus dem veröffentlichten Image kopiert und in das Arbeitsverzeichnis des Produktionsimages eingefügt.

Aufschlüsselung der Phasen

Die erste Phase stellt die Basis unseres optimierten Laufzeitimages bereit. Beachten Sie, dass sie sich von mcr.microsoft.com/dotnet/core/aspnet:3.1 ableitet.

Wir würden zusätzliche Produktionskonfigurationen angeben, z. B. Registrierungskonfigurationen, MSIexec anderer Komponenten. Sie würden jede dieser Umgebungskonfigurationen an Ihr Ops-Team übergeben, um die VM vorzubereiten.

Die zweite Phase ist unsere Buildumgebung. mcr.microsoft.com/dotnet/core/sdk:3.1 Dies schließt alles ein, was wir zum Kompilieren unseres Codes benötigen. Ab hier haben wir kompilierte Binärdateien, die wir veröffentlichen oder testen können – mehr zum Testen in Kürze.

Die dritte Phase leitet sich von unserer Buildphase ab. Sie übernimmt die kompilierte Ausgabe und „veröffentlicht“ sie gemäß der .NET-Terminologie.

Veröffentlichen bedeutet, dass die gesamte Ausgabe, die zum Bereitstellen Ihrer „app/publish/service/component“ erforderlich ist, in einem einzigen Verzeichnis abgelegt wird. Dazu gehören ihre kompilierten Binärdateien, Grafiken (Bilder), JavaScript usw.

In der vierten Phase wird die veröffentlichte Ausgabe im optimierten Image abgelegt, das wir in der ersten Phase definiert haben.

Warum erfolgt die Veröffentlichung (publish) vom Build getrennt?

Wahrscheinlich möchten Sie Komponententests ausführen, um Ihren kompilierten Code zu überprüfen. Oder das Aggregat des kompilierten Codes von mehreren Entwicklern, der zusammengeführt wird, funktioniert weiterhin wie erwartet.

Zum Ausführen von Komponententests können Sie die folgende Phase zwischen Builder und Veröffentlichung platzieren.

FROM build AS test
WORKDIR /src/Web.test
RUN dotnet test

Wenn Ihre Tests fehlschlagen, wird der Build nicht fortgesetzt.

Warum die Basis zuerst?

Sie könnten argumentieren, dass dies einfach der logische Ablauf ist. Zunächst definieren wir das Basislaufzeitimage. Bereiten Sie die kompilierte Ausgabe vor, und legen Sie sie im Basisimage ab.

Dies ist jedoch praktischer. Wenn Sie Ihre Anwendungen mit den Visual Studio-Containertools debuggen, debuggt VS Ihren Code direkt im Basisimage.

Wenn Sie F5 drücken, kompiliert Visual Studio den Code auf Ihrem Entwicklungscomputer. In der ersten Phase wird die Ausgabe dann als Volume in das erstellte Laufzeitimage eingebunden.

Sie können alle Konfigurationen testen, die Sie an Ihrem Produktionsimage vorgenommen haben, z. B. Registrierungskonfigurationen oder andere.

Im Anschluss an die Ausführung von docker build --target base, beginnt Docker mit der Verarbeitung des Dockerfile vom Anfang bis zur definierten Phase (Ziel).

Da die Basis die erste Phase ist, nehmen wir den kürzesten Weg, um die F5-Erfahrung so schnell wie möglich zu gestalten.

Befände sich die Basis hinter der Kompilierung (Builder/Generator), müssten Sie warten, bis alle weiteren Schritte abgeschlossen sind.

Eine der Leistungsoptimierungen, die wir mit VS-Containertools vornehmen, besteht in der Nutzung der Visual Studio-Kompilierungen auf Ihrem Entwicklungscomputer.