Olá a todos! Meu nome é Andrey e trabalho como engenheiro DevOps na Exness, na equipe de desenvolvimento. Meu foco principal é criar, implantar e manter aplicações Docker que rodam no sistema operacional. Linux (doravante denominado SO). Há pouco tempo, tive uma tarefa com as mesmas atividades, mas o SO alvo do projeto passou a ser Windows Server e um conjunto de projetos em C++. Para mim, essa foi a primeira interação direta com contêineres Docker em um sistema operacional. Windows e aplicações C++ em geral. Isso me proporcionou uma experiência interessante e me ensinou algumas das complexidades da conteinerização de aplicações no sistema operacional. Windows.

Neste artigo quero contar quais dificuldades tive que enfrentar e como consegui resolvê-las. Espero que isso seja útil para seus desafios atuais e futuros. Gostar de ler!
Por que contêineres?
A empresa já possui uma infraestrutura do orquestrador de contêineres HashiCorp Nomad e componentes relacionados — Consul e Vault. Portanto, a conteinerização da aplicação foi escolhida como método unificado para entregar a solução final. Como a infraestrutura do projeto inclui hosts Docker com versões de SO, a conteinerização da aplicação foi escolhida como método unificado para a entrega da solução final. Windows Server Se você estiver usando o Core 1803 e 1809, precisará criar versões separadas da imagem Docker para cada uma delas. Na versão 1803, é importante lembrar que o número de revisão do host de compilação do Docker deve corresponder ao número de revisão da imagem Docker base e do host onde o contêiner dessa imagem será executado. A versão 1809 elimina esse problema. Você pode ler mais sobre isso aqui. .
Por que multiestágio?
Os engenheiros da equipe de desenvolvimento não têm acesso ou têm acesso muito limitado para criar hosts; não há como gerenciar rapidamente o conjunto de componentes para criar um aplicativo nesses hosts, por exemplo, instalar um conjunto de ferramentas ou carga de trabalho adicional para o Visual Studio. Portanto, tomamos a decisão de instalar todos os componentes necessários para construir o aplicativo na imagem Docker de construção. Se necessário, você pode alterar rapidamente apenas o dockerfile e iniciar o pipeline para criar esta imagem.
Da teoria à ação
Em uma construção de imagem de vários estágios do Docker ideal, o ambiente para construir o aplicativo é preparado no mesmo script Dockerfile em que o próprio aplicativo é construído. Mas no nosso caso foi adicionado um link intermediário, ou seja, a etapa de criação preliminar de uma imagem docker com tudo o que é necessário para construir a aplicação. Isso foi feito porque eu queria usar o recurso docker cache para reduzir o tempo de instalação de todas as dependências.
Vejamos os pontos principais do script dockerfile para criar esta imagem.
Para criar imagens de diferentes versões de SO, você pode definir um argumento no dockerfile através do qual o número da versão é passado durante a construção, e também é a tag da imagem base.
Lista completa de tags de imagem da Microsoft Windows Server pode encontrar .
ARG WINDOWS_OS_VERSION=1809
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSION
Por padrão, os comandos nas instruções RUN dentro do Dockerfile no sistema operacional Windows são executados no console cmd.exe. Para facilitar a escrita de scripts e expandir a funcionalidade dos comandos utilizados, redefiniremos o console de execução de comandos para o PowerShell usando as seguintes instruções: 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 chocolatey, você pode simplesmente passá-los como uma lista ou instalá-los um de cada vez se precisar passar parâmetros exclusivos para cada pacote. Em nossa situação, utilizamos um arquivo de manifesto em formato XML, que contém uma lista de pacotes necessários e seus parâmetros. Seu conteúdo é assim:
<?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 seguir, instalamos o ambiente de construção do aplicativo, ou seja, MS Build Tools 2019 - esta é uma versão leve do Visual Studio 2019, que contém o conjunto mínimo de componentes necessário para compilar o código.
Para funcionar totalmente com nosso projeto C++, precisaremos de componentes adicionais, a saber:
- Ferramentas de carga de trabalho C++
- Conjunto de ferramentas v141
- Windows 10 SDK (10.0.17134.0)
Você pode instalar um conjunto estendido de ferramentas automaticamente usando um arquivo de configuração no formato JSON. Conteúdo do arquivo de configuração:
Uma lista completa de componentes disponíveis pode ser encontrada no site de documentação .
{
"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 dockerfile executa o script de instalação e, por conveniência, adiciona o caminho para os arquivos executáveis das ferramentas de construção à variável de ambiente PATH. Também é aconselhá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)
Neste estágio, nossa imagem para compilar o aplicativo C++ está pronta e podemos prosseguir diretamente para a criação de uma compilação docker em vários estágios do aplicativo.
Multiestágio em ação
Usaremos a imagem criada com todas as ferramentas integradas como uma imagem de construção. Como no script dockerfile anterior, adicionaremos a capacidade de especificar dinamicamente o número da versão/tag de imagem para facilitar a reutilização do código. É importante adicionar um rótulo as builder para a imagem de montagem nas instruções FROM.
ARG WINDOWS_OS_VERSION=1809
FROM buildtools:$WINDOWS_OS_VERSION as builder
Agora é hora de construir o aplicativo. Tudo aqui é bastante simples: copie o código-fonte e tudo o que está associado a ele e inicie 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 da aplicação, onde estarão localizados todos os artefatos de compilação e arquivos de configuração. Para copiar arquivos compilados de uma imagem de montagem intermediária, você deve especificar o parâmetro --from=builder em instruções COPY.
FROM mcr.microsoft.com/windows/servercore:$WINDOWS_OS_VERSION
COPY --from=builder C:/x64/Release/myapp/ ./
COPY ./configs ./
Agora só falta adicionar as dependências necessárias para que nossa aplicação funcione e especificar o comando de lançamento através das instruções ENTRYPOINT ou CMD.
Conclusão
Neste artigo, expliquei como criar um ambiente de compilação completo para aplicações C++ dentro de um contêiner. Windows e como usar os recursos de construção em várias etapas do Docker para criar imagens completas de nossa aplicação.
Fonte: habr.com
