Usando docker multi-stage para construir imagens do Windows

Olá a todos! Meu nome é André e sou engenheiro DevOps na empresa Exness, na equipe de desenvolvimento. Minha principal atividade está relacionada à construção, implantação e suporte de aplicativos em docker sob o sistema operacional Linux (doravante — SO). Recentemente, tive a tarefa de realizar as mesmas atividades, mas com Windows Server como sistema operacional alvo do projeto e um conjunto de projetos em C++. Para mim, essa foi a primeira interação intensa com contêineres docker no SO Windows e, de modo geral, com aplicativos em C++. Graças a isso, adquiri uma experiência interessante e aprendi algumas sutilezas da contêinerização de aplicativos no SO Windows.

Usando docker multi-stage para construir imagens do Windows

Neste artigo, quero compartilhar as dificuldades que enfrentei e como consegui resolvê-las. Espero que isso seja útil para resolver suas tarefas atuais e futuras. Boa leitura!

Por que contêineres?

A empresa possui uma infraestrutura existente de orquestradores de contêineres Hashicorp Nomad e componentes relacionados — Consul e Vault. Portanto, a contêinerização de aplicativos foi escolhida como um método unificado para entrega de soluções prontas. Como na infraestrutura do projeto existem hosts docker com versões do SO Windows Server Core 1803 e 1809, é necessário construir separadamente as versões das imagens docker para 1803 e 1809. Na versão 1803, é importante lembrar que o número de revisão do host de construção docker deve corresponder ao número de revisão da imagem docker base e ao host onde o contêiner a partir dessa imagem será iniciado. A versão 1809 não possui essa desvantagem. Mais detalhes podem ser lidos aqui.

Por que multi-stage?

Os engenheiros das equipes de desenvolvimento não têm acesso aos hosts de construção ou têm acesso muito limitado, não há como gerenciar rapidamente o conjunto de componentes para a construção de aplicativos nesses hosts, por exemplo, instalar um conjunto de ferramentas adicional ou carga de trabalho para o Visual Studio. Portanto, decidimos — instalar todos os componentes necessários para a construção do aplicativo na imagem docker de construção. Se necessário, é possível alterar rapidamente apenas o dockerfile e iniciar o pipeline de criação dessa imagem.

Da teoria à prática

Em uma ideal montagem multi-stage do Docker, a preparação do ambiente para construir a aplicação acontece no mesmo script do dockerfile que a própria construção da aplicação. Mas no nosso caso, foi adicionado um elo intermediário, nomeadamente, uma etapa de pré-criação da imagem Docker com tudo o que é necessário para a construção da aplicação. Isso foi feito porque queríamos aproveitar a possibilidade de cache do Docker, para reduzir o tempo de instalação de todas as dependências.

Vamos analisar os principais pontos do script do dockerfile para a formação desta imagem.

Para criar imagens de diferentes versões do SO no dockerfile, pode-se definir um argumento, através do qual é passado o número da versão durante a construção, que também é a tag da imagem base.

A lista completa de tags das imagens do Microsoft Windows Server pode ser encontrada aqui.

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

Por padrão, os comandos na instrução RUN dentro do dockerfile no Windows são executados no console cmd.exe. Para facilitar a escrita de scripts e expandir a funcionalidade dos comandos usados, vamos redefinir o console de execução de comandos para o Powershell através da instrução SHELL.

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

A próxima etapa é instalar o gerenciador de pacotes Chocolatey e os pacotes necessários:

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'

Para instalar pacotes usando o Chocolatey, você pode simplesmente passar uma lista deles ou instalá-los um a um caso precise passar parâmetros exclusivos para cada pacote. Na nossa situação, usamos um arquivo de manifesto em formato XML, que especifica a lista de pacotes necessários e seus parâmetros. O conteúdo é assim:

Em seguida, vamos instalar o ambiente de construção da aplicação, especificamente, o MS Build Tools 2019 - uma versão leve do Visual Studio 2019, que contém o conjunto mínimo necessário de componentes para compilar código.
Para trabalhar plenamente com nosso projeto C++, precisaremos de componentes adicionais, especificamente:

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

A instalação do conjunto ampliado de ferramentas em modo automático pode ser feita através de um arquivo de configuração no formato JSON. O conteúdo do arquivo de configuração:

A lista completa dos componentes disponíveis pode ser encontrada no site de documentação. 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"
  ]
}

O script de instalação é executado no dockerfile, e para facilitar, o caminho para os arquivos executáveis do build tools é adicionado à variável de ambiente. caminhos. Também é desejável remover arquivos e diretórios desnecessários para reduzir o tamanho da imagem.

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)

Nesta etapa, nossa imagem para compilar o aplicativo C++ está pronta, e podemos começar diretamente a criação do aplicativo usando o docker multi-stage.

Multi-stage em ação

Usaremos a imagem criada como imagem de construção que contém todas as ferramentas. Como no script anterior do dockerfile, adicionaremos a capacidade de especificar dinamicamente o número da versão/tag da imagem para facilitar a reutilização do código. É importante adicionar a etiqueta as builder à imagem de construção na instrução FROM.

ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builder

Chegou a hora de construir o aplicativo. Aqui tudo é bastante simples: copiar o código-fonte e tudo relacionado, e iniciar o processo de compilação.

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

A etapa final da criação da imagem final é especificar a imagem base do aplicativo, onde todos os artefatos de compilação e arquivos de configuração estarão localizados. Para copiar os arquivos compilados da imagem de construção intermediária, é necessário indicar o parâmetro --from=builder na documentação COPY.

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

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

Agora, resta adicionar as dependências necessárias para o funcionamento do nosso aplicativo e indicar o comando de execução através das instruções. ENTRYPOINT ou CMD.

Conclusão

Neste artigo, explico como criar um ambiente completo para compilar aplicativos em C++ dentro de um contêiner no Windows e como utilizar os recursos das montagens em múltiplas etapas do Docker para criar imagens robustas do nosso aplicativo.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster