docker pull 报 manifest unknown 怎么解决?tag 找不到的 4 种原因
现象:仓库在,tag 不在
Error response from daemon: manifest for myapp/api:v1.2.0 not found:
manifest unknown: manifest unknown
# 或拉 compose 依赖时
pull access denied(仓库级)
manifest unknown(tag 级)
一行结论:registry 认这个仓库,但找不到你写的那个 tag 对应的 manifest。manifest 是镜像的「目录页」(列出各架构的层信息),tag 指向 manifest——tag 错了或指向的东西不存在,就报这个错。
它和 pull access denied 是兄弟错误:denied 是仓库级问题(不存在/没权限),manifest unknown 是仓库内的 tag 级问题。看到 manifest unknown 说明仓库名多半是对的,盯住 tag 查。
四种原因,按概率排序
1. tag 拼写错误(最常见)
大小写敏感、v1.2 和 1.2 是两个 tag、- 和 _ 看混。最靠谱的核对方法——直接问 registry:
# 列出镜像的所有 tag(Docker Hub)
curl -s "https://hub.docker.com/v2/repositories/library/nginx/tags?page_size=20" | grep -o '"name":"[^"]*"'
# 或查特定 manifest 是否存在
docker manifest inspect myapp/api:v1.2.0
2. latest 陷阱:镜像根本没有 latest tag
docker pull myapp/api 省略 tag 时默认拉 latest。官方镜像基本都维护 latest,但个人/团队镜像经常只 push 过版本号 tag——docker push myapp/api:v1.2.0 不会自动创建 latest。写全 tag 就解决:
docker pull myapp/api:v1.2.0 # ✅ 显式 tag
docker pull myapp/api # ❌ 拉不存在的 latest
3. 官方镜像改名/下架
镜像生态会变迁:仓库转移(旧仓库归档只读)、更名(如 amazonlinux)、或某版本 tag 被清理。如果你的 Dockerfile/文档是几年前写的,docker manifest inspect 确认一下,然后去 Hub 搜同名镜像看新家。
4. 架构不匹配:manifest 存在但没有你这个平台的
docker pull --platform linux/amd64 myapp/api:v1 时,如果该 tag 只 push 过 arm64 的 manifest,就会报 manifest unknown 或 no matching manifest。M 系列 Mac 用户交叉构建时高发:
# 看这个 tag 都有哪些架构
docker manifest inspect myapp/api:v1 | grep -A2 platform
# 构建时显式指定平台,保证目标架构存在
docker buildx build --platform linux/amd64 -t myapp/api:v1 --push .
exec format error(运行时架构不匹配炸掉)是这个问题没在 pull 阶段暴露的后果——拉的时候就要对齐平台。
排查路线(按顺序两分钟)
# 1. 列出仓库真实存在的 tag
curl -s "https://hub.docker.com/v2/repositories/<user>/<repo>/tags?page_size=50" | grep -o '"name":"[^"]*"'
# 2. tag 对但还报错?查 manifest 与架构
docker manifest inspect <完整镜像名:tag>
# 3. 省略 tag 拉的?补全 tag 再试
docker pull <完整镜像名>:<显式tag>
和相邻错误的分界
| 报错 | 层级 | 方向 |
|---|---|---|
| manifest unknown / not found | tag 级 | 本篇 |
| pull access denied | 仓库级 | pull access denied 排查 |
| no matching manifest for platform | 架构级 | 本篇原因 4 |
| exec format error | 运行时架构 | 拉取阶段就该对齐平台 |
查 registry 里到底有什么
两条命令解决多数 manifest 争议而无需 pull。docker manifest inspect name:tag 打印 manifest 列表——多架构镜像列出 amd64/arm64 条目;单架构只有一条。列表缺你的平台时,pull 在错架构机器上就报这个错(经典:Apple Silicon 构建、amd64 CI 部署)。skopeo inspect 不需要 Docker daemon,CI 上没有 socket 时也行。先查再拉,把神秘运行时错误变成十秒读数。
buildx:让这类错不可能发生
如果你构建并分发镜像,修复在构建期:docker buildx build --platform linux/amd64,linux/arm64 --push 产出对两个平台都应答的 manifest 列表——整类错误对消费者消失。代价是跨架构构建的 QEMU 一次性设置。从笔记本构建的团队:buildx 不是可选工具——是「在服务器能用」和「只在构建机能用」的区别。
registry 三怪癖
Docker Hub 匿名拉取限流(高峰期 401/429 伪装成 manifest 失败);GHCR 要求大小写精确的 owner 名(ghcr.io/Owner/repo 写 owner 拒绝);自建 registry 在代理后面有时返回推送后的陈旧 manifest 缓存(重试或戳穿代理)。同一 tag 一台机器拉得动另一台拉不动,嫌疑是机器的 DNS/代理路径而不是 tag。
tag 与 digest:钉死你真正拉到的内容
tag 会漂移:myapp/api:v1 明天重建推送后可以指向另一份 manifest。digest 不会:
docker buildx imagetools inspect myapp/api:v1.2.0 --format '{{json .Manifest}}'
docker pull myapp/api@sha256:0123abcd…
Dockerfile 里可用 FROM myapp/api:v1.2.0@sha256:…(tag 给人看,digest 保可复现),或用 Dockerfile 生成器 生成带钉死基础镜像的模板。生产 Compose 只写浮动 tag,和「tag 被删」一样容易在周一早上变成 manifest unknown。
看起来像「tag 不存在」的鉴权噪音
私有 registry 有时把 401/403 改写成 manifest unknown / not found,避免泄露仓库是否存在。线索:
docker login或换新 CI token 之后同一 tag 立刻能拉;- Hub 匿名限流(429)在高峰被客户端说成含糊的 pull 失败;
- GHCR / 多数云 registry 要求路径里 owner 大小写完全一致。
若浏览器登录后 Tags 页看得到 tag,而 docker manifest inspect 报鉴权相关话术,先修凭证,别空转拼写排查。
Compose / CI:错误 tag 从哪混进来
image: myapp/api 不写 tag、${IMAGE_TAG} 为空、流水线构建 :sha-abc 却部署 :latest——这三种最常见。pull 前打印解析结果:
echo "pulling ${IMAGE:?IMAGE unset}"
docker compose config | grep 'image:'
docker pull "$IMAGE"
本机能拉、远端 agent 不能时,对比 daemon 架构(docker version)和 registry 镜像加速配置——镜像站可能缓存了过期或单架构的 manifest 列表。
排查清单
- tag 拼写逐字符核对(大小写、v 前缀、分隔符)
- 省略 tag = 拉 latest——这个镜像真的有 latest 吗?
- Hub Tags 页 / registry API 列出真实 tag 列表
- 指定了
--platform的,确认该 tag 有对应架构的 manifest - 老 Dockerfile 里的镜像名,确认仓库没改名/下架
- 鉴权 / 限流:
docker login后错误是否变化? - 生产 FROM/pull 在 tag 解析成功后优先钉 digest
排查注记
排查主线盯 tag 不盯仓库名,依据是开头那条兄弟错误分界:pull access denied 是仓库级、manifest unknown 是 tag 级——看到 manifest unknown,仓库名多半已经对了。四种原因里 tag 拼写第一、latest 陷阱第二,因为 push 版本号 tag 不会自动创建 latest,而省略 tag 默认拉的就是这个不存在的标签。文末专门留了「鉴权噪音」一节,判断线索是 docker login 后同一 tag 立刻能拉——先修凭证,别空转拼写排查。
来自 ToolVault 工具匣 的开发手记。相关工具:Dockerfile 生成器、docker run 转 compose、Linux 命令速查。相关阅读:pull access denied 排查、Docker 磁盘爆满清理。访问 首页 查看更多开发者工具。
相关工具
相关文章
Linux crontab 定时任务实战:命令、日志与排查
crontab 不只是写表达式:三个必会命令、/etc/cron.d 与用户 crontab 的区别、任务没跑的五步排查法、PATH/时区/% 转义、MAILTO,以及秒级任务的正确解法。
docker run 转 docker-compose 完全指南:为什么转、怎么转、参数对照表
把 docker run 命令迁移到 docker-compose.yml 的完整指南:compose 相比裸 run 的五大优势、参数逐项对照表(端口/卷/环境变量/重启策略/网络)、常见坑(裸 -e 透传、匿名卷、--rm 语义),附在线转换器用法。
Permission denied (publickey) 怎么解决?Git 推送失败的 6 种原因与修复
git clone/push 报 Permission denied (publickey) fatal: Could not read from remote repository?覆盖公钥没生成、没加载进 agent、没添加到 GitHub/Gitee、多账号配错密钥、deploy key 权限、remote URL 写错六种根因,附 ssh -v 诊断方法。