菜单

Administrator
发布于 2026-04-03 / 2 阅读
0

从一次 docker pull 异常说起:新旧版 Docker 在多架构镜像处理上的行为差异

摘要

在多架构镜像场景下,同样的 docker pull 命令,在不同 Docker 版本或不同本地 image store 后端上,可能表现出完全不同的结果:有的环境下镜像会直接体现为单架构镜像,可以正常查看 Architecture 并执行 docker save;有的环境下则只会看到一个 manifest list,本地 inspect 无法直接看到架构信息,save 还可能报错。

本文结合实际排查过程,说明新旧版 Docker 在多架构镜像处理上的差异,并给出两类可落地方案:

  • 如何恢复旧版 Docker 的使用体验
  • 如何在新版本 Docker 下正确保存单架构镜像

  • 如何恢复旧版 Docker 的使用体验
  • 如何在新版本 Docker 下正确保存单架构镜像

一、问题现象

排查过程中,遇到了如下现象:

  • 两台机器执行相同的 docker pull 命令
  • 一台机器可以正常 pullinspectsave
  • 另一台机器虽然 pull 成功,但:
    • docker image inspect 看不到 Architecture
    • docker save 报错
    • 本地看到的是 manifest list,而不是单架构镜像

典型表现如下:

docker image inspect quay.io/ascend/vllm-ascend:releases-v0.13.0

输出中可能出现:

"Architecture": "",
"Os": "",
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json"

这说明当前本地看到的不是某个具体平台镜像,而是一个多架构入口。


二、根因分析

1. 镜像本身是多架构镜像

先看远端 manifest:

docker manifest inspect quay.io/ascend/vllm-ascend:releases-v0.13.0

例如输出:

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
  "manifests": [
    {
      "digest": "sha256:0f8f22023543fe3cb4414192d8f3e4b098b8489c27a559befa108f115478bfd6",
      "platform": {
        "architecture": "arm64",
        "os": "linux"
      }
    },
    {
      "digest": "sha256:69ec114c9ba3ac151b93f8183304d409ee015f4d917e4e655883d6b877493464",
      "platform": {
        "architecture": "amd64",
        "os": "linux"
      }
    }
  ]
}

说明该 tag 同时支持:

  • linux/arm64
  • linux/amd64

也就是说,这个 tag 指向的是 manifest list,不是某一个单独架构镜像。


2. 新旧版 Docker 的 image store 行为不同

核心差异通常不在镜像仓库,而在本地 Docker。

旧体验

旧版 Docker,或者仍在使用 classic image store 的环境,往往会把多架构 tag 落成更接近“单架构镜像”的本地表现:

  • docker image inspect 能直接看到架构
  • docker save 更容易成功
  • 用户感觉上“一个 tag 就是一个镜像”

新体验

新版本 Docker,特别是启用了 containerd image store 的环境,会更完整地保留 manifest list / image index 语义:

  • 本地 tag 可能对应的是 manifest list
  • docker image inspect 顶层未必能直接看到架构
  • docker save 可能在处理多架构对象时失败

三、为什么 docker save 会失败

典型报错如下:

docker save -o vllm-ascend.tar quay.io/ascend/vllm-ascend:releases-v0.13.0

报错:

Error response from daemon: unable to create manifests file: NotFound: content digest sha256:69ec114c9ba3ac151b93f8183304d409ee015f4d917e4e655883d6b877493464: not found

这个报错的含义通常是:

  • 本地 tag 指向的是一个多架构 manifest list
  • 但是本地并没有完整持有该 list 下所有子内容
  • docker save 在整理导出内容时,发现某个 digest 不在本地,于是失败

如果远端 manifest 里:

  • sha256:0f8f22...arm64
  • sha256:69ec11...amd64

而报错缺的是 sha256:69ec11...

那通常可以反推出:

本地已经拿到的是 arm64 子镜像,而缺失的是 amd64 子镜像。


四、docker pull 不指定 --platform 是否两边都能跑

答案是:

不是同一份本地镜像同时能在 amd64 和 arm64 上运行,而是 Docker 会根据当前机器平台自动选择对应架构的子镜像。

例如:

docker pull quay.io/ascend/vllm-ascend:releases-v0.13.0
  • amd64 主机上,通常会选择 amd64
  • arm64 主机上,通常会选择 arm64

这意味着:

  • 同一个 tag 可以在不同机器上分别 pull
  • 但不同机器拉下来的实际内容并不是同一份单架构镜像
  • docker save 导出的 tar 包仍然是单架构内容,不会天然跨架构通用

五、如何确认本地到底是 arm64 还是 amd64

方法 1:先看远端支持哪些架构

docker manifest inspect quay.io/ascend/vllm-ascend:releases-v0.13.0

方法 2:看自己拉取时有没有指定平台

docker pull --platform linux/arm64 quay.io/ascend/vllm-ascend:releases-v0.13.0

如果明确执行过这条,那么该次拉取目标就是 arm64

方法 3:根据 save 报错反推

例如:

NotFound: content digest sha256:69ec114c...

而已知:

  • sha256:69ec114c... = amd64
  • sha256:0f8f2202... = arm64

那就说明:

  • 本地已经有的是 arm64
  • 缺的是 amd64

因此可以判断,本地拉下来的具体镜像内容是 arm64


六、如何恢复旧版 Docker 的使用体验

如果希望新机器表现得更像旧机器,最直接的方法是:

切回 classic image store,不使用 containerd image store。

1. 先看当前 Docker 情况

docker version
docker info
docker info -f '{{ .DriverStatus }}'

如果输出中出现类似:

driver-type io.containerd.snapshotter.v1

通常说明当前启用了 containerd image store 相关能力。

2. Linux 上修改 /etc/docker/daemon.json

查看当前配置:

cat /etc/docker/daemon.json

如果当前启用了 containerd snapshotter,可改成如下:

{
  "features": {
    "containerd-snapshotter": false
  },
  "storage-driver": "overlay2"
}

重启 Docker:

sudo systemctl restart docker

再次确认:

docker info

3. Docker Desktop 上关闭 containerd image store

如果是 Docker Desktop,可在设置中关闭:

  • Use containerd for pulling and storing images

关闭后重新应用配置即可。

4. 注意事项

切换 image store 后:

  • 原来另一套 store 中的镜像和容器会暂时“看不见”
  • 通常不是丢失,而是当前 Docker daemon 换了另一套后端视图

因此切换前建议先备份:

docker images
docker ps -a

必要时先导出能导出的镜像。


七、新版本 Docker 下如何正确保存镜像

在新版本 Docker 下,不要直接对多架构 tag 执行 docker save,而应当保存具体平台的子镜像。

方法一:先找出具体平台的 digest

先查看 manifest:

docker manifest inspect quay.io/ascend/vllm-ascend:releases-v0.13.0

假设得到:

  • arm64: sha256:0f8f22023543fe3cb4414192d8f3e4b098b8489c27a559befa108f115478bfd6
  • amd64: sha256:69ec114c9ba3ac151b93f8183304d409ee015f4d917e4e655883d6b877493464

方法二:按具体 digest 拉取

拉取 arm64:

docker pull quay.io/ascend/vllm-ascend@sha256:0f8f22023543fe3cb4414192d8f3e4b098b8489c27a559befa108f115478bfd6

拉取 amd64:

docker pull quay.io/ascend/vllm-ascend@sha256:69ec114c9ba3ac151b93f8183304d409ee015f4d917e4e655883d6b877493464

方法三:给 digest 打本地 tag

保存 arm64 时:

docker tag quay.io/ascend/vllm-ascend@sha256:0f8f22023543fe3cb4414192d8f3e4b098b8489c27a559befa108f115478bfd6 vllm-ascend:arm64

保存 amd64 时:

docker tag quay.io/ascend/vllm-ascend@sha256:69ec114c9ba3ac151b93f8183304d409ee015f4d917e4e655883d6b877493464 vllm-ascend:amd64

方法四:再执行 docker save

保存 arm64:

docker save -o vllm-ascend-arm64.tar vllm-ascend:arm64

保存 amd64:

docker save -o vllm-ascend-amd64.tar vllm-ascend:amd64

这种做法的优点是:

  • 避开多架构 tag 的 manifest list 问题
  • 导出的就是明确的单架构镜像
  • 后续导入和管理更清晰

八、推荐操作方式

场景 1:希望维持旧机器体验

建议:

docker version
docker info
cat /etc/docker/daemon.json

确认后切回 classic image store。

适合场景:

  • 习惯旧 Docker 行为
  • 需要直接 inspect 看到架构
  • 需要对 tag 直接 save
  • 依赖旧脚本、旧流程

场景 2:接受新版本 Docker 行为,但希望稳定导出镜像

建议统一采用以下流程:

docker manifest inspect <image:tag>
docker pull <image@sha256:platform_digest>
docker tag <image@sha256:platform_digest> local-name:platform
docker save -o xxx.tar local-name:platform

适合场景:

  • 不改宿主机 Docker 配置
  • 接受 manifest list / image index 语义
  • 只要求明确导出单架构镜像

九、结论

这次问题的关键不在镜像仓库,而在于:

  • 镜像本身是多架构镜像
  • 新旧版 Docker 对多架构对象的本地处理方式不同
  • 新版本 Docker 更可能把 tag 落成 manifest list
  • 因而带来 inspect 看不到架构、save 失败等现象

如果希望恢复旧体验,可以切回 classic image store。 如果希望保留新版本 Docker,则应当按具体平台 digest 拉取并保存单架构镜像。

从运维实践角度看,团队内部最好统一:

  • Docker 主版本
  • image store 类型
  • 镜像导出流程

这样才能避免同样命令在不同机器上出现不一致结果。