大家好! 我叫 Andrey,是 Exness 開發團隊的 DevOps 工程師。 我的主要工作是在 Linux 作業系統(以下簡稱 OS)下在 docker 中建置、部署和支援應用程式。 不久前,我有一個具有相同活動的任務,但該專案的目標作業系統是 Windows Server 和一組 C++ 專案。 對我來說,這是與 Windows 作業系統下的 docker 容器以及一般而言與 C++ 應用程式的第一次密切互動。 正因為如此,我獲得了一次有趣的經歷,並了解了 Windows 中容器化應用程式的一些複雜性。
在這篇文章中,我想告訴你我遇到過哪些困難以及我是如何解決這些困難的。 我希望這對您當前和未來的挑戰有所幫助。 享受閱讀!
為什麼是容器?
該公司擁有 Hashicorp Nomad 容器編排器和相關組件(Consul 和 Vault)的現有基礎設施。 因此,選擇應用程式容器化作為交付完整解決方案的統一方法。 由於專案基礎架構包含 Windows Server Core OS 版本 1803 和 1809 的 docker 主機,因此有必要為 1803 和 1809 建置單獨版本的 docker 映像。在版本 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
在 Windows 作業系統上的 dockerfile 內,它們在 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 格式的設定檔自動安裝一組擴充工具。 設定檔內容:
可用組件的完整清單可以在文件網站上找到
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運行安裝腳本,為了方便,將建置工具可執行檔案的路徑新增至環境變數中 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
.
結論
在本文中,我討論瞭如何在 Windows 容器內為 C++ 應用程式建立成熟的編譯環境,以及如何使用 docker 多階段建置的功能來建立應用程式的成熟映像。
來源: www.habr.com