Verwendung von Docker Multi-Stage zum Erstellen von Windows-Images.

Hallo zusammen! Mein Name ist Andrey und ich arbeite als DevOps-Ingenieur bei Exness im Entwicklungsteam. Meine Haupttätigkeit besteht aus dem Aufbau, der Bereitstellung und der Unterstützung von Anwendungen in Docker unter dem Betriebssystem Linux. Kürzlich wurde ich mit der selben Aufgabe konfrontiert, jedoch sollte das Zielbetriebssystem des Projekts Windows Server sein und es handelte sich um eine Reihe von Projekten in C++. Für mich war dies die erste intensive Auseinandersetzung mit Docker-Containern unter Windows und insgesamt mit Anwendungen in C++. Dadurch habe ich wertvolle Erfahrungen gesammelt und einige Feinheiten der Containerisierung von Anwendungen unter Windows kennengelernt.

Verwendung von Docker Multi-Stage zum Erstellen von Windows-Images.

In diesem Artikel möchte ich erzählen, mit welchen Herausforderungen ich konfrontiert war und wie ich sie lösen konnte. Ich hoffe, dass dies nützlich für die Bewältigung Ihrer aktuellen und zukünftigen Aufgaben ist. Viel Spaß beim Lesen!

Warum Container?

Unsere Firma verfügt über eine bestehende Infrastruktur des Container-Orchestrators Hashicorp Nomad sowie über die zugehörigen Komponenten — Consul und Vault. Daher wurde die Containerisierung von Anwendungen als einheitliche Methode zur Bereitstellung einer vollständigen Lösung gewählt. Da in der Projektinfrastruktur Docker-Hosts mit den Windows Server Core-Versionen 1803 und 1809 vorhanden sind, müssen separate Versionen der Docker-Images für 1803 und 1809 erstellt werden. Bei Version 1803 ist es wichtig, dass die Build-Revision des Docker-Hosts mit der Revision des Basis-Docker-Images sowie mit dem Host, auf dem der Container aus diesem Image gestartet wird, übereinstimmt. Die Version 1809 hat dieses Problem nicht. Weitere Informationen finden Sie hier. hier.

Warum Multi-Stage?

Entwicklerteams haben keinen oder nur eingeschränkten Zugang zu den Build-Hosts. Es gibt keine Möglichkeit, schnell auf eine Sammlung von Komponenten zuzugreifen, die zum Erstellen der Anwendung auf diesen Hosts benötigt werden, zum Beispiel zur Installation zusätzlicher Toolsets oder Workloads für Visual Studio. Daher haben wir beschlossen, alle erforderlichen Komponenten für den Anwendungsbau in einem Docker-Image zu installieren. Bei Bedarf kann das Dockerfile schnell angepasst und der Pipeline zur Erstellung dieses Images gestartet werden.

Von der Theorie zur Praxis

In einer idealen Multi-Stage-Docker-Bilderstellung erfolgt die Umgebungsvorbereitung für den Anwendungsbau im selben Dockerfile-Skript, das auch den Bau der Anwendung selbst enthält. In unserem Fall haben wir jedoch eine zusätzliche Stufe hinzugefügt, nämlich den Schritt zur vorherigen Erstellung eines Docker-Images mit allem Notwendigen für den Anwendungsbau. Dies wurde so gemacht, weil wir die Möglichkeit des Docker-Caches nutzen wollten, um die Installationszeit aller Abhängigkeiten zu verkürzen.

Lassen Sie uns die wesentlichen Punkte des Dockerfile-Skripts zur Erstellung dieses Images durchgehen.

Um verschiedene Versionen des Betriebssystems im Dockerfile zu erstellen, kann ein Argument definiert werden, über das beim Bauen die Versionsnummer übergeben wird, und das ist auch das Tag des Basis-Images.

Die vollständige Liste der Tags für Microsoft Windows Server-Images finden Sie hier.

ARG WINDOWS_OS_VERSION=1809
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSION

Standardmäßig werden die Kommandos in der Anweisung RUN innerhalb des Dockerfiles unter Windows in der cmd.exe-Konsole ausgeführt. Um das Schreiben von Skripten zu erleichtern und die Funktionalität der verwendeten Befehle zu erweitern, überschreiben wir die Befehlsausführungskonsole mit PowerShell durch die Anweisung SHELL.

SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]

Im nächsten Schritt installieren wir den Paketmanager Chocolatey und die erforderlichen Pakete:

COPY chocolatey.pkg.config .
RUN Set-ExecutionPolicy Bypass -Scope Process -Force ;
    [System.Net.ServicePointManager]::SecurityProtocol = 
    [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 ;
    $env:chocolateyUseWindowsCompression = 'true' ;
    iex ((New-Object System.Net.WebClient).DownloadString( 
      'https://chocolatey.org/install.ps1')) ;
    choco install chocolatey.pkg.config -y --ignore-detected-reboot ;
    if ( @(0, 1605, 1614, 1641, 3010) -contains $LASTEXITCODE ) { 
      refreshenv; } else { exit $LASTEXITCODE; } ;
    Remove-Item 'chocolatey.pkg.config'

Um Pakete mit Chocolatey zu installieren, können Sie diese einfach als Liste übergeben oder einzeln installieren, wenn spezifische Parameter für jedes Paket erforderlich sind. In unserem Fall haben wir eine XML-Manifeste-Datei verwendet, in der die erforderlichen Pakete und deren Parameter aufgeführt sind. Der Inhalt sieht folgendermaßen aus:

Anschließend richten wir die Build-Umgebung für die Anwendung ein, und zwar mit MS Build Tools 2019 – dies ist eine erleichterte Version von Visual Studio 2019, die das minimal erforderliche Komponentenpaket zur Kompilierung von Code enthält.
Für die vollständige Bearbeitung unseres C++-Projekts benötigen wir zusätzliche Komponenten, nämlich:

  • Workload C++-Tools
  • Toolset v141
  • Windows 10 SDK (10.0.17134.0)

Die erweiterte Sammlung von Tools kann automatisiert mithilfe einer Konfigurationsdatei im JSON-Format installiert werden. Der Inhalt der Konfigurationsdatei:

Die vollständige Liste der verfügbaren Komponenten finden Sie auf der Dokumentationswebsite. Microsoft Visual Studio.

{
  "version": "1.0",
  "components": [
    "Microsoft.Component.MSBuild",
    "Microsoft.VisualStudio.Workload.VCTools;includeRecommended",
    "Microsoft.VisualStudio.Component.VC.v141.x86.x64",
    "Microsoft.VisualStudio.Component.Windows10SDK.17134"
  ]
}

Im Dockerfile wird ein Installationsskript ausgeführt und zur Vereinfachung wird der Pfad zu den ausführbaren Dateien der Build-Tools in die Umgebungsvariable eingefügt. PATHEs ist auch ratsam, nicht benötigte Dateien und Verzeichnisse zu entfernen, um die Größe des Images zu reduzieren.

COPY buildtools.config.json .
RUN Invoke-WebRequest 'https://aka.ms/vs/16/release/vs_BuildTools.exe' 
      -OutFile '.vs_buildtools.exe' -UseBasicParsing ;
    Start-Process -FilePath '.vs_buildtools.exe' -Wait -ArgumentList 
      '--quiet --norestart --nocache --config C:buildtools.config.json' ;
    Remove-Item '.vs_buildtools.exe' ;
    Remove-Item '.buildtools.config.json' ;
    Remove-Item -Force -Recurse 
      'C:Program Files (x86)Microsoft Visual StudioInstaller' ;
    $env:PATH = 'C:Program Files (x86)Microsoft Visual Studio2019BuildToolsMSBuildCurrentBin;' + $env:PATH; 
    [Environment]::SetEnvironmentVariable('PATH', $env:PATH, 
      [EnvironmentVariableTarget]::Machine)

An diesem Punkt ist unser Image zur Kompilierung der C++ Anwendung bereit, und wir können mit dem Erstellen des Docker-Multi-Stage-Baus der Anwendung beginnen.

Multi-Stage in Aktion

Wir werden ein erstelltes Abbild mit allen erforderlichen Tools verwenden. Wie im vorherigen Dockerfile-Skript fügen wir die Möglichkeit hinzu, die Version/tag des Abbilds dynamisch anzugeben, um die Wiederverwendbarkeit des Codes zu erleichtern. Es ist wichtig, ein Tag hinzuzufügen. als Builder zum Abbild in der Anweisung FROM.

ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION als Builder

Es ist Zeit, die Anwendung zu erstellen. Hier ist alles recht einfach: Den Quellcode und alle zugehörigen Dateien kopieren und den Kompilierungsprozess starten.

COPY myapp .
RUN nuget restore myapp.sln ;
    msbuild myapp.sln /t:myapp /p:Configuration=Release

Der abschließende Schritt zur Erstellung des endgültigen Abbilds ist die Angabe des Basisabbaus der Anwendung, wo sich alle Kompilierungsartefakte und Konfigurationsdateien befinden. Um die kompilierten Dateien vom Zwischenabbild zu kopieren, muss der Parameter angegeben werden --from=builder in der Anleitung COPY.

FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSION

COPY --from=builder C:/x64/Release/myapp/ ./
COPY ./configs ./

Jetzt bleibt nur noch, die erforderlichen Abhängigkeiten für unser Anwendung hinzuzufügen und den Startbefehl über Anweisungen anzugeben. ENTRYPOINT oder CMD.

Fazit

In diesem Artikel erkläre ich, wie man eine vollständige C++-Entwicklungsumgebung in einem Windows-Container aufbaut und wie man die Funktionen von Docker-Multi-Stage-Bauten nutzt, um vollwertige Images unserer Anwendung zu erstellen.

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster