使用 Docker Buildx 构建跨平台镜像

x86 机器上开发、ARM 服务器上上线,为每个架构单独构建一遍镜像太笨重。docker buildx 借助 QEMU 用户态仿真,一条命令就能产出多架构镜像。本文从环境准备讲到推送验证,覆盖私有仓库场景下的全部配置点。

为什么需要跨平台构建

常见做法是每个平台各构建一次,但当开发平台与目标平台不一致时,往往还得额外准备目标架构的编译环境。默认的 docker build 无法跨平台,需要 buildx 插件配合:Linux 内核通过 QEMU 用户态模式注册二进制转换处理程序,运行时动态翻译目标架构的二进制指令,效果等同于在本地仿真运行目标架构的程序,容器里的编译体验与原生几乎一致。

Buildx 能力清单

  • 多平台构建:单条命令产出多个 CPU 架构的镜像。
  • 构建缓存:支持本地与远程缓存,复用前次构建结果。
  • 实验性功能:用 –platform 指定目标平台,用 –build-arg BUILDKIT_INLINE_CACHE=1 开启内联缓存。
  • 并发构建:同时在多个节点构建多个镜像。
  • 外部构建器:结合 QEMU,在一个架构上构建另一个架构的镜像。
  • 镜像导出:输出 tar 文件,供没有 Docker 的环境使用。

启用 buildx 与 binfmt_misc

macOS/Windows 的 Docker Desktop 与 Linux deb/rpm 安装的 Docker 已内置 buildx,先确认命令可用:

docker buildx version

没有内置时,从 Docker buildx 项目的 release 页面(https://github.com/docker/buildx/releases/latest)下载对应平台的二进制文件,命名为 docker-buildx,放入插件目录并加执行权限:

mv docker-buildx ~/.docker/cli-plugins/
chmod +x ~/.docker/cli-plugins/docker-buildx

Docker for Linux 默认不支持构建 arm 架构镜像,跑一次 binfmt 容器开启该能力(Docker 桌面版默认已启用 binfmt_misc,可跳过;注意 Linux 内核需 4.x 以上,CentOS 7 默认 3.10 不满足):

[root@DevOps ~]# docker run --rm --privileged tonistiigi/binfmt:latest --install all

# 验证是 binfmt_misc 否开启:
[root@DevOps ~]# ls -al /proc/sys/fs/binfmt_misc
docker-buildx_01

验证 qemu-arm 处理器已注册启用:

[root@DevOps ~]# cat /proc/sys/fs/binfmt_misc/qemu-arm
# 这表示 binfmt_misc 对象(在这里是 qemu-arm)是启用的
enabled
# 这是指定用于解释目标架构二进制文件的解释器。这里使用的是/usr/bin/qemu-arm
interpreter /usr/bin/qemu-arm
# 这是一组标志,它们指示了如何处理目标二进制文件。
flags: OCF
# 这个字段指示了在目标文件的哪个偏移量开始执行解释器。
offset 0
# 这个字段描述了目标文件的特征码,也就是一个标志序列,用于识别文件的格式。
magic 7f454c4601010100000000000000000002002800
# 这个字段定义了哪些部分是需要匹配的,哪些部分是通配符。
mask ffffffffffffff00fffffffffffffffffeffffff

创建多平台构建器

Docker 默认的构建器实例不支持同时指定多个 –platform,需要手动创建新实例。如果私有仓库是 http 且没有证书,创建时必须带 –driver-opt network=host 和 –config 两个参数,同时在 Docker 的 daemon.json 中加入 “insecure-registries” 配置。先准备 buildkitd.toml:

[root@DevOps ~]# vim /etc/buildkit/buildkitd.toml
debug = true
# insecure-entitlements allows insecure entitlements, disabled by default.
insecure-entitlements = [ "network.host", "security.insecure" ]

# optionally mirror configuration can be done by defining it as a registry.
[registry."私有仓库地址IP或者域名"]
  http = true
  insecure = true

创建名为 my-builder 的构建器并设为当前活动实例:

[root@DevOps ~]# docker buildx create --name my-builder --use --driver-opt network=host --config /etc/buildkit/buildkitd.toml

参数说明:–name 指定构建器名称;–use 创建后立即切换使用;–driver-opt network=host 让构建器进程使用宿主机网络命名空间,可访问宿主机网络资源;–config 指定构建器配置文件路径。

检查当前部署的构建器:

[root@DevOps ~]# docker buildx inspect
docker-buildx_02

启动新构建器实例:

[root@DevOps ~]# docker buildx inspect my-builder --bootstrap
docker-buildx_03

查看当前使用的构建器及其支持的 CPU 架构:

[root@DevOps ~]# docker buildx ls
docker-buildx_04

构建并推送多平台镜像

用一个最简单的应用验证:基础镜像通过 –platform=$TARGETPLATFORM 指定平台,把 uname 结果写入文件并在启动时输出:

[root@DevOps ~]# vim Dockerfile
# 通过 --platform=$TARGETPLATFORM指定平台的Alpine 镜像作为基础
FROM --platform=$TARGETPLATFORM alpine

# 运行 uname 命令并将输出写入 os.txt 文件
RUN uname -a > /os.txt

# 设置容器启动时默认执行的命令
CMD cat /os.txt

推送前先登录私有镜像仓库:

[root@DevOps ~]# docker login <私有镜像仓库>
Username: 用户
Password: 密码

Login Succeeded

执行构建,用 –push 直接推送到仓库:

[root@DevOps ~]#  docker buildx build --platform linux/arm64,linux/amd64 -t 私有仓库地址/public/REPOSITORY[:TAG] --push .
docker-buildx_05

到私有仓库的项目页面确认同一标签下存在多个架构的镜像:

docker-buildx_06

验证镜像与注意事项

用 imagetools 探查已推送到远程仓库的镜像:

[root@DevOps ~]# docker buildx imagetools inspect 私有仓库地址/public/REPOSITORY[:TAG]

构建跨平台镜像:使用 docker buildx

本机启用了 binfmt_misc 后,可以直接按 sha256 值拉取任意架构的镜像做本地测试:

[root@DevOps ~]# docker run -it --rm 私有仓库地址/public/demo:v1.0@sha256:xxx
docker-buildx_08
docker-buildx_09
  • 多平台镜像无法同时使用 –load 载入本地,只能 –push 推送或输出到目录,这是构建器层面的限制。
  • QEMU 模拟执行编译速度明显慢于原生,重编译类镜像建议挂真实架构的远程节点做 builder。
  • http 私有仓库需要 buildkitd.toml、driver-opt、daemon.json 三处配置同时到位,缺一处就会在推送阶段报证书或网络错误。
  • CentOS 7 一类老内核环境升级内核后再用 arm 构建,否则 binfmt 注册成功也无法正常执行。
© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容