避坑指南:为什么我的 Docker 镜像在 Docker Hub 上没有多架构(Multi-Arch)支持?

问题现象

在 Mac (Apple Silicon / M1/M2/M3) 上编译并推送 Docker 镜像时:

1
2
docker push docker.io/damingerdai/rammal:v0.0.1-alpha.0

发现 Docker Hub 页面上的 Tag 只显示 linux/arm64,并没有预期的 linux/amd64linux/arm64 共存。重新针对 amd64 推送后,原有的 arm64 镜像反而被覆盖掉了。


原因分析

1. 默认构建引擎(Driver)的局限

运行 docker buildx ls 会发现,默认使用的是 default 实例,其驱动为 docker 引擎:

1
2
3
NAME/NODE      DRIVER/ENDPOINT
default* docker

  • 原生 docker 驱动使用的是 Docker Engine 本地的镜像存储(Image Store)。
  • 本地存储设计初衷是存储单架构镜像,无法直接在本地保存或组合多架构 Manifest List(即包含多个架构镜像指针的索引)。

2. Docker Hub 的覆盖机制

  • 多架构镜像(Multi-Arch Image)本质上是一个 Manifest List
  • 如果分别用单架构构建并先后推送同一个 Tag,后一次推送会直接覆盖前一次的 Manifest,而不会自动合并。

解决方案

使用 Docker Buildx 配合 docker-container 驱动一键构建并推送。

第一步:创建并切换到支持多架构的 Builder 实例

1
2
3
4
5
6
# 创建一个新的 builder 实例(驱动默认为 docker-container)
docker buildx create --name mybuilder --use

# 启动并初始化 builder
docker buildx inspect --bootstrap

初始化完成后,运行 docker buildx ls,确保当前使用的是 mybuilder 且 Driver 为 docker-container

第二步:构建并直接推送多架构镜像

通过传入多个 -t 参数,可以一次构建同时为版本号(如 v0.0.1-alpha.0)和 latest 打上标签并推送:

1
2
3
4
5
6
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t docker.io/damingerdai/rammal:v0.0.1-alpha.0 \
-t docker.io/damingerdai/rammal:latest \
--push .

重点提示

  1. 必须加上 --push 参数。因为多架构 Manifest 无法保存在本地普通的 Docker 镜像库中,必须在构建完成时直接推送到远程 Registry。
  2. 支持同时指定多个 -t 参数(例如追加 :latest),Buildx 只会进行一次编译,但会为所有指定 Tag 生成对应的多架构 Manifest List。

验证多架构镜像

推送完成后,可通过以下命令验证镜像的 Platform 信息:

1
2
docker buildx imagetools inspect docker.io/damingerdai/rammal:v0.0.1-alpha.0

如果输出中同时包含了 linux/amd64linux/arm64,说明多架构镜像构建并推送成功!

备忘金句

  • docker build + docker push** 只能推单架构,重复推同名 Tag 会覆盖**。
  • docker buildx build --platform ... --push 才是打包多架构镜像的标准姿势。