Hej alle sammen! Jeg hedder Andrey, og jeg arbejder som DevOps-ingeniør i Exness i udviklingsteamet. Mit primære arbejde involverer opbygning, deployment og vedligeholdelse af applikationer i Docker under operativsystemet Linux (herefter - OS). For ikke så længe siden fik jeg til opgave at udføre de samme aktiviteter, men i denne omgang blev Windows Server den målrettede OS for projektet med et sæt projekter i C++. Det var for mig første gang, jeg havde intensivt samarbejde med Docker-containere under OS Windows, samt med applikationer skrevet i C++. Dette har givet mig en interessant erfaring og viden om nogle af nuancerne ved containerisering af applikationer i OS Windows.

I denne artikel vil jeg fortælle om de udfordringer, jeg stødte på, og hvordan jeg fik løst dem. Jeg håber, dette vil være nyttigt for at løse jeres nuværende og fremtidige opgaver. God læsning!
Hvorfor containere?
Virksomheden har en eksisterende infrastruktur for containerorkestratoren Hashicorp Nomad og tilknyttede komponenter - Consul og Vault. Derfor blev containerisering af applikationer valgt som en ensartet metode til levering af en færdig løsning. Da der i projektets infrastruktur er Docker-værter med versioner af Windows Server Core 1803 og 1809, skal der bygges separate versioner af Docker-billeder for 1803 og 1809. I version 1803 er det vigtigt at huske, at revisionsnummeret på den byggede Docker-vært skal matche revisionsnummeret på den grundlæggende Docker-billede og værten, hvor containeren fra dette billede vil blive kørt. Version 1809 har ikke denne ulempe. Læs mere .
Hvorfor multi-stage?
Ingeniører i udviklingsteam har ingen eller stærkt begrænset adgang til byggede værter, og der er ikke mulighed for hurtigt at styre sæt af komponenter til opbygning af applikationen på disse værter, for eksempel ved at installere et ekstra toolset eller workload til Visual Studio. Derfor besluttede vi at installere alle nødvendige komponenter til opbygning af applikationen i det byggede Docker-billede. Ved behov kan man hurtigt ændre kun Dockerfile og starte pipeline til oprettelse af dette billede.
Fra teori til praksis
I en ideel docker multi-stage opbygning af billedet foregår forberedelsen af miljøet til opbygning af applikationen i den samme dockerfile-script som selve opbygningen af applikationen. Men i vores tilfælde blev der tilføjet et mellemlag, nemlig et trin til forberedelse af docker-billedet med alt, hvad der er nødvendigt for at bygge applikationen. Dette blev gjort, fordi vi ønskede at udnytte muligheden for docker-cache for at forkorte tiden til installation af alle afhængigheder.
Lad os gennemgå de vigtigste punkter i dockerfile-scriptet til opbygning af dette billede.
For at oprette billeder af forskellige versioner af OS i dockerfile kan man definere en argument, som sender versionsnummeret, og som også er tagget på basisbilledet.
Den fulde liste over tags til Microsoft Windows Server-billeder kan findes .
ARG WINDOWS_OS_VERSION=1809
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSIONSom standard udføres kommandoerne i instruktionen RUN inde i dockerfile på Windows OS i cmd.exe-konsollen. For at gøre det nemmere at skrive scripts og udvide funktionaliteten af de anvendte kommandoer, vil vi ændre kommandokonsollen til Powershell via instruktionen SHELL.
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]Det næste trin er at installere pakkestyren chocolatey og de nødvendige pakker:
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'For at installere pakker med chocolatey kan man simpelthen sende dem som en liste eller installere dem enkeltvis, hvis det er nødvendigt at sende unikke parametre for hver pakke. I vores tilfælde brugte vi en manifestfil i XML-format, der angiver listen over nødvendige pakker og deres parametre. Indholdet ser sådan ud:
Derefter installerer vi byggemiljøet for applikationen, nemlig MS Build Tools 2019 — en letvægtsversion af Visual Studio 2019, der indeholder det minimalt nødvendige sæt af komponenter til at kompilere kode.
For at arbejde ordentligt med vores C++-projekt har vi brug for yderligere komponenter, nemlig:
- Workload C++ tools
- Toolset v141
- Windows 10 SDK (10.0.17134.0)
Det udvidede værktøjssæt kan installeres automatisk ved hjælp af en konfigurationsfil i JSON-format. Indholdet af konfigurationsfilen er:
Den fulde liste over tilgængelige komponenter kan findes på dokumentationssiden .
{
"version": "1.0",
"components": [
"Microsoft.Component.MSBuild",
"Microsoft.VisualStudio.Workload.VCTools;includeRecommended",
"Microsoft.VisualStudio.Component.VC.v141.x86.x64",
"Microsoft.VisualStudio.Component.Windows10SDK.17134"
]
}I dockerfile udføres installationsscriptet, og for nemheds skyld tilføjes stien til eksekverbare filer fra build tools til miljøvariablen PATH. Det er også ønskeligt at fjerne unødvendige filer og mapper for at reducere billedstørrelsen.
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)På dette tidspunkt er vores billede til compilation af C++ applicationen klar, og vi kan begynde selve oprettelsen af docker multi-stage bygge applikationen.
Multi-stage i aktion
Som bygge billede skal vi bruge det oprettede billede med alt værktøjet ombord. Som i det tidligere dockerfile-script tilføjer vi mulighed for dynamisk at angive versionsnummer/tag for at lette genbrug af kode. Det er vigtigt at tilføje en etikette as builder til bygge billedet i instruktionen FROM.
ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builderDet er tid til at bygge applikationen. Her er alt ret simpelt: kopier kildekoden og alt relateret, og start compilationsprocessen.
COPY myapp .
RUN nuget restore myapp.sln ;
msbuild myapp.sln /t:myapp /p:Configuration=ReleaseDen afsluttende fase af at oprette det endelige billede er at angive det grundlæggende billede for applikationen, hvor alle compilationsartefakter og konfigurationsfiler vil blive placeret. For at kopiere de kompilerede filer fra det mellemliggende bygge billede skal du angive parameteren --from=builder i manualen COPY.
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSION
COPY --from=builder C:/x64/Release/myapp/ ./
COPY ./configs ./Nu skal vi tilføje de nødvendige afhængigheder for at køre vores applikation og angive startkommandoen gennem instruktionerne ENTRYPOINT eller CMD.
Konklusion
I denne artikel beskriver jeg, hvordan man opretter et komplet C++ udviklingsmiljø inde i en container på Windows, og hvordan man bruger docker multi-stage builds til at skabe færdige billeder af vores applikation.
Kilde: habr.com
