這幾年整個 CPU 的市場從原本的 x86 開始翻轉到 Arm based 的 CPU,從 AWS Graviton2 和 Apple M1 都是 Arm CPU 的佼佼者,成本跟效能都有明顯的改善,就連作者都快被 Arm 給香爆,但是從 x86 到 Arm 的轉換期總是有一些事情要做,今天這篇要講的時下最夯的 Container 如何建立多種架構的 Container image 到 AWS ECR (Elastic Container Registry)
首先 AWS ECR 和 Docker 都有支援 manifest lists,使用 manifest lists 可以將 x86 或 Arm 等不同架構儲存在單個 ECR Container image,當啟動 Container image 時會自動選擇適合當前 CPU 架構的 image 使用。
Docker buildx mode
Docker 支援 buildx, manifest 建立 multi-arch,作者試過兩種都可以使用,用法也都大同小異可以自行選擇,在這篇採用 buildx 示範
先建立 AWS ECR Repository 待會上傳 Container image 的使用空間
$ aws ecr create-repository \
--repository-name multi-arch \
--image-scanning-configuration scanOnPush=true \
--image-tag-mutability MUTABLE \
--region us-east-1
拿到 repositoryArn 後先記錄下來
arn:aws:ecr:${region}:${accountId}:repository/multi-arch
Dockerfile 執行 uname -m
用於檢測 CPU 架構
# Dockerfile
FROM alpine:latest
CMD echo “Running on $(uname -m)”
buildx inspect 可以查看目前 Docker build mode
$ docker buildx inspect
Name: default
Driver: docker
Nodes:
Name: default
Endpoint: default
Status: running
Platforms: linux/amd64, linux/arm64, linux/riscv64 ...
但預設並不支援 multi-arch 的方式建構 container image,所以要透過 buildx 建立支援 multi-arch 的 builder instance
$ docker buildx create --name mybuilder
$ docker buildx use mybuilder
再次 buildx inspect 檢查可以看到 builder instance 換成 mybuilder,而 Driver 也從 docker 變成 docker-container
$ docker buildx inspect
Name: mybuilder
Driver: docker-container
Nodes:
Name: mybuilder0
Endpoint: unix:///var/run/docker.sock
Status: inactive
Platforms: linux/amd64, linux/arm64, linux/riscv64 ...
但是 Status 仍是 inactive
,使用 --bootstrap
讓 builder 初始化
$ docker buildx inspect --bootstrap
...
Status: running
確定狀態為 running
後就可以建構 multi-arch 的模式了
Docker Login with AWS ECR
預設 Docker 支援的 registry 是 DockerHub 如果要將 registry 改成 ECR 則要修改 docker login
$ aws ecr get-login-password --region us-east-1 \
| docker login --username AWS \
--password-stdin ${accountId}.dkr.ecr.region.amazonaws.com
Docker build multi-arch image
建構 multi-arch 一樣要使用 docker buildx 執行
$ docker buildx build \
--platform linux/amd64,linux/arm64 \
--push \
-t ${accountId}.dkr.ecr.us-east-1.amazonaws.com/multi-arch:latest \
.
--platform
用於指定要建構哪些平台架構,範例為 linux/amd64, linux/arm64,除此之外可以從docker buildx inspect
找到支援的 platform--push
指定後可以將 manifest lists 推送到 registry (ECR)
Verification
buildx build 成功之後在 AWS ECR 可以看到新的 image tag 被建立,但是卻無法看到支援哪些 architecture?
buildx 支援 imagetools 用來查看 container image 的詳細資訊,其中就包含 Manifests platform
$ docker buildx imagetools inspect ${accountId}.dkr.ecr.us-east-1.amazonaws.com/multi-arch:latest
...
Manifests:
Platform: linux/amd64
...
Platform: linux/arm64
預設情況下 docker run 會依照當前的 CPU chip 去選擇對應的 arch
$ docker run --rm ${accountId}.dkr.ecr.us-east-1.amazonaws.com/multi-arch:latest
"Running on x86_64"
當然也可以指定 –platform 選擇啟動的 image arch
$ docker run --rm --platform linux/aarch64 ${accountId}.dkr.ecr.us-east-1.amazonaws.com/multi-arch:latest
"Running on aarch64"
References
- Building Multi-Architecture Docker Images With Buildx
- How to build multi-arch Docker image with AWS Graviton
- docker buildx build
要注意 ECR 不能開啟 tag immutability
詳情可以參閱:https://github.com/moby/buildkit/issues/2004
感謝提醒,在這篇推文底下 Docker 有針對 buildkit 的問題做修復,我剛剛也測試更新到最新版 Docker 就沒問題了!
https://github.com/moby/buildkit/pull/2020