Выкарыстанне docker multi-stage для зборкі windows выяў

Ўсім прывітанне! Мяне клічуць Андрэй, і я працую DevOps інжынерам у кампаніі Exness у камандзе распрацоўкі. Мая асноўная дзейнасць звязана са зборкай, дэплоем і падтрымкай прыкладанняў у docker пад аперацыйнай сістэмай Linux (далей - АС). Не так даўно ў мяне з'явілася задача з тымі ж актыўнасцямі, але ў якасці мэтавай АС праекту стала Windows Server і набор праектаў на C++. Для мяне гэта было першае шчыльнае ўзаемадзеянне c docker кантэйнерамі пад АС Windows і ў цэлым з праграмамі на C++. Дзякуючы гэтаму я атрымаў цікавы досвед і пазнаў аб некаторых тонкасцях кантэйнерызацыі прыкладанняў у АС Windows.

Выкарыстанне docker multi-stage для зборкі windows выяў

У гэтым артыкуле хачу расказаць, з якімі цяжкасцямі мне давялося сутыкнуцца, якім чынам іх удалося вырашыць. Спадзяюся, гэта будзе карысным для вырашэння вашых бягучых і будучых задач. Прыемнага чытання!

Чаму кантэйнеры?

У кампаніі ёсць існуючая інфраструктура аркестратара кантэйнераў Hashicorp Nomad і звязаных кампанентаў – Consul і Vault. Таму кантэйнерызацыя прыкладанняў была абрана як уніфікаваны метад дастаўкі гатовага рашэння. Бо ў інфраструктуры праекту маюцца docker-хасты з версіямі АС Windows Server Core 1803 і 1809, тое неабходна збіраць асобна версіі docker-вобразаў для 1803 і 1809. У версіі 1803 важна памятаць пра тое, што нумар рэвізіі зборачнага docker-хаста павінен супадаць з нумарам рэвізіі базавай docker-выявы і хаста, дзе кантэйнер з гэтай выявы будзе запушчаны. Версія 1809 г. пазбаўлена такога недахопу. Падрабязней можна прачытаць тут.

Чаму multi-stage?

У інжынераў каманд распрацоўкі доступ да зборачных хастаў адсутнічае ці моцна абмежаваны, няма магчымасці аператыўна кіраваць наборам кампанентаў для зборкі прыкладання на гэтых хастах, напрыклад, усталяваць дадатковы toolset ці workload для Visual Studio. Таму мы прынялі рашэнне - усе неабходныя для зборкі прыкладання кампаненты ўсталяваць у зборачны docker-выява. Пры неабходнасці можна дастаткова хутка змяніць толькі dockerfile і запусціць пайплайн стварэння гэтай выявы.

Ад тэорыі да справы

У ідэальнай docker multi-stage зборцы выявы падрыхтоўка асяроддзя для зборкі прыкладання адбываецца ў тым жа dockerfile скрыпце, што і зборка самога прыкладання. Але ў нашым выпадку было дададзена прамежкавае звяно, а менавіта, крок папярэдняга стварэння docker-выявы са ўсім неабходным для зборкі прыкладання. Так зроблена, таму што хацелася выкарыстоўваць магчымасць docker cache, каб скараціць час усталёўкі ўсіх залежнасцяў.

Давайце разбяром асноўныя моманты dockerfile скрыпту для фармавання гэтай выявы.

Для стварэння выяваў розных версій АС у dockerfile можна вызначыць аргумент, праз які пры зборцы перадаецца нумар версіі, і ён жа тэг базавай выявы.

Поўны спіс тэгаў выяў Microsoft Windows Server можна знайсці тут.

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

Па змаўчанні каманды ў інструкцыі RUN усярэдзіне dockerfile у АС Windows выконваюцца ў кансолі cmd.exe. Для выгоды напісання скрыптоў і пашырэнні функцыяналу выкарыстоўваных каманд перавызначым кансоль выканання каманд на Powershell праз інструкцыю SHELL.

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

Наступным крокам усталёўваны пакетны мэнэджар chocolatey і неабходныя пакеты:

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'

Каб усталяваць пакеты, выкарыстоўваючы chocolatey, можна проста перадаць іх спісам ці ж усталяваць па адным у тым выпадку, калі неабходна перадаць унікальныя параметры для кожнага пакета. У нашай сітуацыі мы выкарыстоўвалі маніфест файл у фармаце XML, у якім пазначаны спіс неабходных пакетаў і іх параметраў. Яго змесціва выглядае так:

<?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>

Далей мы ўсталёўваем асяроддзе зборкі прыкладання, а менавіта, MS Build Tools 2019 – гэта аблегчаная версія Visual Studio 2019, якая ўтрымоўвае ў сабе мінімальна неабходны набор кампанентаў для кампіляцыі кода.
Для паўнавартаснай працы з нашым C++ праектам нам запатрабуюцца дадатковыя кампаненты, а менавіта:

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

Усталяваць пашыраны набор прылад у аўтаматычным рэжыме можна пры дапамозе файла канфігурацыі ў фармаце JSON. Змесціва файла канфігурацыі:

Поўны спіс даступных кампанентаў можна знайсці на сайце дакументацыі 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"
  ]
}

У dockerfile выконваецца скрыпт усталёўкі, і для выгоды дадаецца шлях да выкананых файлаў build tools у зменную асяроддзі PATH. Таксама пажадана выдаліць непатрэбныя файлы і дырэкторыі, каб паменшыць памер выявы.

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)

На гэтым этапе наша выява для кампіляцыі C++ прыкладанні гатовы, і можна прыступаць непасрэдна да стварэння docker multi-stage зборцы прыкладання.

Multi-stage у дзеянні

У якасці зборачнай выявы будзем выкарыстоўваць створаную выяву са ўсім інструментаром на борце. Як і ў папярэднім dockerfile скрыпце, дадамо магчымасць дынамічна паказваць нумар версіі / тэга выявы для выгоды перавыкарыстання кода. Важна дадаць пазнаку as builder да зборачнай выявы ў інструкцыі FROM.

ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builder

Надышла чарга зборкі прыкладання. Тут усё дастаткова проста: скапіяваць зыходны код і ўсё, што з ім звязана, і запусціць працэс кампіляцыі.

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

Завяршальны этап стварэння канчатковай выявы - указанне базавай выявы прыкладання, дзе будуць размяшчацца ўсе артэфакты кампіляцыі і файлы канфігурацыі. Для капіявання скампіляваных файлаў з прамежкавай зборачнай выявы трэба паказаць параметр --from=builder у інструкцыі COPY.

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

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

Цяпер застаецца дадаць неабходныя залежнасці для працы нашага прыкладання і пазначыць каманду запуску праз інструкцыі ENTRYPOINT або CMD.

Заключэнне

У гэтым артыкуле я распавёў, як стварыць паўнавартаснае асяроддзе кампіляцыі C++ прыкладанняў усярэдзіне кантэйнера пад Windows і пра тое, як выкарыстоўваць магчымасці docker multi-stage зборак для стварэння паўнавартасных выяў нашага прыкладання.

Крыніца: habr.com

Дадаць каментар