大家好!我叫Andrey,是Exness開發團隊的DevOps工程師。我的主要工作是建置、部署和維護運行在作業系統上的Docker應用程式。 Linux (以下簡稱作業系統)。不久前,我曾接到一個類似的任務,但專案的目標作業系統變成了 Windows Server и набор проектов на C++. Для меня это было первое плотное взаимодействие c docker контейнерами под ОС Windows и в целом с приложениями на C++. Благодаря этому я получил интересный опыт и узнал о некоторых тонкостях контейнеризации приложений в ОС Windows.

在這篇文章中,我想告訴你我遇到過哪些困難以及我是如何解決這些困難的。 我希望這對您當前和未來的挑戰有所幫助。 享受閱讀!
為什麼是容器?
В компании есть существующая инфраструктура оркестратора контейнеров Hashicorp Nomad и связанных компонентов — Consul и Vault. Поэтому контейнеризация приложений была выбрана как унифицированный метод доставки готового решения. Так как в инфраструктуре проекта имеются docker-хосты с версиями ОС Windows Server Core 1803 и 1809, то необходимо собирать отдельно версии docker-образов для 1803 и 1809. В версии 1803 важно помнить о том, что номер ревизии сборочного docker-хоста должен совпадать с номером ревизии базового docker-образа и хоста, где контейнер из этого образа будет запущен. Версия 1809 лишена такого недостатка. Подробнее можно прочитать .
為什麼要多階段?
開發團隊工程師沒有或非常有限地存取建置主機;無法快速管理用於在這些主機上建置應用程式的元件集,例如,為 Visual Studio 安裝附加工具集或工作負載。 因此,我們決定將建置應用程式所需的所有元件安裝到建置 Docker 映像中。 如有必要,您可以快速僅更改 dockerfile 並啟動用於建立此映像的管道。
從理論到行動
在理想的 Docker 多階段映像建置中,建置應用程式的環境是在建置應用程式本身的同一個 Dockerfile 腳本中準備的。 但在我們的例子中,加入了一個中間環節,即初步建立 docker 映像以及建置應用程式所需的一切的步驟。 這樣做是因為我想使用 docker 快取功能來減少所有依賴項的安裝時間。
讓我們來看看建立這個映像的 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++ 項目,我們需要額外的元件,即:
- 工作負載 C++ 工具
- 工具集 v141
- Windows 10 SDK(10.0.17134.0)
您可以使用 JSON 格式的設定檔自動安裝一組擴充工具。 設定檔內容:
可用組件的完整清單可以在文件網站上找到 .
{
"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運行安裝腳本,為了方便,將建置工具可執行檔案的路徑新增至環境變數中 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 多階段建置。
多階段行動
我們將使用創建的映像以及板上的所有工具作為構建映像。 與先前的 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 сборок для создания полноценных образов нашего приложения.
來源: www.habr.com
