使用Docker buildx 為 .NET 構建多平臺映象

張善友發表於2023-10-15

.NET 團隊有一篇部落格 改進多平臺容器支援, 詳細介紹了.NET 7 以上的平臺可以輕鬆的使用Docker buildx 工具構建多平臺的映象。 buildx 是 Docker 官方提供的一個構建工具,它可以幫助使用者快速、高效地構建 Docker 映象,並支援多種平臺的構建。使用 buildx,使用者可以在單個命令中構建多種架構的映象,例如 x86 和 ARM 架構,而無需手動操作多個構建命令。此外,buildx 還支援 Dockerfile 的多階段構建和快取,這可以大大提高映象構建的效率和速度。

buildx 是一個管理 Docker 構建的 CLI 外掛,底層使用 BuildKit 擴充套件了 Docker 構建功能。要使用buildx 需要 Docker Engine 版本號大於等於 19.03,如果你使用的是 Docker Desktop,則預設安裝了 buildx。可以使用 docker buildx version 命令檢視安裝版本,得到以下類似輸出,證明已經安裝過了。

❯❯  docker buildx version
github.com/docker/buildx v0.11.2-desktop.1 986ab6afe790e25f022969a18bc0111cff170bc2


要使用 buildx 構建跨平臺映象,我們需要先建立一個 builder,可以翻譯為「構建器」。

❯❯ docker buildx create --use  

使用 docker buildx ls 命令可以檢視 builder 列表:

❯❯ docker buildx ls    
NAME/NODE         DRIVER/ENDPOINT                STATUS   BUILDKIT             PLATFORMS
agitated_tesla    docker-container
   agitated_tesla0 npipe:////./pipe/docker_engine inactive
elegant_mclean *  docker-container
   elegant_mclean0 npipe:////./pipe/docker_engine running  v0.12.2              linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default           docker
   default         default                        running  v0.11.6+0a15675913b7 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
desktop-linux     docker
   desktop-linux   desktop-linux                  running  v0.11.6+0a15675913b7 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6

其中 PLATFORMS 一列所展示的值 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6就是當前構建器所支援的所有平臺了。


現在一些準備工作已經就緒,我們終於可以使用 builder 構建多平臺映象了。 我們以 https://github.com/dotnet/dotnet-docker/blob/main/samples/aspnetapp/Dockerfile.alpine-composite 為例 :

# Learn about building .NET container images:
# https://github.com/dotnet/dotnet-docker/blob/main/samples/README.md
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build
ARG TARGETARCH
WORKDIR /source

# copy csproj and restore as distinct layers
COPY aspnetapp/*.csproj .
RUN dotnet restore -a $TARGETARCH

# copy and publish app and libraries
COPY aspnetapp/. .
RUN dotnet publish -a $TARGETARCH --no-restore -o /app


# Enable globalization and time zones:
# https://github.com/dotnet/dotnet-docker/blob/main/samples/enable-globalization.md
# final stage/image
FROM mcr.microsoft.com/dotnet/nightly/aspnet:8.0-alpine-composite
WORKDIR /app
COPY --from=build /app .
USER $APP_UID
ENTRYPOINT ["./aspnetapp"]

Docker file 裡面加上了 --platform=$BUILDPLATFORM  是關鍵:

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0-alpine AS build

Dockerfile 格式允許為語句指定開關,並使用內建函式提供值。在這種情況下,我們說應該始終使用(又名本地機器架構)。在 Arm64 計算機上,這將始終是 Arm64。


使用buildx 構建多平臺映象,

docker buildx build --pull -t aspnetapp -f Dockerfile.alpine-composite --platform linux/arm64,linux/arm,linux/amd64 .

docker buildx build 語法跟 docker build 一樣,--platform 引數列示構建映象的目標平臺,-t 表示映象的 Tag,. 表示上下文為當前目錄。

唯一不同的是對 --platform 引數的支援,docker build--platform 引數只支援傳遞一個平臺資訊,如 --platform linux/arm64,也就是一次只能構建單個平臺的映象。

而使用 docker buildx build 構建映象則支援同時傳遞多個平臺資訊,中間使用英文逗號分隔,這樣就實現了只用一條命令便可以構建跨平臺映象的功能。

在這裡,我們正在構建三種架構。在某些環境中,您還可以僅指定體系結構作為簡寫,避免重複“linux”。

使用該命令,你將看到以下警告。

WARNING: No output specified with docker-container driver. Build result will only remain in the build cache. To push result image into registry use --push or to load image into docker use --load

這條警告提示我們沒有為 docker-container 驅動程式指定輸出,生成結果將只會保留在構建快取中,使用 --push 可以將映象推送到 Docker Hub 遠端倉庫,使用 --load 可以將映象儲存在本地(僅在一次面向一個體繫結構時才有效)。

相關文章