Bruke docker multi-stage for å bygge Windows-bilder

Hei alle sammen! Jeg heter Andrey, og jeg jobber som DevOps-ingeniør hos Exness i utviklingsteamet. Min hovedaktivitet er knyttet til å bygge, distribuere og støtte applikasjoner i docker under Linux-operativsystemet (heretter referert til som OS). For ikke lenge siden hadde jeg en oppgave med de samme aktivitetene, men målet OS for prosjektet var Windows Server og et sett med C++-prosjekter. For meg var dette den første nære interaksjonen med docker-containere under Windows OS og generelt med C++-applikasjoner. Takket være dette hadde jeg en interessant opplevelse og lærte om noen av vanskelighetene med å samle applikasjoner i Windows.

Bruke docker multi-stage for å bygge Windows-bilder

I denne artikkelen vil jeg fortelle deg hvilke vanskeligheter jeg måtte møte og hvordan jeg klarte å løse dem. Jeg håper dette er nyttig for dine nåværende og fremtidige utfordringer. Liker å lese!

Hvorfor containere?

Selskapet har eksisterende infrastruktur for Hashicorp Nomad container orkestrator og tilhørende komponenter - Consul og Vault. Derfor ble applikasjonscontainerisering valgt som en enhetlig metode for å levere en komplett løsning. Siden prosjektinfrastrukturen inneholder docker-verter med Windows Server Core OS versjoner 1803 og 1809, er det nødvendig å bygge separate versjoner av docker-bilder for 1803 og 1809. I versjon 1803 er det viktig å huske at revisjonsnummeret til build docker-verten må samsvare med revisjonsnummeret til base docker-bildet og verten der beholderen fra dette bildet vil bli lansert. Versjon 1809 har ingen slike ulemper. Du kan lese mer her.

Hvorfor flertrinn?

Utviklingsteamingeniører har ingen eller svært begrenset tilgang til å bygge verter; det er ingen måte å raskt administrere settet med komponenter for å bygge en applikasjon på disse vertene, for eksempel installere et ekstra verktøysett eller arbeidsbelastning for Visual Studio. Derfor tok vi beslutningen om å installere alle komponentene som er nødvendige for å bygge applikasjonen inn i build Docker-bildet. Om nødvendig kan du raskt endre bare dockerfilen og starte rørledningen for å lage dette bildet.

Fra teori til handling

I en ideell Docker flertrinns bildebygging, er miljøet for å bygge applikasjonen forberedt i det samme Dockerfile-skriptet som selve applikasjonen er bygget. Men i vårt tilfelle ble det lagt til en mellomkobling, nemlig trinnet med foreløpig å lage et docker-bilde med alt nødvendig for å bygge applikasjonen. Dette ble gjort fordi jeg ønsket å bruke docker-cache-funksjonen for å redusere installasjonstiden for alle avhengigheter.

La oss se på hovedpunktene i dockerfile-skriptet for å lage dette bildet.

For å lage bilder av forskjellige OS-versjoner, kan du definere et argument i dockerfilen som versjonsnummeret sendes gjennom under byggingen, og det er også taggen til basisbildet.

Du finner en fullstendig liste over Microsoft Windows Server-bildekoder her.

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

Som standard kommandoene i instruksjonene RUN inne i dockerfilen på Windows OS kjøres de i cmd.exe-konsollen. For å gjøre det enklere å skrive skript og utvide funksjonaliteten til kommandoene som brukes, vil vi omdefinere kommandoutførelseskonsollen i Powershell gjennom instruksjonen SHELL.

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

Det neste trinnet er å installere sjokoladepakkebehandleren og de nødvendige pakkene:

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 med sjokolade, kan du ganske enkelt sende dem som en liste, eller installere dem en om gangen hvis du trenger å sende unike parametere for hver pakke. I vår situasjon brukte vi en manifestfil i XML-format, som inneholder en liste over nødvendige pakker og deres parametere. Innholdet ser slik ut:

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="python" version="3.8.2"/>
  <package id="nuget.commandline" version="5.5.1"/>
  <package id="git" version="2.26.2"/>
</packages>

Deretter installerer vi applikasjonsbyggemiljøet, nemlig MS Build Tools 2019 - dette er en lett versjon av Visual Studio 2019, som inneholder det minste nødvendige settet med komponenter for kompilering av kode.
For å jobbe fullt ut med vårt C++-prosjekt, trenger vi tilleggskomponenter, nemlig:

  • Arbeidsmengde C++-verktøy
  • Verktøysett v141
  • Windows 10 SDK (10.0.17134.0)

Du kan installere et utvidet sett med verktøy automatisk ved å bruke en konfigurasjonsfil i JSON-format. Konfigurasjonsfilens innhold:

En fullstendig liste over tilgjengelige komponenter finner du på dokumentasjonssiden 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"
  ]
}

Dockerfilen kjører installasjonsskriptet, og legger for enkelhets skyld banen til byggeverktøyets kjørbare filer til miljøvariabelen PATH. Det er også tilrådelig å 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 stadiet er bildet vårt for kompilering av C++-applikasjonen klart, og vi kan fortsette direkte til å lage en docker-flertrinnsbygging av applikasjonen.

Flertrinn i aksjon

Vi vil bruke det opprettede bildet med alle verktøyene ombord som et byggebilde. Som i det forrige dockerfile-skriptet, vil vi legge til muligheten til å dynamisk spesifisere versjonsnummeret/bildekoden for enkel gjenbruk av kode. Det er viktig å legge til en etikett as builder til monteringsbildet i instruksjonene FROM.

ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builder

Nå er det på tide å bygge applikasjonen. Alt her er ganske enkelt: kopier kildekoden og alt knyttet til den, og start kompileringsprosessen.

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

Den siste fasen av å lage det endelige bildet er å spesifisere basisbildet til applikasjonen, hvor alle kompileringsartefakter og konfigurasjonsfiler vil være plassert. For å kopiere kompilerte filer fra det mellomliggende monteringsbildet, må du spesifisere parameteren --from=builder i instruksjonene 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 startkommandoen gjennom instruksjonene ENTRYPOINT eller CMD.

Konklusjon

I denne artikkelen snakket jeg om hvordan du lager et fullverdig kompileringsmiljø for C++-applikasjoner inne i en beholder under Windows og hvordan du bruker mulighetene til docker-flertrinnsbygg for å lage fullverdige bilder av applikasjonen vår.

Kilde: www.habr.com

Legg til en kommentar