Hei alle sammen! Jeg heter Andrei, og jeg jobber som DevOps-ingegør hos Exness i utviklingsteamet. Mitt hovedarbeid er relatert til bygging, distribusjon og støtte av applikasjoner i docker på operativsystemet Linux (heretter kalt OS). For ikke så lenge siden fikk jeg en oppgave med de samme aktivitetene, men denne gangen skulle prosjektet være på Windows Server og en rekke prosjekter skrevet i C++. Dette var min første dype interaksjon med docker-beholdere på Windows OS og generelt med applikasjoner skrevet i C++. Dette ga meg interessant erfaring og innsikt i noen av nyansene ved applikasjonscontainerisering i Windows OS.

I denne artikkelen vil jeg dele hvilke utfordringer jeg støtte på, og hvordan jeg klarte å løse dem. Jeg håper dette vil være nyttig for å løse dine nåværende og fremtidige oppgaver. God lesning!
Hvorfor containere?
Selskapet har en eksisterende infrastruktur for containerorkestrering ved hjelp av Hashicorp Nomad og relaterte komponenter — Consul og Vault. Derfor ble containerisering av applikasjoner valgt som en enhetlig metode for levering av ferdige løsninger. Siden prosjektinfrastrukturen har docker-verter med versjoner av Windows Server Core 1803 og 1809, må docker-bilder for 1803 og 1809 bygges separat. I versjon 1803 er det viktig å huske at revisjonsnummeret til bygge-docker-verten må samsvare med revisjonsnummeret til det grunnleggende docker-bildet og verten der containeren fra dette bildet vil bli kjørt. Versjon 1809 har ikke denne ulempen. Mer informasjon kan leses .
Hvorfor multi-stage?
Utviklerteamets ingeniører har ikke tilgang til byggevertner eller har veldig begrenset tilgang, og det er ikke mulig å administrere komponentene for å bygge applikasjonen effektivt på disse vertene, for eksempel installere et ekstra verktøysett eller arbeidsbelastning for Visual Studio. Derfor har vi besluttet at alle nødvendige komponenter for å bygge applikasjonen skal installeres i bygge-docker-bildet. Ved behov kan dockerfilen raskt endres, og byggpipen for dette bildet kan startes.
Fra teori til praksis
I den ideelle docker multi-stage byggingen av bildet skjer miljøforberedelsen for å bygge applikasjonen i samme dockerfile-script som selve applikasjonsbyggingen. Men i vårt tilfelle ble det lagt til et mellomledd, nemlig trinnet for forhåndsskaping av docker-bildet med alt nødvendig for å bygge applikasjonen. Dette ble gjort fordi vi ønsket å benytte oss av mulighetene for docker-cache for å redusere installasjonstiden for alle avhengigheter.
La oss gå gjennom hovedpunktene i dockerfile-scriptet for å danne dette bildet.
For å opprette bilder av forskjellige operativsystemversjoner i dockerfile kan du definere et argument som versjonsnummeret overføres under byggingen, som også er taggen for basisbildet.
En fullstendig liste over tagger for Microsoft Windows Server-bilder finner du .
ARG WINDOWS_OS_VERSION=1809
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSIONSom standard utføres kommandoene i instruksjonene RUN inne i dockerfile i Windows-operativsystemet i cmd.exe-konsollen. For å gjøre skriptveksten enklere og utvide funksjonaliteten til de brukte kommandoene vil vi overstyre konsollen for kommandoutførelse til Powershell via instruksjonen SHELL.
SHELL ["powershell", "-Command", "$ErrorActionPreference = 'Stop';"]Det neste trinnet er å installere pakkebehandleren chocolatey og 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 å installere pakker ved bruk av chocolatey kan du ganske enkelt overføre dem som en liste eller installere en om gangen hvis du trenger å spesifisere unike parametere for hver pakke. I vår situasjon brukte vi en manifestfil i XML-format som spesifiserer listen over nødvendige pakker og deres parametere. Innholdet ser slik ut:
Deretter installerer vi utviklingsmiljøet for applikasjonen, nemlig MS Build Tools 2019 – dette er en lettvektsversjon av Visual Studio 2019 som inneholder det minimale nødvendige settet av komponenter for å kompilere kode.
For å kunne jobbe ordentlig med C++-prosjektet vårt trenger vi tilleggskomponenter, nemlig:
- Arbeidsbelastning C++ verktøy
- Verktøysett v141
- Windows 10 SDK (10.0.17134.0)
Du kan installere det utvidede verktøysettet automatisk ved hjelp av en konfigurasjonsfil i JSON-format. Innholdet i konfigurasjonsfilen:
Den fullstendige listen over tilgjengelige komponenter finnes på dokumentasjonsnettsiden .
{
"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 kjører et installasjonsskript, og for enkelhets skyld legges banen til kjørbare filer for build-verktøyene til miljøvariabelen. PATH. Det er også ønskelig å fjerne unødvendige filer og kataloger for å redusere størrelsen på bildet.
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 punktet er vårt bilde for å kompilere C++-applikasjonen klart, og vi kan begynne å opprette docker multi-stage bygget for applikasjonen.
Multi-stage i aksjon
Som byggbilde vil vi bruke det opprettede bildet med alle verktøyene ombord. Som i det forrige dockerfile-skriptet vil vi legge til muligheten til dynamisk å spesifisere versjonsnummer/tag for bekvemmelighets skyld ved gjenbruk av koden. Det er viktig å legge til et merke som bygger til byggbildet i instruksjonen FROM.
ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builderDet er tid for å bygge applikasjonen. Her er alt ganske enkelt: kopier kildekoden og alt som er relatert til den, og start kompilasjonsprosessen.
COPY myapp .
RUN nuget restore myapp.sln ;
msbuild myapp.sln /t:myapp /p:Configuration=ReleaseDen avsluttende fasen for å opprette det endelige bildet er å spesifisere basebildet for applikasjonen, hvor alle kompilasjonsartefakter og konfigurasjonsfiler vil bli plassert. For å kopiere de kompilerte filene fra det mellomliggende byggebildet må du spesifisere parameteren --from=builder i instruksjonen COPY.
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSION
COPY --from=builder C:/x64/Release/myapp/ ./
COPY ./configs ./Nå gjenstår det bare å legge til de nødvendige avhengighetene for at applikasjonen vår skal fungere og spesifisere oppstartskommand gjennom instruksjonene. ENTRYPOINT eller CMD.
Konklusjon
I denne artikkelen forklarer jeg hvordan man kan opprette et fullverdig utviklingsmiljø for C++-applikasjoner i en container på Windows, samt hvordan man kan bruke funksjonene i docker multi-stage byggen til å lage komplette bilder av applikasjonen vår.
Kilde: habr.com
