Hallo zusammen! Ich bin Andrej und arbeite als DevOps-Ingenieur bei Exness im Entwicklungsteam. Mein Hauptaugenmerk liegt auf dem Erstellen, Bereitstellen und Unterstützen von Anwendungen in Docker unter dem Betriebssystem Linux (im Folgenden OS). Kürzlich erhielt ich die Aufgabe, die gleichen Aktivitäten durchzuführen, aber als Zielbetriebssystem für das Projekt wurde Windows Server und ein Satz von Projekten in C++ ausgewählt. Dies war meine erste intensive Interaktion mit Docker-Containern unter Windows und im Allgemeinen mit Anwendungen in C++. Dadurch konnte ich interessante Erfahrungen sammeln und einige Feinheiten der Containerisierung von Anwendungen unter Windows kennenlernen.

In diesem Artikel möchte ich darüber berichten, mit welchen Schwierigkeiten ich konfrontiert war und wie ich sie lösen konnte. Ich hoffe, es ist hilfreich für Ihre aktuellen und zukünftigen Aufgaben. Viel Spaß beim Lesen!
Warum Container?
Im Unternehmen gibt es eine bestehende Infrastruktur für den Container-Orchestrator Hashicorp Nomad und damit verbundene Komponenten – Consul und Vault. Daher wurde die Containerisierung von Anwendungen als einheitliche Methode für die Bereitstellung einer fertigen Lösung gewählt. Da in der Infrastruktur des Projekts Docker-Hosts mit den Versionen Windows Server Core 1803 und 1809 vorhanden sind, müssen die Docker-Images separat für 1803 und 1809 erstellt werden. Bei Version 1803 ist es wichtig, dass die Revision des Docker-Hosts mit der Revision des Basis-Docker-Images und des Hosts, auf dem der Container aus diesem Image gestartet wird, übereinstimmt. Die Version 1809 hat diesen Nachteil nicht. Weitere Informationen finden Sie .
Warum Multi-Stage?
Die Ingenieure der Entwicklungsteams haben keinen oder nur stark eingeschränkten Zugriff auf die Build-Hosts und können nicht schnell die benötigten Komponenten für den Build der Anwendung auf diesen Hosts verwalten, zum Beispiel kein zusätzliches Toolset oder Workload für Visual Studio installieren. Daher haben wir beschlossen – alle notwendigen Komponenten für den Build der Anwendung im Docker-Image zu installieren. Bei Bedarf kann das Dockerfile relativ schnell geändert und die Pipeline zur Erstellung dieses Images gestartet werden.
Vom Theorie zur Praxis
In einer idealen Docker-Multi-Stage-Bauweise erfolgt die Vorbereitung der Umgebung für den App-Bau im selben Dockerfile-Skript wie der Bau der App selbst. In unserem Fall wurde jedoch ein Zwischenschritt hinzugefügt, nämlich der Schritt zur vorläufigen Erstellung des Docker-Images mit allem Notwendigen für den Bau der App. Dies wurde getan, um die Möglichkeit des Docker-Caches zu nutzen und die Installationszeit aller Abhängigkeiten zu verkürzen.
Lassen Sie uns die wichtigsten Punkte des Dockerfile-Skripts zur Erstellung dieses Images durchgehen.
Um Images verschiedener Betriebssystemversionen zu erstellen, kann im Dockerfile ein Argument definiert werden, über das während des Builds die Versionsnummer übergeben wird, und dies ist auch das Tag des Basis-Images.
Die vollständige Liste der Tags für Microsoft Windows Server-Images finden Sie .
ARG WINDOWS_OS_VERSION=1809
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSIONStandardmäßig werden die Befehle in der Anweisung RUN innerhalb des Dockerfiles unter Windows in der cmd.exe-Konsole ausgeführt. Zur Vereinfachung des Schreibens von Skripten und zur Erweiterung der Funktionalität der verwendeten Befehle überschreiben wir die Befehlsausführungskonsole auf Powershell mit der Anweisung SHELL.
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]Als nächstes installieren wir den Paketmanager Chocolatey und die benötigten 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, kann man einfach eine Liste übergeben oder sie einzeln installieren, wenn einzigartige Parameter für jedes Paket übergeben werden müssen. In unserer Situation haben wir eine Manifestdatei im XML-Format verwendet, in der die Liste der erforderlichen Pakete und deren Parameter angegeben ist. Ihr Inhalt sieht so aus:
Danach installieren wir die Build-Umgebung für die App, nämlich die MS Build Tools 2019 — eine schlankere Version von Visual Studio 2019, die die minimal erforderlichen Komponenten zur Code-Komplierung enthält.
Für die vollständige Arbeit an unserem C++-Projekt benötigen wir zusätzliche Komponenten, und zwar:
- Workload C++ tools
- Toolset v141
- Windows 10 SDK (10.0.17134.0)
Die erweiterte Werkzeugausstattung kann im automatischen Modus mithilfe einer Konfigurationsdatei im JSON-Format installiert werden. Der Inhalt der Konfigurationsdatei:
Eine vollständige Liste der verfügbaren Komponenten finden Sie auf der Dokumentationswebsite .
{
"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 das Installationsskript ausgeführt, und zur Vereinfachung wird der Pfad zu den ausführbaren Dateien der Build-Tools in die Umgebungsvariable aufgenommen. 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)In diesem Schritt ist unser Image zur Kompilierung der C++-Anwendung bereit, und wir können mit dem Erstellen der Docker-Multi-Stage-Builds für die Anwendung beginnen.
Multi-Stage in Aktion
Als Build-Image verwenden wir das erstellte Image mit allen benötigten Werkzeugen. Wie im vorherigen Dockerfile-Skript fügen wir die Möglichkeit hinzu, die Versionsnummer / das Tag des Images dynamisch anzugeben, um den Code besser wiederverwenden zu können. Es ist wichtig, das Label as builder im Build-Image in der Anweisung hinzuzufügen FROM.
ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builderJetzt ist der Moment gekommen, die Anwendung zu erstellen. Hier ist alles ziemlich einfach: den Quellcode und alles, was damit verbunden ist, kopieren und den Kompilierungsprozess starten.
COPY myapp .
RUN nuget restore myapp.sln ;
msbuild myapp.sln /t:myapp /p:Configuration=ReleaseDer letzte Schritt bei der Erstellung des endgültigen Images besteht darin, das Basis-Image der Anwendung anzugeben, in dem alle Artefakte der Kompilierung und die Konfigurationsdateien untergebracht werden. Um die kompilierten Dateien vom Zwischen-Build-Image zu kopieren, müssen wir den Parameter --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 den Betrieb unserer Anwendung hinzuzufügen und den Startbefehl in den Anweisungen anzugeben ENTRYPOINT oder CMD.
Fazit
In diesem Artikel habe ich erklärt, wie man eine vollständige C++-Entwicklungsumgebung innerhalb eines Containers unter Windows erstellen kann und wie man die Möglichkeiten von Docker-Multi-Stage-Bauten nutzt, um vollständige Images unserer Anwendung zu erstellen.
Quelle: habr.com
