在生产环境中,我们可能需要将某个程序跑在不同的 CPU 架构上,比如通常服务器基本是x86,但华为鲲鹏或M1芯片的MAC等则是arm64。
值得庆幸的是,Docker 19.03
引入了一个新的实验性插件,本文阐述通过该插件如何构建跨平台 Docker 镜像。
一、搭建buildx环境
1、启用buildx插件
要想使用 buildx
,首先要确保 Docker 版本不低于 19.03
,同时还要通过设置环境变量 DOCKER_CLI_EXPERIMENTAL
来启用。可以通过下面的命令来为当前终端启用 buildx 插件:
1
| 🐳 → export DOCKER_CLI_EXPERIMENTAL=enabled
|
验证是否开启:
1 2
| 🐳 → docker buildx version github.com/docker/buildx v0.5.1-docker 11057da37336192bfc57d81e02359ba7ba848e4a
|
如果在某些系统上设置环境变量 DOCKER_CLI_EXPERIMENTAL
不生效(比如 Arch Linux),你可以选择从源代码编译:
1 2 3
| 🐳 → export DOCKER_BUILDKIT=1 🐳 → docker build --platform=local -o . git://github.com/docker/buildx 🐳 → mkdir -p ~/.docker/cli-plugins && mv buildx ~/.docker/cli-plugins/docker-buildx
|
2、启用 binfmt_misc
如果你使用的是 Docker 桌面版(MacOS 和 Windows),默认已经启用了 binfmt_misc
,可以跳过这一步。
如果你使用的是 Linux,需要手动启用 binfmt_misc
。大多数 Linux 发行版都很容易启用,不过还有一个更容易的办法,直接运行一个特权容器,容器里面写好了设置脚本:
1
| 🐳 → docker run --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
|
建议将 Linux 内核版本升级到 4.x 以上,特别是 CentOS 用户,你可能会遇到错误。
验证是 binfmt_misc 否开启:
1 2 3 4 5 6 7 8 9 10
| 🐳 → ls -al /proc/sys/fs/binfmt_misc/ 总用量 0 drwxr-xr-x. 2 root root 0 7月 1 23:51 . dr-xr-xr-x. 1 root root 0 6月 29 04:22 .. -rw-r--r--. 1 root root 0 7月 1 23:51 qemu-aarch64 -rw-r--r--. 1 root root 0 7月 1 23:51 qemu-arm -rw-r--r--. 1 root root 0 7月 1 23:51 qemu-ppc64le -rw-r--r--. 1 root root 0 7月 1 23:51 qemu-s390x --w-------. 1 root root 0 7月 1 23:51 register -rw-r--r--. 1 root root 0 7月 1 23:51 status
|
验证是否启用了相应的处理器:
1 2 3 4 5 6 7
| 🐳 → cat /proc/sys/fs/binfmt_misc/qemu-aarch64 enabled interpreter /usr/bin/qemu-aarch64 flags: OCF offset 0 magic 7f454c460201010000000000000000000200b7 mask ffffffffffffff00fffffffffffffffffeffff
|
3、切换到多平台构建器
Docker 默认会使用不支持多 CPU 架构的构建器,我们需要手动切换。
先创建一个新的构建器:
1
| 🐳 → docker buildx create --use --name mybuilder
|
启动构建器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 🐳 → docker buildx inspect mybuilder --bootstrap
[+] Building 5.0s (1/1) FINISHED => [internal] booting buildkit 5.0s => => pulling image moby/buildkit:buildx-stable-1 4.4s => => creating container buildx_buildkit_mybuilder0 0.6s Name: mybuilder Driver: docker-container
Nodes: Name: mybuilder0 Endpoint: unix:///var/run/docker.sock Status: running Platforms: linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6
|
查看当前使用的构建器及构建器支持的 CPU 架构,可以看到支持很多 CPU 架构:
1 2 3 4 5 6 7
| 🐳 → docker buildx ls
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMS mybuilder * docker-container mybuilder0 unix:///var/run/docker.sock running linux/amd64, linux/arm64, linux/ppc64le, linux/s390x, linux/386, linux/arm/v7, linux/arm/v6 default docker default default running linux/amd64, linux/386
|
二、构建多平台镜像
构建多平台镜像可使用指令如下
需要提前通过 docker login
命令登录认证 Docker Hub。
1
| 🐳 → docker buildx build -t <镜像名:版本> --platform=linux/amd64,linux/arm64,linux/ppc64le,linux/s390x,linux/386,linux/arm/v7,linux/arm/v6 . --push
|
其中--platform
可以指定镜像支持哪些平台,末尾--push
则表示构建后会直接推送到仓库上。
如果想将构建好的镜像保存在本地,可以将 type
指定为 docker
,但必须分别为不同的 CPU 架构构建不同的镜像,不能合并成一个镜像,即:
1 2 3
| 🐳 → docker buildx build -t <镜像名:版本> --platform=linux/arm -o type=docker . 🐳 → docker buildx build -t <镜像名:版本> --platform=linux/arm64 -o type=docker . 🐳 → docker buildx build -t <镜像名:版本> --platform=linux/amd64 -o type=docker .
|
因此建议构建推送,再通过docker pull
拉取镜像
三、测试多平台镜像
由于之前已经启用了 binfmt_misc
,现在我们就可以运行任何 CPU 架构的 Docker 镜像了,因此可以在本地系统上测试之前生成的 3 个镜像是否有问题。
1、首先列出每个镜像的 digests
,以yangchuansheng/hello-arch
为例,需将其替换成你所推送的镜像:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| 🐳 → docker buildx imagetools inspect yangchuansheng/hello-arch
Name: docker.io/yangchuansheng/hello-arch:latest MediaType: application/vnd.docker.distribution.manifest.list.v2+json Digest: sha256:ec55f5ece9a12db0c6c367acda8fd1214f50ee502902f97b72f7bff268ebc35a
Manifests: Name: docker.io/yangchuansheng/hello-arch:latest@sha256:38e083870044cfde7f23a2eec91e307ec645282e76fd0356a29b32122b11c639 MediaType: application/vnd.docker.distribution.manifest.v2+json Platform: linux/arm/v7
Name: docker.io/yangchuansheng/hello-arch:latest@sha256:de273a2a3ce92a5dc1e6f2d796bb85a81fe1a61f82c4caaf08efed9cf05af66d MediaType: application/vnd.docker.distribution.manifest.v2+json Platform: linux/arm64
Name: docker.io/yangchuansheng/hello-arch:latest@sha256:8b735708d7d30e9cd6eb993449b1047b7229e53fbcebe940217cb36194e9e3a2 MediaType: application/vnd.docker.distribution.manifest.v2+json Platform: linux/amd64
|
2、运行每一个镜像并观察输出结果:
1 2 3 4 5 6 7 8
| 🐳 → docker run --rm docker.io/yangchuansheng/hello-arch:latest@sha256:38e083870044cfde7f23a2eec91e307ec645282e76fd0356a29b32122b11c639 Hello, arm!
🐳 → docker run --rm docker.io/yangchuansheng/hello-arch:latest@sha256:de273a2a3ce92a5dc1e6f2d796bb85a81fe1a61f82c4caaf08efed9cf05af66d Hello, arm64!
🐳 → docker run --rm docker.io/yangchuansheng/hello-arch:latest@sha256:8b735708d7d30e9cd6eb993449b1047b7229e53fbcebe940217cb36194e9e3a2 Hello, amd64!
|