构建多平台 Docker 镜像
构建多平台 Docker 镜像
利用 Docker 19.03 引入的插件 buildx,可以很轻松地构建多平台 Docker 镜像。buildx 是 docker build ...
命令的下一代替代品,它利用 BuildKit 的全部功能扩展了 docker build
的功能。
下面就来演示一下如何在短短几分钟内使用 buildx
构建出不同平台的 Docker 镜像。步骤如下:
启用 buildx 插件
要想使用
buildx
,首先要确保 Docker 版本不低于19.03
,同时还要通过设置环境变量DOCKER_CLI_EXPERIMENTAL
来启用。可以通过下面的命令来为当前终端启用 buildx 插件:🐳 → export DOCKER_CLI_EXPERIMENTAL=enabled
验证是否开启:
🐳 → sudo docker buildx version
github.com/docker/buildx v0.3.1-tp-docker 6db68d029599c6710a32aa7adcba8e5a344795a7
如果在某些系统上设置环境变量
DOCKER_CLI_EXPERIMENTAL
不生效(比如 Arch Linux),你可以选择从源代码编译:🐳 → 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或者使用如下方式:
在宿主机目录下,打开 /root/.docker/config.json 文件,没有的话自行创建
$ sudo vi /root/.docker/config.json
写入以下数据,并保存后,重启docker
1
2
3
4{
"experimental": "enabled",
"debug": true
}启用 binfmt_misc
如果你使用的是 Docker 桌面版(MacOS 和 Windows),默认已经启用了
binfmt_misc
,可以跳过这一步。如果你使用的是 Linux,需要手动启用
binfmt_misc
。大多数 Linux 发行版都很容易启用,不过还有一个更容易的办法,直接运行一个特权容器,容器里面写好了设置脚本:🐳 → docker run –rm –privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d
建议将 Linux 内核版本升级到 4.x 以上,特别是 CentOS 用户,你可能会遇到错误。
验证是 binfmt_misc 否开启:
🐳 → ls -al /proc/sys/fs/binfmt_misc/
1
2
3
4
5
6
7
8总用量 0
总用量 0
-rw-r--r-- 1 root root 0 11月 18 00:12 qemu-aarch64
-rw-r--r-- 1 root root 0 11月 18 00:12 qemu-arm
-rw-r--r-- 1 root root 0 11月 18 00:12 qemu-ppc64le
-rw-r--r-- 1 root root 0 11月 18 00:12 qemu-s390x
--w------- 1 root root 0 11月 18 00:09 register
-rw-r--r-- 1 root root 0 11月 18 00:12 status验证是否启用了相应的处理器:
🐳 → cat /proc/sys/fs/binfmt_misc/qemu-aarch64
1
2
3
4
5
6enabled
interpreter /usr/bin/qemu-aarch64
flags: OCF
offset 0
magic 7f454c460201010000000000000000000200b7
mask ffffffffffffff00fffffffffffffffffeffff从默认的构建器切换到多平台构建器
Docker 默认会使用不支持多 CPU 架构的构建器,我们需要手动切换。
先创建一个新的构建器:
🐳 → docker buildx create –use –name mybuilder
启动构建器:
🐳 → docker buildx inspect mybuilder –bootstrap
1
2
3
4
5
6
7
8
9
10
11
12[+] 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 架构:
🐳 → docker buildx ls
1
2
3
4
5NAME/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
构建多平台镜像
现在我们就可以构建支持多 CPU 架构的镜像了!
假设现在就可以使用 buildx 构建一个支持 arm、arm64 和 amd64 多架构的 Docker 镜像了,同时将其推送到 Docker Hub:
🐳 → docker buildx build -t yangchuansheng/hello-arch –platform=linux/arm,linux/arm64,linux/amd64 . –push
需要提前通过
docker login
命令登录认证 Docker Hub。现在就可以通过
docker pull mirailabs/hello-arch
拉取刚刚创建的镜像了,Docker 将会根据你的 CPU 架构拉取匹配的镜像。背后的原理也很简单,之前已经提到过了,buildx 会通过
QEMU
和binfmt_misc
分别为 3 个不同的 CPU 架构(arm,arm64 和 amd64)构建 3 个不同的镜像。构建完成后,就会创建一个 manifest list,其中包含了指向这 3 个镜像的指针。如果想将构建好的镜像保存在本地,可以将
type
指定为docker
,但必须分别为不同的 CPU 架构构建不同的镜像,不能合并成一个镜像,即:🐳 → docker buildx build -t yangchuansheng/hello-arch –platform=linux/arm -o type=docker .
🐳 → docker buildx build -t yangchuansheng/hello-arch –platform=linux/arm64 -o type=docker .
🐳 → docker buildx build -t yangchuansheng/hello-arch –platform=linux/amd64 -o type=docker .
测试多平台镜像
由于之前已经启用了
binfmt_misc
,现在我们就可以运行任何 CPU 架构的 Docker 镜像了,因此可以在本地系统上测试之前生成的 3 个镜像是否有问题。首先列出每个镜像的
digests
:🐳 → docker buildx imagetools inspect yangchuansheng/hello-arch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16Name: 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
运行每一个镜像并观察输出结果:
🐳 → docker run –rm xxx:arm
🐳 → docker run –rm xxx:amd64
🐳 → docker run –rm xxx:arm64
总结
回顾一下,本文带大家了解了在不同的 CPU 架构上运行软件的挑战性,以及
buildx
如何帮助我们解决了其中的一些挑战。使用buildx
,我们无需对 Dockerfile 进行任何修改,就可以创建支持多种 CPU 架构的 Docker 镜像,然后将其推送到 Docker Hub。任何安装了 Docker 的系统都可以拉取到与它的 CPU 架构相对应的镜像。未来 buildx 可能会成为
docker build
命令的一部分,最终所有上面提到的功能都会变成默认的功能,下沉到基础设施中交叉编译程序的做法将会变成远古时代的愚蠢行为。