使用 buildx 构建多平台 Docker 镜像
在工作和生活中,我们可能经常需要将某个程序跑在不同的 CPU 架构上,比如让某些不可描述的软件运行在树莓派或嵌入式路由器设备上。特别是 Docker 席卷全球之后,我们可以轻松地在 ARM 设备上通过容器部署各种好玩的应用,而不用在意各种系统的差异性。
但是想要跨平台构建 Docker 镜像可不是一件轻松的活,要么到不同 CPU 架构的系统上全部构建一遍,要么就得在当前系统上通过虚拟化技术模拟不同的 CPU 架构,最后可能还要想办法合并镜像,费力不讨好。
不过值得庆幸的是,Docker 19.03
引入了一个新的实验性插件,该插件使得跨平台构建 Docker 镜像比以往更加容易了。在介绍这个新特性之前,我们先来了解一下跨 CPU 架构构建程序的基础知识。
1 构建多平台 Docker 镜像
利用 Docker 19.03 引入的插件 buildx,可以很轻松地构建多平台 Docker 镜像。buildx 是 docker build ...
命令的下一代替代品,它利用 BuildKit 的全部功能扩展了 docker build
的功能。
下面就来演示一下如何在短短几分钟内使用 buildx
构建出不同平台的 Docker 镜像。步骤如下:
1.1 启用 buildx 插件
开启 Dockerd 的实验特性
要想使用 buildx
,首先要确保 Docker 版本不低于 19.03
,同时还要通过设置环境变量 DOCKER_CLI_EXPERIMENTAL
来启用。可以通过下面的命令来为当前终端启用 buildx 插件:
|
|
或者
编辑 /etc/docker/daemon.json
,新增如下条目
|
|
验证是否开启:
|
|
如果在某些系统上设置环境变量 DOCKER_CLI_EXPERIMENTAL
不生效(比如 Arch Linux),你可以选择从源代码编译:
|
|
docker buildx介绍https://docs.docker.com/buildx/working-with-buildx/
docker buildx --help
,docker buildx COMMAND --help
查看用法,或者参考https://docs.docker.com/engine/reference/commandline/buildx/
1.2 启用 binfmt_misc
如果你使用的是 Docker 桌面版(MacOS 和 Windows),默认已经启用了 binfmt_misc
,可以跳过这一步。
如果你使用的是 Linux,需要手动启用 binfmt_misc
。大多数 Linux 发行版都很容易启用,不过还有一个更容易的办法,直接运行一个特权容器,容器里面写好了设置脚本:
|
|
建议将 Linux 内核版本升级到 4.x 以上,特别是 CentOS 用户,你可能会遇到错误。
在软件依赖中我们提到需要 Linux 内核版本>= 4.8.0
;如果在内核版本为3.10.0
的系统(比如 CentOS)上运行 docker/binfmt
,会出现报错 Cannot write to /proc/sys/fs/binfmt_misc/register: write /proc/sys/fs/binfmt_misc/register: invalid argument
,这是由于内核不支持(F)标志造成的。出现这种情况,建议您升级系统内核或者换使用较高版本内核的 Linux 发行版。
验证是 binfmt_misc 否开启:
|
|
验证是否启用了相应的处理器:
|
|
1.3 从默认的构建器切换到多平台构建器
Docker 默认会使用不支持多 CPU 架构的构建器,我们需要手动切换。
先创建一个新的构建器:
|
|
启动构建器:
|
|
查看当前使用的构建器及构建器支持的 CPU 架构,可以看到支持很多 CPU 架构:
|
|
1.4 构建多平台镜像
现在我们就可以构建支持多 CPU 架构的镜像了!假设有一个简单的 golang 程序源码:
|
|
创建一个 Dockerfile 将该应用容器化:
|
|
这是一个多阶段构建 Dockerfile,使用 Go 编译器来构建应用,并将构建好的二进制文件拷贝到 alpine 镜像中。
现在就可以使用 buildx 构建一个支持 arm、arm64 和 amd64 多架构的 Docker 镜像了,同时将其推送到 Docker Hub:
|
|
需要提前通过 docker login
命令登录认证 Docker Hub。
现在就可以通过 docker pull yaokun/hello
拉取刚刚创建的镜像了,Docker 将会根据你的 CPU 架构拉取匹配的镜像。
背后的原理也很简单,之前已经提到过了,buildx 会通过 QEMU
和 binfmt_misc
分别为 3 个不同的 CPU 架构(arm,arm64 和 amd64)构建 3 个不同的镜像。构建完成后,就会创建一个 manifest list,其中包含了指向这 3 个镜像的指针。
如果想将构建好的镜像保存在本地,可以将 type
指定为 docker
,但必须分别为不同的 CPU 架构构建不同的镜像,不能合并成一个镜像,即:
|
|
1.5 测试多平台镜像
由于之前已经启用了 binfmt_misc
,现在我们就可以运行任何 CPU 架构的 Docker 镜像了,因此可以在本地系统上测试之前生成的 3 个镜像是否有问题。
首先列出每个镜像的 digests
:
|
|
运行每一个镜像并观察输出结果:
|
|
参考链接: