https://docs.docker.com/build/building/multi-platform
1. 使用 buildx 構(gòu)建跨平臺鏡像
構(gòu)建跨平臺鏡像是 Docker 生態(tài)系統(tǒng)中的一個重要話題, 因為跨平臺鏡像可以在多種平臺上運(yùn)行, 極具靈活性。為了實現(xiàn)這個目標(biāo), Docker 社區(qū)提供了多種方式來構(gòu)建跨平臺鏡像, 其中之一是使用 docker manifest, 我在《使用 docker manifest 構(gòu)建跨平臺鏡像》一文中詳細(xì)介紹了這種方法。然而, 目前最流行的方式是使用 Docker 的 buildx 工具, 這種方式不僅可以輕松構(gòu)建跨平臺鏡像, 還可以自動化整個構(gòu)建過程, 大大提高了效率。在本文中, 我們將重點介紹使用 buildx 構(gòu)建跨平臺鏡像的方法和技巧。
1.1. 簡介
buildx 是 Docker 官方提供的一個構(gòu)建工具, 它可以幫助用戶快速、高效地構(gòu)建 Docker 鏡像, 并支持多種平臺的構(gòu)建。使用 buildx, 用戶可以在單個命令中構(gòu)建多種架構(gòu)的鏡像, 例如 x86 和 ARM 架構(gòu), 而無需手動操作多個構(gòu)建命令。此外, buildx 還支持 Dockerfile 的多階段構(gòu)建和緩存, 這可以大大提高鏡像構(gòu)建的效率和速度。
1.2. 安裝
buildx 是一個管理 Docker 構(gòu)建的 CLI 插件, 底層使用 BuildKit 擴(kuò)展了 Docker 構(gòu)建功能。
筆記: BuildKit 是 Docker 官方提供的一個高性能構(gòu)建引擎, 可以用來替代 Docker 原有的構(gòu)建引擎。相比于原有引擎, BuildKit 具有更快的構(gòu)建速度、更高的并行性、更少的資源占用和更好的安全性。
要安裝并使用 buildx, 需要 Docker Engine 版本號大于等于 19.03。
如果你使用的是 Docker Desktop, 則默認(rèn)安裝了 buildx。可以使用 docker buildx version 命令查看安裝版本, 得到以下類似輸出, 證明已經(jīng)安裝過了。
$ docker buildx version
github.com/docker/buildx v0.9.1 ed00243a0ce2a0aee75311b06e32d33b44729689
如果需要手動安裝, 可以從 GitHub 發(fā)布頁面下載對應(yīng)平臺的最新二進(jìn)制文件, 重命名為 docker-buildx, 然后將其放到 Docker 插件目錄下(Linux/Mac 系統(tǒng)為 $HOME/.docker/cli-plugins, Windows 系統(tǒng)為 %USERPROFILE%.docker\cli-plugins)。
Linux/Mac 系統(tǒng)還需要給插件增加可執(zhí)行權(quán)限 chmod +x ~/.docker/cli-plugins/docker-buildx
, 之后就可以使用 buildx 了。
更詳細(xì)的安裝過程可以參考官方文檔。
1.3. 構(gòu)建跨平臺鏡像
首先, 需要澄清的是, 本文中所提到的「跨平臺鏡像」這一說法并不十分準(zhǔn)確。實際上, Docker 官方術(shù)語叫 Multi-platform images 即「多平臺鏡像」, 意思是支持多種不同 CPU 架構(gòu)的鏡像。之所以使用「跨平臺鏡像」這一術(shù)語, 是因為從使用者的角度來看, 在使用如 docker pull、docker run 等命令來拉取和啟動容器時, 并不會感知到這個鏡像是一個虛擬的 manifest list 鏡像還是針對當(dāng)前平臺的鏡像。
筆記: manifest list 是通過指定多個鏡像名稱創(chuàng)建的鏡像列表, 是一個虛擬鏡像, 它包含了多個不同平臺的鏡像信息??梢韵衿胀ㄧR像一樣使用 docker pull 和 docker run 等命令來操作它。如果你想了解關(guān)于 manifest list 的更多信息, 可參考《使用 docker manifest 構(gòu)建跨平臺鏡像》一文。
1.4. 跨平臺鏡像構(gòu)建策略
builder 支持三種不同策略構(gòu)建跨平臺鏡像:
1.4.1. 在內(nèi)核中使用 QEMU 仿真支持
如果你正在使用 Docker Desktop, 則已經(jīng)支持了 QEMU, QEMU 是最簡單的構(gòu)建跨平臺鏡像策略。它不需要對原有的 Dockerfile 進(jìn)行任何更改, BuildKit 會通過 binfmt_misc 這一 Linux 內(nèi)核功能實現(xiàn)跨平臺程序的執(zhí)行。
工作原理:
QEMU 是一個處理器模擬器, 可以模擬不同的 CPU 架構(gòu), 我們可以把它理解為是另一種形式的虛擬機(jī)。在 buildx 中, QEMU 用于在構(gòu)建過程中執(zhí)行非本地架構(gòu)的二進(jìn)制文件。例如, 在 x86 主機(jī)上構(gòu)建一個 ARM 鏡像時, QEMU 可以模擬 ARM 環(huán)境并運(yùn)行 ARM 二進(jìn)制文件。
binfmt_misc 是 Linux 內(nèi)核的一個模塊, 它允許用戶注冊可執(zhí)行文件格式和相應(yīng)的解釋器。當(dāng)內(nèi)核遇到未知格式的可執(zhí)行文件時, 會使用 binfmt_misc 查找與該文件格式關(guān)聯(lián)的解釋器(在這種情況下是 QEMU)并運(yùn)行文件。
QEMU 和 binfmt_misc 的結(jié)合使得通過 buildx 跨平臺構(gòu)建成為可能。這樣我們就可以在一個架構(gòu)的主機(jī)上構(gòu)建針對其他架構(gòu)的 Docker 鏡像, 而無需擁有實際的目標(biāo)硬件。
雖然 Docker Desktop 預(yù)配置了 binfmt_misc 對其他平臺的支持, 但對于其他版本 Docker, 你可能需要使用 tonistiigi/binfmt 鏡像啟動一個特權(quán)容器來進(jìn)行支持:
$ docker run --privileged --rm tonistiigi/binfmt --install all
1.4.2. 使用相同的構(gòu)建器實例在多個本機(jī)節(jié)點上構(gòu)建。
此方法直接在對應(yīng)平臺的硬件上構(gòu)建鏡像, 所以需要準(zhǔn)備各個平臺的主機(jī)。因為此方法門檻比較高, 所以并不常使用。
1.4.3. 使用 Dockerfile 中的多階段構(gòu)建, 交叉編譯到不同的平臺架構(gòu)中。
交叉編譯的復(fù)雜度不在于 Docker, 而是取決于程序本身。比如 Go 程序就很容易實現(xiàn)交叉編譯, 只需要在使用 go build 構(gòu)建程序時指定 GOOS、GOARCH 兩個環(huán)境變量即可實現(xiàn)。
1.5. 創(chuàng)建 builder
要使用 buildx 構(gòu)建跨平臺鏡像, 我們需要先創(chuàng)建一個 builder, 可以翻譯為「構(gòu)建器」。
使用 docker buildx ls 命令可以查看 builder 列表:
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
default * docker
default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
desktop-linux docker
desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
這兩個是默認(rèn) builder, default * 中的 * 表示當(dāng)前正在使用的 builder, 當(dāng)我們運(yùn)行 docker build 命令時就是在使用此 builder 構(gòu)建鏡像。
可以發(fā)現(xiàn), 這兩個默認(rèn)的 builder 第二列 DRIVER/ENDPOINT 項的值都是 docker, 表示它們都使用 docker 驅(qū)動程序。
buildx 支持以下幾種驅(qū)動程序:
驅(qū)動 | 說明 |
---|---|
docker | 使用捆綁到 Docker 守護(hù)進(jìn)程中的 BuildKit 庫, 就是安裝 Docker 后默認(rèn)的 BuildKit。 |
docker-container | 使用 Docker 新創(chuàng)建一個專用的 BuildKit 容器。 |
kubernetes | 在 Kubernetes 集群中創(chuàng)建一個 BuildKit Pod。 |
remote | 直接連接到手動管理的 BuildKit 守護(hù)進(jìn)程。 |
默認(rèn)的 docker 驅(qū)動程序優(yōu)先考慮簡單性和易用性, 所以它對緩存和輸出格式等高級功能的支持有限, 并且不可配置。其他驅(qū)動程序則提供了更大的靈活性, 并且更擅長處理高級場景。
具體差異你可以到官方文檔中查看。
因為使用 docker 驅(qū)動程序的默認(rèn) builder 不支持使用單條命令(默認(rèn) builder 的 --platform 參數(shù)只接受單個值)構(gòu)建跨平臺鏡像, 所以我們需要使用 docker-container 驅(qū)動創(chuàng)建一個新的 builder。
命令語法如下:
$ docker buildx create --name=<builder-name> --driver=<driver> --driver-opt=<driver-options>
參數(shù)含義如下:
- –name: 構(gòu)建器名稱, 必填。
- –driver: 構(gòu)建器驅(qū)動程序, 默認(rèn)為 docker-container。
- –driver-opt: 驅(qū)動程序選項, 如選項
--driver-opt=image=moby/buildkit:v0.11.3
可以安裝指定版本的 BuildKit, 默認(rèn)值是 moby/buildkit。
更多可選參數(shù)可以參考官方文檔。
我們可以使用如下命令創(chuàng)建一個新的 builder:
$ docker buildx create --name mybuilder
mybuilder
再次查看 builder 列表:
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
mybuilder * docker-container
mybuilder0 unix:///var/run/docker.sock inactive
default docker
default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
desktop-linux docker
desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
可以發(fā)現(xiàn)選中的構(gòu)建器已經(jīng)切換到了 mybuilder, 如果沒有選中, 你需要手動使用 docker buildx use mybuilder 命令切換構(gòu)建器。
1.6. 啟動 builder
我們新創(chuàng)建的 mybuilder 當(dāng)前狀態(tài)為 inactive, 需要啟動才能使用。
$ docker buildx inspect --bootstrap mybuilder
[+] Building 16.8s (1/1) FINISHED
=> [internal] booting buildkit 16.8s
=> => pulling image moby/buildkit:buildx-stable-1 16.1s
=> => creating container buildx_buildkit_mybuilder0 0.7s
Name: mybuilder
Driver: docker-container
Nodes:
Name: mybuilder0
Endpoint: unix:///var/run/docker.sock
Status: running
Buildkit: v0.9.3
Platforms: linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
inspect 子命令用來檢查構(gòu)建器狀態(tài), 使用 --bootstrap 參數(shù)則可以啟動 mybuilder 構(gòu)建器。
再次查看 builder 列表, mybuilder 狀態(tài)已經(jīng)變成了 running。
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
mybuilder * docker-container
mybuilder0 unix:///var/run/docker.sock running v0.9.3 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
default docker
default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
desktop-linux docker
desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
其中 PLATFORMS 一列所展示的值 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6 就是當(dāng)前構(gòu)建器所支持的所有平臺了。
現(xiàn)在使用 docker ps 命令可以看到 mybuilder 構(gòu)建器所對應(yīng)的 BuildKit 容器已經(jīng)啟動。
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b8887f253d41 moby/buildkit:buildx-stable-1 "buildkitd" 4 minutes ago Up 4 minutes buildx_buildkit_mybuilder0
這個容器就是輔助我們構(gòu)建跨平臺鏡像用的, 不要手動刪除它。
1.7. 使用 builder 構(gòu)建跨平臺鏡像
現(xiàn)在一些準(zhǔn)備工作已經(jīng)就緒, 我們終于可以使用 builder 構(gòu)建跨平臺鏡像了。
這里以一個 Go 程序為例, 來演示如何構(gòu)建跨平臺鏡像。
hello.go 程序如下:
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Printf("Hello, %s/%s!\n", runtime.GOOS, runtime.GOARCH)
}
這個程序非常簡單, 執(zhí)行后打印 Hello, 操作系統(tǒng)/CPU 架構(gòu)。
Go 程序還需要一個 go.mod 文件:
module hello
go 1.20
編寫 Dockerfile 內(nèi)容如下:
FROM golang:1.20-alpine AS builder
WORKDIR /app
ADD . .
RUN go build -o hello .
FROM alpine:latest
WORKDIR /app
COPY --from=builder /app/hello .
CMD ["./hello"]
這是一個普通的 Dockerfile 文件, 為了減小鏡像大小, 使用了多階段構(gòu)建。它跟構(gòu)建僅支持當(dāng)前平臺的鏡像所使用的 Dockerfile 沒什么兩樣。
$ ls
Dockerfile go.mod hello.go
以上三個文件需要放在同一個目錄下, 然后就可以在這個目錄下使用 docker buildx 來構(gòu)建跨平臺鏡像了。
$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go .
docker buildx build 語法跟 docker build 一樣, --platform 參數(shù)表示構(gòu)建鏡像的目標(biāo)平臺, -t 表示鏡像的 Tag, . 表示上下文為當(dāng)前目錄。
唯一不同的是對 --platform 參數(shù)的支持, docker build 的 --platform 參數(shù)只支持傳遞一個平臺信息, 如 --platform linux/arm64, 也就是一次只能構(gòu)建單個平臺的鏡像。
而使用 docker buildx build 構(gòu)建鏡像則支持同時傳遞多個平臺信息, 中間使用英文逗號分隔, 這樣就實現(xiàn)了只用一條命令便可以構(gòu)建跨平臺鏡像的功能。
執(zhí)行以上命令后, 我們將會得到一條警告:
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 驅(qū)動程序指定輸出, 生成結(jié)果將只會保留在構(gòu)建緩存中, 使用 --push 可以將鏡像推送到 Docker Hub 遠(yuǎn)程倉庫, 使用 --load 可以將鏡像保存在本地。
這是因為我們新創(chuàng)建的 mybuilder 是啟動了一個容器來運(yùn)行 BuildKit, 它并不能直接將構(gòu)建好的跨平臺鏡像輸出到本機(jī)或推送到遠(yuǎn)程, 必須要用戶來手動指定輸出位置。
我們可以嘗試指定 --load 將鏡像保存的本地主機(jī)。
$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --load
[+] Building 0.0s (0/0)
ERROR: docker exporter does not currently support exporting manifest lists
結(jié)果會得到一條錯誤日志??磥硭⒉恢С种苯訉⒖缙脚_鏡像輸出到本機(jī), 這其實是因為傳遞了多個 --platform 的關(guān)系, 如果 --platform 只傳遞了一個平臺, 則可以使用 --load 將構(gòu)建好的鏡像輸出到本機(jī)。
那么我們就只能通過 --push 參數(shù)將跨平臺鏡像推送到遠(yuǎn)程倉庫了。不過在此之前需要確保使用 docker login 完成登錄。
$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-go . --push
現(xiàn)在登錄 Docker Hub 就可以看見推送上來的跨平臺鏡像了。
我們也可以使用 imagetools 來檢查跨平臺鏡像的 manifest 信息。
$ docker buildx imagetools inspect jianghushinian/hello-go
Name: docker.io/jianghushinian/hello-go:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest: sha256:51199dadfc55b23d6ab5cfd2d67e38edd513a707273b1b8b554985ff562104db
Manifests:
Name: docker.io/jianghushinian/hello-go:latest@sha256:8032a6f23f3bd3050852e77b6e4a4d0a705dfd710fb63bc4c3dc9d5e01c8e9a6
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/arm64
Name: docker.io/jianghushinian/hello-go:latest@sha256:fd46fd7e93c7deef5ad8496c2cf08c266bac42ac77f1e444e83d4f79d58441ba
MediaType: application/vnd.docker.distribution.manifest.v2+json
Platform: linux/amd64
可以看到, 這個跨平臺鏡像包含了兩個目標(biāo)平臺的鏡像, 分別是 linux/arm64 和 linux/amd64。
我們分別在 Apple M2 芯片平臺和 Linux x86 平臺來啟動這個 Docker 鏡像看下輸出結(jié)果。
$ docker run --rm jianghushinian/hello-go
Hello, linux/arm64!
$ docker run --rm jianghushinian/hello-go
Hello, linux/amd64!
至此, 我們使用 builder 完成了跨平臺鏡像的構(gòu)建。
1.8. 使用交叉編譯
以上演示的構(gòu)建跨平臺鏡像過程就是利用 QEMU 的能力, 因為 Go 語言的交叉編譯非常簡單, 所以我們再來演示一下如何使用交叉編譯來構(gòu)建跨平臺鏡像。
我們只需要對 Dockerfile 文件進(jìn)行修改:
FROM --platform=$BUILDPLATFORM golang:1.20-alpine AS builder
ARG TARGETOS
ARG TARGETARCH
WORKDIR /app
ADD . .
RUN GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o hello .
FROM --platform=$TARGETPLATFORM alpine:latest
WORKDIR /app
COPY --from=builder /app/hello .
CMD ["./hello"]
其中 BUILDPLATFORM、TARGETOS、TARGETARCH、TARGETPLATFORM 四個變量是 BuildKit 提供的全局變量, 分別表示構(gòu)建鏡像所在平臺、操作系統(tǒng)、架構(gòu)、構(gòu)建鏡像的目標(biāo)平臺。
在構(gòu)建鏡像時, BuildKit 會將當(dāng)前所在平臺信息傳遞給 Dockerfile 中的 BUILDPLATFORM 參數(shù)(如 linux/arm64)。
通過 --platform
參數(shù)傳遞的 linux/arm64,linux/amd64 鏡像目標(biāo)平臺列表會依次傳遞給 TARGETPLATFORM 變量。
而 TARGETOS、TARGETARCH 兩個變量在使用時則需要先通過 ARG 進(jìn)行聲明, BuildKit 會自動為其賦值。
在 Go 程序進(jìn)行編譯時, 可以通過 GOOS 環(huán)境變量指定目標(biāo)操作系統(tǒng), 通過 GOARCH 環(huán)境變量指定目標(biāo)架構(gòu)。
所以這個 Dockerfile 所表示的含義是: 首先拉取當(dāng)前構(gòu)建鏡像所在平臺的 golang 鏡像, 然后使用交叉編譯構(gòu)建目標(biāo)平臺的 Go 程序, 最后將構(gòu)建好的 Go 程序復(fù)制到目標(biāo)平臺的 alpine 鏡像。
最終我們會通過交叉編譯得到一個跨平臺鏡像。
筆記: 通過
FROM --platform=$BUILDPLATFORM image
可以拉取指定平臺的鏡像, 由此我們可以知道, 其實 golang 和 alpine 鏡像都是支持跨平臺的。
構(gòu)建鏡像命令不變:
$ docker buildx build --platform linux/arm64,linux/amd64 -t jianghushinian/hello-cross-go . --push
啟動鏡像后輸出結(jié)果不變:
$ docker run --rm jianghushinian/hello-cross-go
Hello, linux/arm64!
$ docker run --rm jianghushinian/hello-cross-go
Hello, linux/amd64!
至此, 我們利用 Go 語言的交叉編譯完成了跨平臺鏡像的構(gòu)建。
1.9. 平臺相關(guān)的全局變量
關(guān)于上面提到的幾個全局變量, BuildKit 后端預(yù)定義了一組 ARG 全局變量(共 8 個)可供使用, 其定義和說明如下:
變量 | 說明 |
---|---|
TARGETPLATFORM | 構(gòu)建鏡像的目標(biāo)平臺, 如: linux/amd64, linux/arm/v7, windows/amd64。 |
TARGETOS | TARGETPLATFORM 的操作系統(tǒng), 如: linux、windows。 |
TARGETARCH | TARGETPLATFORM 的架構(gòu)類型, 如: amd64、arm。 |
TARGETVARIANT | TARGETPLATFORM 的變體, 如: v7。 |
BUILDPLATFORM | 執(zhí)行構(gòu)建所在的節(jié)點平臺。 |
BUILDOS | BUILDPLATFORM 的操作系統(tǒng)。 |
BUILDARCH | BUILDPLATFORM 的架構(gòu)類型。 |
BUILDVARIANT | BUILDPLATFORM 的變體。 |
使用示例如下:
# 這里可以直接使用 TARGETPLATFORM 變量
FROM --platform=$TARGETPLATFORM alpine
# 稍后的 RUN 命令想要使用變量必須提前用 ARG 進(jìn)行聲明
ARG TARGETPLATFORM
RUN echo "I'm building for $TARGETPLATFORM"
1.10. 刪除 builder
我們已經(jīng)實現(xiàn)了使用 builder 構(gòu)建跨平臺鏡像。如果現(xiàn)在你想要恢復(fù)環(huán)境, 刪除新建的 builder。則可以使用 docker buildx rm mybuilder 命令來完成。
$ docker buildx rm mybuilder
mybuilder removed
跟隨 mybuilder 啟動的 buildx_buildkit_mybuilder0 容器也會隨之被刪除。
現(xiàn)在再使用 docker buildx ls 命令查看構(gòu)建器列表, 已經(jīng)恢復(fù)成原來的樣子了。
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
default * docker
default default running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
desktop-linux docker
desktop-linux desktop-linux running 20.10.21 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
1.11. 功能清單
除了前文介紹的幾個 buildx 常用命令, 更多功能可以通過 --help 參數(shù)進(jìn)行查看。
$ docker buildx --help
Usage: docker buildx [OPTIONS] COMMAND
Extended build capabilities with BuildKit
Options:
--builder string Override the configured builder instance
Management Commands:
imagetools Commands to work on images in registry
Commands:
bake Build from a file
build Start a build
create Create a new builder instance
du Disk usage
inspect Inspect current builder instance
ls List builder instances
prune Remove build cache
rm Remove a builder instance
stop Stop builder instance
use Set the current builder instance
version Show buildx version information
Run 'docker buildx COMMAND --help' for more information on a command.
如 stop、rm 可以管理 builder 的生命周期。每條子命令又可以使用 docker buildx COMMAND --help 方式查看使用幫助, 感興趣的同學(xué)可以自行學(xué)習(xí)。
1.12. 總結(jié)
本文講解了如何使用 buildx 構(gòu)建跨平臺鏡像, 這也是在 Docker 生態(tài)中目前最優(yōu)的構(gòu)建方式。
首先介紹了 buildx 是什么, 以及如何安裝。接下來就進(jìn)入了構(gòu)建跨平臺鏡像的講解, 我們分析了三種跨平臺鏡像構(gòu)建策略, 并且分別對 QEMU 和 交叉編譯兩種策略進(jìn)行了演示。QEMU 策略無需對 Dockerfile 做任何更改, 而使用交叉編譯方式則需要根據(jù)程序的支持來編寫 Dockerfile 構(gòu)建跨平臺應(yīng)用。
最后我們還講解了如何管理 buildx 的生命周期, 以及羅列了 buildx 的功能清單幫助你進(jìn)一步深入學(xué)習(xí)。
2. 使用 docker manifest 構(gòu)建跨平臺鏡像
在當(dāng)今的軟件開發(fā)領(lǐng)域中, 構(gòu)建跨平臺應(yīng)用程序已經(jīng)成為了一個普遍存在的需求。不同的操作系統(tǒng)、硬件架構(gòu)需要不同的鏡像環(huán)境來支持它們。Docker 作為一個廣泛應(yīng)用的容器化技術(shù), 必然需要能夠支持構(gòu)建跨平臺鏡像, 本文將介紹如何使用 docker manifest 來實現(xiàn)構(gòu)建跨平臺鏡像。
2.1. 簡介
docker manifest 是 Docker 的一個命令, 它提供了一種方便的方式來管理不同操作系統(tǒng)和硬件架構(gòu)的 Docker 鏡像。通過 docker manifest, 用戶可以創(chuàng)建一個虛擬的 Docker 鏡像, 其中包含了多個實際的 Docker 鏡像, 每個實際的 Docker 鏡像對應(yīng)一個不同的操作系統(tǒng)和硬件架構(gòu)。
docker manifest 命令本身并不執(zhí)行任何操作。為了操作一個 manifest 或 manifest list, 必須使用其中一個子命令。
manifest 可以理解為是一個 JSON 文件, 單個 manifest 包含有關(guān)鏡像的信息, 例如層 (layers)、大小 (size) 和摘要 (digest) 等。
manifest list 是通過指定一個或多個(理想情況下是多個)鏡像名稱創(chuàng)建的鏡像列表(即上面所說的虛擬 Docker 鏡像)??梢韵衿胀ㄧR像一樣使用 docker pull 和 docker run 等命令來操作它。manifest list 通常被稱為「多架構(gòu)鏡像」。
注意: docker manifest 命令是實驗性的, 還未轉(zhuǎn)正。旨在用于測試和反饋, 因此其功能和用法可能會在不同版本之間發(fā)生變化。
2.2. 準(zhǔn)備工作
工欲善其事, 必先利其器, 如果想使用 docker manifest 構(gòu)建多架構(gòu)鏡像, 需要具備以下條件。
- 機(jī)器上安裝了 Docker。
- 需要注冊一個 Docker Hub 賬號。
- 最少有兩個不同平臺的主機(jī), 用來驗證 docker manifest 鎖構(gòu)建出來的多架構(gòu)鏡像正確性(可選)。
- 聯(lián)網(wǎng), docker manifest 命令是需要聯(lián)網(wǎng)使用的。
2.3. 為不同平臺構(gòu)建鏡像
本文中演示程序所使用的環(huán)境是 Apple M2 芯片平臺。本地的 Docker 版本如下:
$ docker version
Client:
Cloud integration: v1.0.29
Version: 20.10.21
API version: 1.41
Go version: go1.18.7
Git commit: baeda1f
Built: Tue Oct 25 18:01:18 2022
OS/Arch: darwin/arm64
Context: default
Experimental: true
Server: Docker Desktop 4.15.0 (93002)
Engine:
Version: 20.10.21
API version: 1.41 (minimum version 1.12)
Go version: go1.18.7
Git commit: 3056208
Built: Tue Oct 25 17:59:41 2022
OS/Arch: linux/arm64
Experimental: false
containerd:
Version: 1.6.10
GitCommit: 770bd0108c32f3fb5c73ae1264f7e503fe7b2661
runc:
Version: 1.1.4
GitCommit: v1.1.4-0-g5fd4c4d
docker-init:
Version: 0.19.0
GitCommit: de40ad0
2.4. 準(zhǔn)備 Dockerfile
首先準(zhǔn)備如下 Dockerfile 文件, 用來構(gòu)建鏡像。
FROM alpine
RUN uname -a > /os.txt
CMD cat /os.txt
這個鏡像非常簡單, 構(gòu)建時將 uname -a 命令輸出信息(即當(dāng)前操作系統(tǒng)的相關(guān)信息)寫入 /os.txt
, 運(yùn)行時將 /os.txt
內(nèi)容輸出。
2.5. 構(gòu)建 arm64 平臺鏡像
因為本機(jī)為 Apple M2 芯片, 所以使用 docker build 命令構(gòu)建鏡像默認(rèn)為 arm64 平臺鏡像。構(gòu)建命令如下:
$ docker build -t jianghushinian/echo-platform-arm64 .
[+] Building 15.6s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 94B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/alpine:latest 15.5s
=> [1/2] FROM docker.io/library/alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc01 0.0s
=> CACHED [2/2] RUN uname -a > /os.txt 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:f017783a39920aa4646f87d7e5a2d67ab51aab479147d60e5372f8749c3742bb 0.0s
=> => naming to docker.io/jianghushinian/echo-platform-arm64 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
注意: jianghushinian 是我的 Docker Hub 用戶名, 你在構(gòu)建鏡像時應(yīng)該使用自己的 Docker Hub 用戶名。
如果得到如上類似輸出, 表明構(gòu)建成功。
使用 docker run 運(yùn)行容器進(jìn)行測試:
$ docker run --rm jianghushinian/echo-platform-arm64
Linux buildkitsandbox 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 aarch64 Linux
輸出內(nèi)容中的 aarch64 就表示 ARMv8 架構(gòu)。
現(xiàn)在我們需要將鏡像推送到 Docker Hub, 確保在命令行中已經(jīng)使用 docker login 登錄過 Docker Hub 的情況下, 使用 docker push 命令推送鏡像:
$ docker push jianghushinian/echo-platform-arm64
Using default tag: latest
The push refers to repository [docker.io/jianghushinian/echo-platform-arm64]
dd0468cb6cb1: Pushed
07d3c46c9599: Mounted from jianghushinian/demo-arm64
latest: digest: sha256:8eb172234961bf54a01e83d510697f09646c43c297a24f839be846414dfaf583 size: 735
瀏覽器中登錄 Docker Hub 查看推送成功的鏡像:
2.6. 構(gòu)建 amd64 平臺鏡像
無需切換設(shè)備, 在 Apple M2 芯片的機(jī)器上我們可以直接構(gòu)建 amd64 也就是 Linux 平臺鏡像, docker build 命令提供了 --platform 參數(shù)可以構(gòu)建跨平臺鏡像。
$ docker build --platform=linux/amd64 -t jianghushinian/echo-platform-amd64 .
[+] Building 15.7s (6/6) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 36B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/alpine:latest 15.3s
=> CACHED [1/2] FROM docker.io/library/alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300 0.0s
=> [2/2] RUN uname -a > /os.txt 0.2s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:5c48af5176402727627cc18136d78f87f0793ccf61e3e3fb4df98391a69e9f70 0.0s
=> => naming to docker.io/jianghushinian/echo-platform-amd64 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
鏡像構(gòu)建成功后, 同樣使用 docker push 命令推送鏡像到 Docker Hub:
$ docker push jianghushinian/echo-platform-amd64
Using default tag: latest
The push refers to repository [docker.io/jianghushinian/echo-platform-amd64]
9499dee27c9f: Pushed
8d3ac3489996: Mounted from jianghushinian/demo-amd64
latest: digest: sha256:13cbf21fc8078fb54444992faae9aafca0706a842dfb0ab4f3447a6f14fb1359 size: 735
瀏覽器中登錄 Docker Hub 查看推送成功的鏡像:
你也許會好奇, 在 Apple M2 芯片的主機(jī)設(shè)備上運(yùn)行 amd64 平臺鏡像會怎樣。目前咱們構(gòu)建的這個簡單鏡像其實是能夠運(yùn)行的, 只不過會得到一條警告信息:
$ docker run --rm jianghushinian/echo-platform-amd64
WARNING: The requested image's platform (linux/amd64) does not match the detected host platform (linux/arm64/v8) and no specific platform was requested
Linux buildkitsandbox 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 x86_64 Linux
輸出內(nèi)容中的 x86_64 就表示 AMD64 架構(gòu)。
注意: 雖然這個簡單的鏡像能夠運(yùn)行成功, 但如果容器內(nèi)部程序不支持跨平臺, amd64 平臺鏡像無法在 arm64 平臺運(yùn)行成功。
同樣的, 如果我們登錄到一臺 amd64 架構(gòu)的設(shè)備上運(yùn)行 arm64 平臺鏡像, 也會得到一條警告信息:
# docker run --rm jianghushinian/echo-platform-arm64
WARNING: The requested image's platform (linux/arm64/v8) does not match the detected host platform (linux/amd64) and no specific platform was requested
Linux buildkitsandbox 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 aarch64 Linux
在 amd64 架構(gòu)的設(shè)備上運(yùn)行 amd64 平臺鏡像則不會遇到警告問題:
# docker run --rm jianghushinian/echo-platform-amd64
Linux buildkitsandbox 5.15.49-linuxkit #1 SMP PREEMPT Tue Sep 13 07:51:32 UTC 2022 x86_64 Linux
2.7. 使用 manifest 合并多平臺鏡像
我們可以使用 docker manifest 的子命令 create 創(chuàng)建一個 manifest list, 即將多個平臺的鏡像合并為一個鏡像。
create 命令用法很簡單, 后面跟的第一個參數(shù) jianghushinian/echo-platform 即為合并后的鏡像, 從第二個參數(shù)開始可以指定一個或多個不同平臺的鏡像。
$ docker manifest create jianghushinian/echo-platform jianghushinian/echo-platform-arm64 jianghushinian/echo-platform-amd64
Created manifest list docker.io/jianghushinian/echo-platform:latest
如上輸出, 表明多架構(gòu)鏡像構(gòu)建成功。
注意: 在使用 docker manifest create 命令時, 確保待合并鏡像都已經(jīng)被推送到 Docker Hub 鏡像倉庫, 不然報錯 no such manifest。這也是為什么前文在構(gòu)建鏡像時, 都會將鏡像推送到 Docker Hub。
此時在 Apple M2 芯片設(shè)備上使用 docker run 啟動構(gòu)建好的跨平臺鏡像 jianghushinian/echo-platform:
$ docker run --rm jianghushinian/echo-platform
Linux buildkitsandbox 5.4.0-80-generic #90-Ubuntu SMP Fri Jul 9 22:49:44 UTC 2021 aarch64 Linux
沒有任何問題, 就像在啟動 jianghushinian/echo-platform-arm64 鏡像一樣。
現(xiàn)在我們可以將這個跨平臺鏡像推送到 Docker Hub, 不過, 這回我們需要使用的命令不再是 docker push 而是 manifest 的子命令 docker manifest push:
$ docker manifest push jianghushinian/echo-platform
Pushed ref docker.io/jianghushinian/echo-platform@sha256:13cbf21fc8078fb54444992faae9aafca0706a842dfb0ab4f3447a6f14fb1359 with digest: sha256:13cbf21fc8078fb54444992faae9aafca0706a842dfb0ab4f3447a6f14fb1359
Pushed ref docker.io/jianghushinian/echo-platform@sha256:8eb172234961bf54a01e83d510697f09646c43c297a24f839be846414dfaf583 with digest: sha256:8eb172234961bf54a01e83d510697f09646c43c297a24f839be846414dfaf583
sha256:87b51c1835f13bb722bbb4279fcf50a6da0ecb852433a8f1c04e2f5fe93ac055
瀏覽器中登錄 Docker Hub 查看推送成功的鏡像:
進(jìn)入鏡像信息詳情頁面的 Tags 標(biāo)簽, 能夠看到鏡像支持 amd64、arm64/v8 這兩個平臺。
現(xiàn)在, 我們可以在 amd64 架構(gòu)的設(shè)備上同樣使用 docker run 命令啟動構(gòu)建好的跨平臺鏡像 jianghushinian/echo-platform:
# docker run --rm jianghushinian/echo-platform
Linux buildkitsandbox 5.4.0-80-generic #90-Ubuntu SMP Fri Jul 9 22:49:44 UTC 2021 x86_64 Linux
輸出結(jié)果沒有任何問題??梢园l(fā)現(xiàn), 無論是 arm64 設(shè)備還是 amd64 設(shè)備, 雖然同樣使用 docker run --rm jianghushinian/echo-platform 命令啟動鏡像, 但它們的輸出結(jié)果都表明啟動的是當(dāng)前平臺的鏡像, 沒有再次出現(xiàn)警告。
2.8. manifest 功能清單
docker manifest 不止有 create 一個子命令, 可以通過 --help/-h 參數(shù)查看使用幫助:
$ docker manifest --help
Usage: docker manifest COMMAND
The **docker manifest** command has subcommands for managing image manifests and
manifest lists. A manifest list allows you to use one name to refer to the same image
built for multiple architectures.
To see help for a subcommand, use:
docker manifest CMD --help
For full details on using docker manifest lists, see the registry v2 specification.
EXPERIMENTAL:
docker manifest is an experimental feature.
Experimental features provide early access to product functionality. These
features may change between releases without warning, or can be removed from a
future release. Learn more about experimental features in our documentation:
https://docs.docker.com/go/experimental/
Commands:
annotate Add additional information to a local image manifest
create Create a local manifest list for annotating and pushing to a registry
inspect Display an image manifest, or manifest list
push Push a manifest list to a repository
rm Delete one or more manifest lists from local storage
Run 'docker manifest COMMAND --help' for more information on a command.
可以發(fā)現(xiàn), docker manifest 共提供了 annotate、create、inspect、push、rm 這 5 個子命。
接下來我們分別看下這幾個子命令的功能。
2.9. create
先從最熟悉的 create 子命令看起, 來看下它都支持哪些功能。
$ docker manifest create -h
Flag shorthand -h has been deprecated, please use --help
Usage: docker manifest create MANIFEST_LIST MANIFEST [MANIFEST...]
Create a local manifest list for annotating and pushing to a registry
EXPERIMENTAL:
docker manifest create is an experimental feature.
Experimental features provide early access to product functionality. These
features may change between releases without warning, or can be removed from a
future release. Learn more about experimental features in our documentation:
https://docs.docker.com/go/experimental/
Options:
-a, --amend Amend an existing manifest list
--insecure Allow communication with an insecure registry
筆記: 可以看到輸出結(jié)果第一行的提示, 短標(biāo)志 -h 已經(jīng)被棄用, 推薦使用 --help 查看子命令幫助信息。
可以發(fā)現(xiàn), create 子命令支持兩個可選參數(shù) -a/–amend 用來修訂已存在的多架構(gòu)鏡像。
指定 --insecure 參數(shù)則允許使用不安全的(非 https) 鏡像倉庫。
2.10. push
push 子命令我們也見過了, 使用 push 可以將多架構(gòu)鏡像推送到鏡像倉庫。
來看下 push 還支持設(shè)置哪些可選參數(shù)。
$ docker manifest push -h
Flag shorthand -h has been deprecated, please use --help
Usage: docker manifest push [OPTIONS] MANIFEST_LIST
Push a manifest list to a repository
EXPERIMENTAL:
docker manifest push is an experimental feature.
Experimental features provide early access to product functionality. These
features may change between releases without warning, or can be removed from a
future release. Learn more about experimental features in our documentation:
https://docs.docker.com/go/experimental/
Options:
--insecure Allow push to an insecure registry
-p, --purge Remove the local manifest list after push
同樣的, push 也有一個 --insecure 參數(shù)允許使用不安全的(非 https) 鏡像倉庫。
-p/--purge
選項的作用是推送本地鏡像到遠(yuǎn)程倉庫后, 刪除本地 manifest list。
2.11. inspect
inspect 用來查看 manifest/manifest list 所包含的鏡像信息。
其使用幫助如下:
$ docker manifest inspect -h
Flag shorthand -h has been deprecated, please use --help
Usage: docker manifest inspect [OPTIONS] [MANIFEST_LIST] MANIFEST
Display an image manifest, or manifest list
EXPERIMENTAL:
docker manifest inspect is an experimental feature.
Experimental features provide early access to product functionality. These
features may change between releases without warning, or can be removed from a
future release. Learn more about experimental features in our documentation:
https://docs.docker.com/go/experimental/
Options:
--insecure Allow communication with an insecure registry
-v, --verbose Output additional info including layers and platform
--insecure
參數(shù)允許使用不安全的(非 https) 鏡像倉庫。這已經(jīng)是我們第三次看見這個參數(shù)了, 這也驗證了 docker manifest 命令需要聯(lián)網(wǎng)才能使用的說法, 因為這些子命令基本都涉及到和遠(yuǎn)程鏡像倉庫的交互。
指定 -v/--verbose
參數(shù)可以輸出更多信息, 包括鏡像的 layers 和 platform 信息。
使用示例如下:
$ docker manifest inspect jianghushinian/echo-platform
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 735,
"digest": "sha256:13cbf21fc8078fb54444992faae9aafca0706a842dfb0ab4f3447a6f14fb1359",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 735,
"digest": "sha256:8eb172234961bf54a01e83d510697f09646c43c297a24f839be846414dfaf583",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
}
}
]
}
從輸出信息中可以發(fā)現(xiàn), 我們構(gòu)建的多架構(gòu)鏡像 jianghushinian/echo-platform 包含兩個 manifest, 可以支持 amd64/arm64 架構(gòu), 并且都為 linux 系統(tǒng)下的鏡像。
指定 -v 參數(shù)輸出更詳細(xì)信息:
$ docker manifest inspect -v jianghushinian/echo-platform
[
{
"Ref": "docker.io/jianghushinian/echo-platform:latest@sha256:13cbf21fc8078fb54444992faae9aafca0706a842dfb0ab4f3447a6f14fb1359",
"Descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:13cbf21fc8078fb54444992faae9aafca0706a842dfb0ab4f3447a6f14fb1359",
"size": 735,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
"SchemaV2Manifest": {
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1012,
"digest": "sha256:5c48af5176402727627cc18136d78f87f0793ccf61e3e3fb4df98391a69e9f70"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 2818413,
"digest": "sha256:59bf1c3509f33515622619af21ed55bbe26d24913cedbca106468a5fb37a50c3"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 211,
"digest": "sha256:1e5897976ad1d3969268a18f4f0356a05875baf0225e39768a9066f43e950ebd"
}
]
}
},
{
"Ref": "docker.io/jianghushinian/echo-platform:latest@sha256:8eb172234961bf54a01e83d510697f09646c43c297a24f839be846414dfaf583",
"Descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:8eb172234961bf54a01e83d510697f09646c43c297a24f839be846414dfaf583",
"size": 735,
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
}
},
"SchemaV2Manifest": {
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1027,
"digest": "sha256:f017783a39920aa4646f87d7e5a2d67ab51aab479147d60e5372f8749c3742bb"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 2715434,
"digest": "sha256:9b3977197b4f2147bdd31e1271f811319dcd5c2fc595f14e81f5351ab6275b99"
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 212,
"digest": "sha256:edf2b8e1db64e4f46a2190a3dfcb74ae131ae13ad43fcfedde4c3f304c451f7d"
}
]
}
}
]
2.12. annotate
annotate 子命令可以給一個本地鏡像 manifest 添加附加的信息。這有點像 K8s Annotations 的意思。
其使用幫助如下:
$ docker manifest annotate -h
Flag shorthand -h has been deprecated, please use --help
Usage: docker manifest annotate [OPTIONS] MANIFEST_LIST MANIFEST
Add additional information to a local image manifest
EXPERIMENTAL:
docker manifest annotate is an experimental feature.
Experimental features provide early access to product functionality. These
features may change between releases without warning, or can be removed from a
future release. Learn more about experimental features in our documentation:
https://docs.docker.com/go/experimental/
Options:
--arch string Set architecture
--os string Set operating system
--os-features strings Set operating system feature
--os-version string Set operating system version
--variant string Set architecture variant
可選參數(shù)列表如下:
選項 | 描述 |
---|---|
–arch | 設(shè)置 CPU 架構(gòu)信息。 |
–os | 設(shè)置操作系統(tǒng)信息。 |
–os-features | 設(shè)置操作系統(tǒng)功能信息。 |
–os-version | 設(shè)置操作系統(tǒng)版本信息。 |
–variant | 設(shè)置 CPU 架構(gòu)的 variant 信息(翻譯過來是"變種"的意思), 如 ARM 架構(gòu)的 v7、v8 等。 |
例如設(shè)置操作系統(tǒng)版本信息, 可以使用如下命令:
$ docker manifest annotate --os-version macOS jianghushinian/echo-platform jianghushinian/echo-platform-arm64
現(xiàn)在使用 inspect
查看鏡像信息已經(jīng)發(fā)生變化:
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 735,
"digest": "sha256:13cbf21fc8078fb54444992faae9aafca0706a842dfb0ab4f3447a6f14fb1359",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 735,
"digest": "sha256:8eb172234961bf54a01e83d510697f09646c43c297a24f839be846414dfaf583",
"platform": {
"architecture": "arm64",
"os": "linux",
"os.version": "macOS",
"variant": "v8"
}
}
]
}
2.13. rm
最后要介紹的子命令是 rm, 使用 rm 可以刪除本地一個或多個多架構(gòu)鏡像 (manifest lists)。
$ docker manifest rm -h
Flag shorthand -h has been deprecated, please use --help
Usage: docker manifest rm MANIFEST_LIST [MANIFEST_LIST...]
Delete one or more manifest lists from local storage
EXPERIMENTAL:
docker manifest rm is an experimental feature.
Experimental features provide early access to product functionality. These
features may change between releases without warning, or can be removed from a
future release. Learn more about experimental features in our documentation:
https://docs.docker.com/go/experimental/
使用示例如下:
$ docker manifest rm jianghushinian/echo-platform
現(xiàn)在使用 inspect 查看鏡像信息已經(jīng)不在有 os.version 信息了, 因為本地鏡像 manifest lists 信息已經(jīng)被刪除, 重新從遠(yuǎn)程鏡像倉庫拉下來的多架構(gòu)鏡像信息并不包含 os.version。
$ docker manifest inspect jianghushinian/echo-platform
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 735,
"digest": "sha256:13cbf21fc8078fb54444992faae9aafca0706a842dfb0ab4f3447a6f14fb1359",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 735,
"digest": "sha256:8eb172234961bf54a01e83d510697f09646c43c297a24f839be846414dfaf583",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
}
}
]
}
2.14. 總結(jié)
本文主要介紹了如何使用 docker manifest 來實現(xiàn)構(gòu)建跨平臺鏡像。
首先對 docker manifest 進(jìn)行了簡單介紹, 它是 Docker 的一個子命令, 本身并不執(zhí)行任何操作, 為了操作一個 manifest 或 manifest list, 必須使用它包含的子命令。
接著我們又在 Apple M2 芯片設(shè)備上構(gòu)建了不同平臺的鏡像, 然后使用 manifest list 的能力將其合并成跨平臺鏡像。
最后對 docker manifest 支持的所有子命令都進(jìn)行了講解。文章來源:http://www.zghlxwxcb.cn/news/detail-768179.html
2.15. 參考
docker manifest 官方文檔: https://docs.docker.com/engine/reference/commandline/manifest/文章來源地址http://www.zghlxwxcb.cn/news/detail-768179.html
到了這里,關(guān)于使用 docker buildx 構(gòu)建跨平臺鏡像 (QEMU/buildx/build)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!