使用docker多階段建置windows映像

大家好! 我叫 Andrey,是 Exness 開發團隊的 DevOps 工程師。 我的主要工作是在 Linux 作業系統(以下簡稱 OS)下在 docker 中建置、部署和支援應用程式。 不久前,我有一個具有相同活動的任務,但該專案的目標作業系統是 Windows Server 和一組 C++ 專案。 對我來說,這是與 Windows 作業系統下的 docker 容器以及一般而言與 C++ 應用程式的第一次密切互動。 正因為如此,我獲得了一次有趣的經歷,並了解了 Windows 中容器化應用程式的一些複雜性。

使用docker多階段建置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 ./

現在剩下的就是添加應用程式運行所需的依賴項,並透過說明指定啟動命令 ENTRYPOINTCMD.

結論

在本文中,我討論瞭如何在 Windows 容器內為 C++ 應用程式建立成熟的編譯環境,以及如何使用 docker 多階段建置的功能來建立應用程式的成熟映像。

來源: www.habr.com

添加評論