Ús de docker multietapa per crear imatges de Windows

Hola a tots! Em dic Andrey i treballo com a enginyer de DevOps a Exness a l'equip de desenvolupament. La meva activitat principal està relacionada amb la creació, el desplegament i el suport d'aplicacions a Docker sota el sistema operatiu Linux (d'ara endavant anomenat SO). No fa gaire vaig tenir una tasca amb les mateixes activitats, però el sistema operatiu objectiu del projecte era Windows Server i un conjunt de projectes C++. Per a mi, aquesta va ser la primera interacció estreta amb els contenidors Docker sota el sistema operatiu Windows i, en general, amb les aplicacions C++. Gràcies a això, vaig tenir una experiència interessant i vaig conèixer algunes de les complexitats de la contenidorització d'aplicacions a Windows.

Ús de docker multietapa per crear imatges de Windows

En aquest article us vull explicar quines dificultats m'he hagut d'enfrontar i com he aconseguit resoldre-les. Espero que això sigui útil per als vostres reptes actuals i futurs. Gaudeix de la lectura!

Per què contenidors?

L'empresa disposa d'una infraestructura existent per a l'orquestrador de contenidors Hashicorp Nomad i components relacionats: Consul i Vault. Per tant, la contenidorització d'aplicacions es va triar com un mètode unificat per oferir una solució completa. Atès que la infraestructura del projecte conté amfitrions docker amb les versions del sistema operatiu Windows Server Core 1803 i 1809, és necessari crear versions separades d'imatges docker per a 1803 i 1809. A la versió 1803, és important recordar que el número de revisió de l'amfitrió docker de compilació ha de coincidir amb el número de revisió de la imatge acobladora base i l'amfitrió on es llançarà el contenidor d'aquesta imatge. La versió 1809 no té aquest inconvenient. Podeu llegir més aquí.

Per què multietapa?

Els enginyers de l'equip de desenvolupament no tenen accés o són molt limitats per crear amfitrions; no hi ha manera de gestionar ràpidament el conjunt de components per crear una aplicació en aquests amfitrions, per exemple, instal·lar un conjunt d'eines o càrrega de treball addicional per a Visual Studio. Per tant, vam prendre la decisió d'instal·lar tots els components necessaris per crear l'aplicació a la imatge de compilació de Docker. Si cal, podeu canviar ràpidament només el fitxer docker i iniciar la canalització per crear aquesta imatge.

De la teoria a l'acció

En una creació d'imatges en diverses etapes de Docker ideal, l'entorn per a la creació de l'aplicació es prepara amb el mateix script Dockerfile que es construeix l'aplicació. Però en el nostre cas, s'ha afegit un enllaç intermedi, és a dir, el pas de crear prèviament una imatge docker amb tot el necessari per construir l'aplicació. Això es va fer perquè volia utilitzar la funció de memòria cau de Docker per reduir el temps d'instal·lació de totes les dependències.

Vegem els punts principals de l'script dockerfile per crear aquesta imatge.

Per crear imatges de diferents versions del sistema operatiu, podeu definir un argument al fitxer docker a través del qual es passa el número de versió durant la compilació, i també és l'etiqueta de la imatge base.

Es pot trobar una llista completa d'etiquetes d'imatge de Microsoft Windows Server aquí.

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

Per defecte, les ordres de les instruccions RUN dins del fitxer docker del sistema operatiu Windows, s'executen a la consola cmd.exe. Per a la comoditat d'escriure scripts i ampliar la funcionalitat de les ordres utilitzades, redefinirem la consola d'execució d'ordres a Powershell mitjançant la instrucció SHELL.

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

El següent pas és instal·lar el gestor de paquets chocolatey i els paquets necessaris:

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'

Per instal·lar paquets amb chocolatey, simplement podeu passar-los com a llista o instal·lar-los un a un si necessiteu passar paràmetres únics per a cada paquet. En la nostra situació, hem utilitzat un fitxer de manifest en format XML, que conté una llista de paquets necessaris i els seus paràmetres. El seu contingut té aquest aspecte:

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

A continuació, instal·lem l'entorn de creació d'aplicacions, és a dir, MS Build Tools 2019: aquesta és una versió lleugera de Visual Studio 2019, que conté el conjunt mínim de components necessaris per compilar codi.
Per treballar completament amb el nostre projecte C++, necessitarem components addicionals, a saber:

  • Càrrega de treball Eines C++
  • Conjunt d'eines v141
  • Windows 10 SDK (10.0.17134.0)

Podeu instal·lar un conjunt estès d'eines automàticament mitjançant un fitxer de configuració en format JSON. Contingut del fitxer de configuració:

Es pot trobar una llista completa dels components disponibles al lloc de documentació 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"
  ]
}

El dockerfile executa l'script d'instal·lació i, per comoditat, afegeix el camí als fitxers executables de les eines de compilació a la variable d'entorn PATH. També és recomanable eliminar fitxers i directoris innecessaris per reduir la mida de la imatge.

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)

En aquesta fase, la nostra imatge per compilar l'aplicació C++ està preparada i podem procedir directament a la creació d'una compilació multietapa de Docker de l'aplicació.

Multietapa en acció

Utilitzarem la imatge creada amb totes les eines a bord com a imatge de construcció. Com a l'script dockerfile anterior, afegirem la possibilitat d'especificar dinàmicament el número de versió/etiqueta d'imatge per facilitar la reutilització del codi. És important afegir una etiqueta as builder a la imatge de muntatge a les instruccions FROM.

ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builder

Ara és el moment de crear l'aplicació. Aquí tot és bastant senzill: copieu el codi font i tot el que hi estigui associat i inicieu el procés de compilació.

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

L'etapa final de la creació de la imatge final és especificar la imatge base de l'aplicació, on es trobaran tots els artefactes de compilació i fitxers de configuració. Per copiar fitxers compilats de la imatge del conjunt intermedi, heu d'especificar el paràmetre --from=builder a les instruccions COPY.

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

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

Ara només queda afegir les dependències necessàries perquè la nostra aplicació funcioni i especificar l'ordre d'inici mitjançant les instruccions ENTRYPOINT o CMD.

Conclusió

En aquest article, vaig parlar sobre com crear un entorn de compilació complet per a aplicacions C++ dins d'un contenidor a Windows i com utilitzar les capacitats de les compilacions multietapa de Docker per crear imatges completes de la nostra aplicació.

Font: www.habr.com

Afegeix comentari