Utilizarea docker în mai multe etape pentru a construi imagini Windows

Salutare tuturor! Numele meu este Andrey și lucrez ca inginer DevOps la Exness în echipa de dezvoltare. Activitatea mea principală este legată de construirea, implementarea și susținerea aplicațiilor în docker sub sistemul de operare Linux (denumit în continuare OS). Nu cu mult timp în urmă am avut o sarcină cu aceleași activități, dar sistemul de operare țintă al proiectului era Windows Server și un set de proiecte C++. Pentru mine, aceasta a fost prima interacțiune strânsă cu containerele docker sub sistemul de operare Windows și, în general, cu aplicațiile C++. Datorită acestui fapt, am avut o experiență interesantă și am învățat despre unele dintre complexitățile containerizării aplicațiilor în Windows.

Utilizarea docker în mai multe etape pentru a construi imagini Windows

În acest articol vreau să vă spun cu ce dificultăți am avut de întâmpinat și cum am reușit să le rezolv. Sper că acest lucru este de ajutor pentru provocările tale actuale și viitoare. Bucură-te de lectură!

De ce containere?

Compania are o infrastructură existentă pentru orchestratorul de containere Hashicorp Nomad și componentele aferente - Consul și Vault. Prin urmare, containerizarea aplicației a fost aleasă ca metodă unificată pentru livrarea unei soluții complete. Deoarece infrastructura proiectului conține gazde docker cu versiunile Windows Server Core OS 1803 și 1809, este necesar să se construiască versiuni separate ale imaginilor docker pentru 1803 și 1809. În versiunea 1803, este important să rețineți că numărul de revizuire al gazdei docker de compilare trebuie să se potrivească cu numărul de revizuire al imaginii docker de bază și cu gazda în care va fi lansat containerul din această imagine. Versiunea 1809 nu are un astfel de dezavantaj. Puteți citi mai multe aici.

De ce în mai multe etape?

Inginerii echipei de dezvoltare nu au acces sau au acces foarte limitat pentru a construi gazde; nu există nicio modalitate de a gestiona rapid setul de componente pentru construirea unei aplicații pe aceste gazde, de exemplu, instalarea unui set de instrumente suplimentar sau a unei sarcini de lucru pentru Visual Studio. Prin urmare, am luat decizia de a instala toate componentele necesare pentru a construi aplicația în imaginea de compilare Docker. Dacă este necesar, puteți schimba rapid doar fișierul docker și puteți lansa conducta pentru crearea acestei imagini.

De la teorie la acțiune

Într-o construcție ideală de imagine Docker în mai multe etape, mediul pentru construirea aplicației este pregătit în același script Dockerfile ca și aplicația în sine. Dar în cazul nostru a fost adăugată o legătură intermediară, și anume pasul de creare preliminară a unei imagini docker cu tot ce este necesar pentru construirea aplicației. Acest lucru s-a făcut deoarece am vrut să folosesc caracteristica docker cache pentru a reduce timpul de instalare a tuturor dependențelor.

Să ne uităm la punctele principale ale scriptului dockerfile pentru crearea acestei imagini.

Pentru a crea imagini ale diferitelor versiuni ale sistemului de operare, puteți defini un argument în fișierul docker prin care numărul versiunii este trecut în timpul construirii și este, de asemenea, eticheta imaginii de bază.

O listă completă a etichetelor de imagine Microsoft Windows Server poate fi găsită aici.

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

În mod implicit, comenzile din instrucțiuni RUN în interiorul fișierului docker pe sistemul de operare Windows, acestea sunt executate în consola cmd.exe. Pentru comoditatea scrierii de scripturi și a extinderii funcționalității comenzilor utilizate, vom redefini consola de execuție a comenzilor în Powershell prin instrucțiunea SHELL.

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

Următorul pas este să instalați managerul de pachete chocolatey și pachetele necesare:

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'

Pentru a instala pachete folosind chocolatey, puteți să le transmiteți pur și simplu ca o listă sau să le instalați pe rând dacă trebuie să treceți parametri unici pentru fiecare pachet. În situația noastră, am folosit un fișier manifest în format XML, care conține o listă de pachete necesare și parametrii acestora. Conținutul său arată astfel:

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

Apoi, instalăm mediul de construire a aplicației, și anume, MS Build Tools 2019 - aceasta este o versiune ușoară a Visual Studio 2019, care conține setul minim necesar de componente pentru compilarea codului.
Pentru a lucra pe deplin cu proiectul nostru C++, vom avea nevoie de componente suplimentare, și anume:

  • Instrumente C++ de sarcină de lucru
  • Set de instrumente v141
  • Windows 10 SDK (10.0.17134.0)

Puteți instala automat un set extins de instrumente folosind un fișier de configurare în format JSON. Conținutul fișierului de configurare:

O listă completă a componentelor disponibile poate fi găsită pe site-ul de documentație 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 rulează scriptul de instalare și, pentru comoditate, adaugă calea către fișierele executabile ale instrumentelor de construcție la variabila de mediu PATH. De asemenea, este recomandabil să eliminați fișierele și directoarele inutile pentru a reduce dimensiunea imaginii.

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)

În această etapă, imaginea noastră pentru compilarea aplicației C++ este gata și putem trece direct la crearea unei versiuni docker în mai multe etape a aplicației.

În acțiune în mai multe etape

Vom folosi imaginea creată cu toate instrumentele de la bord ca imagine de construcție. Ca și în scriptul anterior dockerfile, vom adăuga capacitatea de a specifica dinamic numărul versiunii/eticheta de imagine pentru ușurința reutilizarii codului. Este important să adăugați o etichetă as builder la imaginea de asamblare din instrucțiuni FROM.

ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builder

Acum este timpul să construim aplicația. Totul aici este destul de simplu: copiați codul sursă și tot ceea ce este asociat cu acesta și începeți procesul de compilare.

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

Etapa finală a creării imaginii finale este de a specifica imaginea de bază a aplicației, unde vor fi localizate toate artefactele de compilare și fișierele de configurare. Pentru a copia fișiere compilate din imaginea ansamblului intermediar, trebuie să specificați parametrul --from=builder in instructiuni COPY.

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

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

Acum nu mai rămâne decât să adăugați dependențele necesare pentru ca aplicația noastră să funcționeze și să specificați comanda de lansare prin instrucțiuni ENTRYPOINT sau CMD.

Concluzie

În acest articol, am vorbit despre cum să creați un mediu de compilare cu drepturi depline pentru aplicațiile C++ în interiorul unui container Windows și despre cum să folosiți capacitățile versiunilor docker în mai multe etape pentru a crea imagini cu drepturi depline ale aplicației noastre.

Sursa: www.habr.com

Adauga un comentariu