使用 Docker Buildx Bake 精通多平台建置、測試等
本指南示範如何使用 Docker Buildx Bake 簡化和自動化建置映像檔、測試和產生建置成品的流程。透過在宣告式 docker-bake.hcl
檔案中定義建置配置,您可以省去手動腳本,並為複雜的建置、測試和成品產生啟用高效工作流程。
假設
本指南假設您熟悉
先決條件
- 您的機器上已安裝最新版本的 Docker。
- 您已安裝 Git 以用於複製儲存庫。
- 您正在使用 containerd 映像檔儲存庫。
簡介
本指南使用一個範例專案來示範 Docker Buildx Bake 如何簡化您的建置和測試工作流程。儲存庫包含 Dockerfile 和 docker-bake.hcl
檔案,為您提供可立即使用的設定來試用 Bake 命令。
首先複製範例儲存庫
git clone https://github.com/dvdksn/bakeme.git
cd bakeme
Bake 檔案 docker-bake.hcl
使用目標和群組以宣告式語法定義建置目標,讓您可以有效管理複雜的建置。
Bake 檔案的初始內容如下所示
target "default" {
target = "image"
tags = [
"bakeme:latest",
]
attest = [
"type=provenance,mode=max",
"type=sbom",
]
platforms = [
"linux/amd64",
"linux/arm64",
"linux/riscv64",
]
}
target
關鍵字定義 Bake 的建置目標。default
目標定義在命令列上未指定特定目標時要建置的目標。以下是 default
目標選項的簡要摘要
target
:Dockerfile 中的目標建置階段。tags
:要指派給映像檔的標籤。attest
:要附加到映像檔的證明。提示
證明提供中繼資料,例如建置來源,追蹤映像檔建置的來源,以及 SBOM(軟體物料清單),適用於安全審計和合規性。
platforms
:要建置的平台變體。
要執行此建置,只需在儲存庫的根目錄中執行以下命令
$ docker buildx bake
使用 Bake,您可以避免冗長且難以記住的命令列咒語,透過使用結構化配置檔案取代手動、容易出錯的腳本,簡化建置配置管理。
相較之下,如果沒有 Bake,此建置命令會如下所示
$ docker buildx build \
--target=image \
--tag=bakeme:latest \
--provenance=true \
--sbom=true \
--platform=linux/amd64,linux/arm64,linux/riscv64 \
.
測試和程式碼檢查
Bake 不僅適用於定義建置配置和執行建置。您也可以使用 Bake 來執行測試,有效地將 BuildKit 用作任務執行器。在容器中執行測試非常適合確保結果可重複。本節將說明如何新增兩種測試
- 使用
go test
進行單元測試。 - 使用
golangci-lint
檢查樣式違規。
以測試驅動開發 (TDD) 的方式,首先將新的 test
目標新增到 Bake 檔案
target "test" {
target = "test"
output = ["type=cacheonly"]
}
提示
使用
type=cacheonly
可確保有效地捨棄建置輸出;圖層會儲存到 BuildKit 的快取中,但 Buildx 不會嘗試將結果載入到 Docker 引擎的映像檔儲存庫中。對於測試執行,您不需要匯出建置輸出 — 只有測試執行才重要。
要執行此 Bake 目標,請執行 docker buildx bake test
。此時,您會收到錯誤訊息,指出 Dockerfile 中不存在 test
階段。
$ docker buildx bake test
[+] Building 1.2s (6/6) FINISHED
=> [internal] load local bake definitions
...
ERROR: failed to solve: target stage "test" could not be found
為了滿足此目標,請新增對應的 Dockerfile 目標。此處的 test
階段與建置階段基於相同的基礎階段。
FROM base AS test
RUN --mount=target=. \
--mount=type=cache,target=/go/pkg/mod \
go test .
提示
--mount=type=cache
指令會在建置之間快取 Go 模組,透過避免重新下載依賴項來提高建置效能。此共用快取可確保在建置、測試和其他階段中可以使用相同的依賴項集。
現在,使用 Bake 執行 test
目標將會評估此專案的單元測試。如果您要驗證它是否有效,可以對 main_test.go
進行任意變更以導致測試失敗。
接下來,要啟用程式碼檢查,請將另一個目標新增到 Bake 檔案,名為 lint
target "lint" {
target = "lint"
output = ["type=cacheonly"]
}
在 Dockerfile 中,新增建置階段。此階段將使用 Docker Hub 上的官方 golangci-lint
映像檔。
提示
由於此階段依賴於執行外部依賴項,因此通常最好將您要使用的版本定義為建置引數。這讓您可以透過將依賴項版本並置到 Dockerfile 的開頭,更輕鬆地管理未來的版本升級。
ARG GO_VERSION="1.23"
ARG GOLANGCI_LINT_VERSION="1.61"
#...
FROM golangci/golangci-lint:v${GOLANGCI_LINT_VERSION}-alpine AS lint
RUN --mount=target=.,rw \
golangci-lint run
最後,要啟用同時執行兩個測試,您可以在 Bake 檔案中使用 groups
建構。群組可以指定要透過單一調用執行的多個目標。
group "validate" {
targets = ["test", "lint"]
}
現在,執行兩個測試就像這樣簡單
$ docker buildx bake validate
建置變體
有時您需要建置多個版本的程式。以下範例使用 Bake 來建置程式的個別「發行」和「偵錯」變體,使用矩陣。使用矩陣可以讓您使用不同的配置執行平行建置,節省時間並確保一致性。
矩陣將單一建置擴展為多個建置,每個建置代表矩陣參數的唯一組合。這表示您可以協調 Bake 以平行建置程式的生產和開發建置,只需最少的配置變更。
本指南的範例專案設定為使用建置時選項來有條件地啟用偵錯記錄和追蹤功能。
- 如果您使用
go build -tags="debug"
編譯程式,則會啟用額外的記錄和追蹤功能(開發模式)。 - 如果您在沒有
debug
標籤的情況下建置,則程式會使用預設記錄器進行編譯(生產模式)。
透過新增定義要建置的變數組合的矩陣屬性來更新 Bake 檔案
target "default" {
+ matrix = {
+ mode = ["release", "debug"]
+ }
+ name = "image-${mode}"
target = "image"
matrix
屬性定義要建置的變體(「發行」和「偵錯」)。name
屬性定義矩陣如何擴展為多個不同的建置目標。在本例中,矩陣屬性將建置擴展為兩個工作流程:image-release
和 image-debug
,每個工作流程使用不同的配置參數。
接下來,定義一個名為 BUILD_TAGS
的建置引數,它採用矩陣變數的值。
target = "image"
+ args = {
+ BUILD_TAGS = mode
+ }
tags = [
您還需要變更映像檔標籤指派給這些建置的方式。目前,兩個矩陣路徑都會產生相同的映像檔標籤名稱,並互相覆蓋。更新 tags
屬性,使用條件運算子根據矩陣變數值設定標籤。
tags = [
- "bakeme:latest",
+ mode == "release" ? "bakeme:latest" : "bakeme:dev"
]
- 如果
mode
是release
,則標籤名稱為bakeme:latest
- 如果
mode
是debug
,則標籤名稱為bakeme:dev
最後,更新 Dockerfile 以便在編譯階段使用 BUILD_TAGS
參數。當 -tags="${BUILD_TAGS}"
選項的值為 -tags="debug"
時,編譯器會使用 debug.go
檔案中的 configureLogging
函式。
# build compiles the program
FROM base AS build
-ARG TARGETOS TARGETARCH
+ARG TARGETOS TARGETARCH BUILD_TAGS
ENV GOOS=$TARGETOS
ENV GOARCH=$TARGETARCH
RUN --mount=target=. \
--mount=type=cache,target=/go/pkg/mod \
- go build -o "/usr/bin/bakeme" .
+ go build -tags="${BUILD_TAGS}" -o "/usr/bin/bakeme" .
這樣就完成了。透過這些變更,您的 docker buildx bake
命令現在可以建置兩個多平台映像變體。您可以使用 docker buildx bake --print
命令檢視 Bake 產生的規範建置配置。執行此命令會顯示 Bake 將執行一個具有兩個目標的 default
群組,它們具有不同的建置參數和映像標籤。
{
"group": {
"default": {
"targets": ["image-release", "image-debug"]
}
},
"target": {
"image-debug": {
"attest": ["type=provenance,mode=max", "type=sbom"],
"context": ".",
"dockerfile": "Dockerfile",
"args": {
"BUILD_TAGS": "debug"
},
"tags": ["bakeme:dev"],
"target": "image",
"platforms": ["linux/amd64", "linux/arm64", "linux/riscv64"]
},
"image-release": {
"attest": ["type=provenance,mode=max", "type=sbom"],
"context": ".",
"dockerfile": "Dockerfile",
"args": {
"BUILD_TAGS": "release"
},
"tags": ["bakeme:latest"],
"target": "image",
"platforms": ["linux/amd64", "linux/arm64", "linux/riscv64"]
}
}
}
將所有平台變體都考慮進去,這表示建置配置會產生 6 個不同的映像。
$ docker buildx bake
$ docker image ls --tree
IMAGE ID DISK USAGE CONTENT SIZE USED
bakeme:dev f7cb5c08beac 49.3MB 28.9MB
├─ linux/riscv64 0eae8ba0367a 9.18MB 9.18MB
├─ linux/arm64 56561051c49a 30MB 9.89MB
└─ linux/amd64 e8ca65079c1f 9.8MB 9.8MB
bakeme:latest 20065d2c4d22 44.4MB 25.9MB
├─ linux/riscv64 7cc82872695f 8.21MB 8.21MB
├─ linux/arm64 e42220c2b7a3 27.1MB 8.93MB
└─ linux/amd64 af5b2dd64fde 8.78MB 8.78MB
匯出建置成品
匯出二進位檔等建置成品對於部署到沒有 Docker 或 Kubernetes 的環境非常有用。例如,如果您的程式要在使用者的本機電腦上執行。
提示
本節討論的技巧不僅可以應用於二進位檔等建置輸出,還可以應用於任何類型的成品,例如測試報告。
使用 Go 和 Rust 等編譯後的二進位檔通常可移植的程式語言,建立僅用於匯出二進位檔的替代建置目標非常簡單。您只需要在 Dockerfile 中新增一個空階段,其中僅包含您要匯出的二進位檔。
首先,讓我們新增一種快速方法來為您的本地平台建置二進位檔,並將其匯出到本地檔案系統上的 ./build/local
。
在 docker-bake.hcl
檔案中,建立一個新的 bin
目標。在此階段,將 output
屬性設定為本地檔案系統路徑。Buildx 會自動偵測輸出看起來像檔案路徑,並使用 本地匯出器 將結果匯出到指定的路徑。
target "bin" {
target = "bin"
output = ["build/bin"]
platforms = ["local"]
}
請注意,此階段指定了一個 local
平台。預設情況下,如果未指定 platforms
,則建置會以 BuildKit 主機的作業系統和架構為目標。如果您使用的是 Docker Desktop,這通常表示建置目標是 linux/amd64
或 linux/arm64
,即使您的本機電腦是 macOS 或 Windows,因為 Docker 在 Linux 虛擬機器中執行。使用 local
平台會強制目標平台與您的本地環境相符。
接下來,將 bin
階段新增到 Dockerfile 中,它會從建置階段複製已編譯的二進位檔。
FROM scratch AS bin
COPY --from=build "/usr/bin/bakeme" /
現在,您可以使用 docker buildx bake bin
匯出您的本地平台版本的二進位檔。例如,在 macOS 上,此建置目標會在 Mach-O 格式