昨天研究了 Image Manifest 的概念,提到了通常官方的 Docker Image 都有 Manifest、並提供多種架構的 image,
那既然官方的 image 可以,我們應該也可以為我們自己的 Image 建立 Manifest 吧!
因此今天延續昨天的內容,讓我們來繼續說說如何建置出支援多種架構的 image。
buildx 指令buildx 是 Docker 官方提供的一個指令,可以讓我們用來建置多種 Image,
同時在開始前,需要注意一點,
根據我的實驗,以下的指令跟步驟只能在裝有 Docker Desktop 的電腦上使用,
原因值得研究,
但直觀地猜測,是因為 Docker Desktop 的底層由 VM 架構,讓我們的開發電腦擁有建立模擬其他 CPU 架構 Image 的能力,
以下範例如果是在 Local 執行的指令就不會加上 sudo。
buildx ls在我的 Mac M1 電腦上執行後 buildx ls 後這些資訊,
以我目前的理解,這些是這台電腦上支援的架構,
# M1 Mac
$ docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
default * docker
default default running 20.10.17 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.17 linux/arm64, linux/amd64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
而在一台 AMD64 架構的電腦上,可以看到內容有一些差別:
# AMD64 架構的伺服器
$ sudo docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMS
mybuilder * docker-container
mybuilder0 unix:///var/run/docker.sock running v0.10.4 linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
default docker
default default running 20.10.18 linux/amd64, linux/386
buildx createbuildx create 指令是用來執行一個「builder」,用來模擬各種架構的特殊環境,
$ docker buildx create --name mybuilder --use --bootstrap
[+] Building 3.5s (1/1) FINISHED
=> [internal] booting buildkit 3.5s
=> => pulling image moby/buildkit:buildx-stable-1 3.0s
=> => creating container buildx_buildkit_mybuilder0 0.5s
mybuilder
其中 --use 參數是用來指定為預設的 builder,--bootstrap 則是預先建立好需要的架構資料,
有興趣的讀者可以自己把這兩個參數拿掉,觀察看看有哪裡不同,
此時 Docker 會執行起一個特殊的 image,可以透過 docker ps 跟 docker images 來查看:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5bd689a0fbe4 moby/buildkit:buildx-stable-1 "buildkitd" 23 seconds ago Up 22 seconds buildx_buildkit_mybuilder0
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
moby/buildkit buildx-stable-1 21bbfc679017 6 weeks ago 134MB
buildx build接著就到了我們最重要的建置 image,同時會上傳到 Container Registry,
我們一樣拿 D5 的程式碼範例來用,並推到 Gitlab:
$ docker buildx build --push \
--platform linux/amd64,linux/arm64 \
--tag registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:multi-arch .
[+] Building 29.0s (17/17) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 136B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [linux/amd64 internal] load metadata for docker.io/library/node:16-slim 4.0s
=> [linux/arm64 internal] load metadata for docker.io/library/node:16-slim 4.0s
=> [linux/amd64 2/5] WORKDIR /app 0.3s
=> [linux/amd64 3/5] COPY ./package*.json ./ 0.0s
=> [linux/amd64 4/5] RUN npm ci 7.7s
=> [linux/arm64 2/5] WORKDIR /app 0.0s
=> [linux/arm64 3/5] COPY ./package*.json ./ 0.0s
=> [linux/arm64 4/5] RUN npm ci 0.9s
=> [linux/arm64 5/5] COPY . . 0.0s
=> [linux/amd64 5/5] COPY . . 0.0s
=> exporting to image 11.1s
=> => exporting layers 0.2s
=> => pushing layers 9.1s
=> => pushing manifest for registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hel 1.8s
=> [auth] louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:pull,push token for r 0.0s
可以注意到我們用了 --platform 來指定要建置的 image 架構,
接著我們再用 Server 來查看 manifest:
# AMD64 架構的 server
$ sudo docker manifest inspect registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:multi-arch
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"manifests": [
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 2200,
"digest": "sha256:9becc34a5625c31a538ba232dc9d3c9d6efab9cafacacdd1536083a5a769ddb6",
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"size": 2200,
"digest": "sha256:e45d73007b3998bba9e286bf0e896b05c57c90a7f24b8830cf7ea28d86456d8a",
"platform": {
"architecture": "arm64",
"os": "linux"
}
}
]
}
可以看到成功建置多架構的 image,
最後當然還是要檢查一下,是否真的可以執行:
$ sudo docker run \
-d -p 3000:3000 \
registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:multi-arch
multi-arch: Pulling from louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server
...
Digest: sha256:bbf7ea87a2d0e488f97b0549c9d2215ad03f5f6fe8a572d25af577a98457ea2c
Status: Downloaded newer image for registry.gitlab.com/louis222220/2022-ithelp-docker-is-not-so-hard/hello-world-server:multi-arch
d2983e7a83d17fae5cf36d564d05a603e1871f5caf75d42d5bbaeb9f7f474468
$ curl localhost:3000
{"hello":"world"}
Tada~ ?
完成,
那我們今天的教學就到這邊。