| 项目 | 内容 |
|---|---|
| 分类 / 难度 | 诊断 / Easy |
| 分值 | 50 |
| 类型 | 容器启动故障排查(镜像引用缺 tag) |
| 题面 | 「引用上传记录(无 tag)验证容器能否启动」 |
1. 这是一道什么样的题
DIAG 是本次比赛中唯一一道没有攻击面的题目。它给的不是一个能访问的服务,而是一个现象:某个环境按上传记录启动时,容器起不来。
题面只有一句话:
引用上传记录(无 tag)验证容器能否启动
关键信息全在这句话里:
- 引用上传记录 —— 指的是按当初上传镜像时记录的镜像名去引用,而不是按完整坐标;
- 无 tag —— 记录里只有仓库名 + 镜像名,没有
:标签; - 验证容器能否启动 —— 现象是启动失败。
结合分值只有 50,可以判断这是一道"看一眼就懂、不懂就卡住"的常识题。
2. 复现现象
在目标节点上,按"上传记录"里的名字去引用同一个镜像 —— 也就是不带 tag:
$ docker images | grep check-01
lj-check-01-trap:v1 42206e37b9e4 148MB 37.7MB U
$ docker run -d --name diagtest lj-check-01-trap
Unable to find image 'lj-check-01-trap:latest' locally
docker: Error response from daemon: error from registry: ...
观察这行自动补全:
Unable to find image 'lj-check-01-trap:latest' locally
我们输入的是 lj-check-01-trap,Docker 自作主张补上了 :latest。
3. 根因
Docker 镜像的完整坐标是 [registry/][namespace/]repository[:tag|@digest]。tag 是可选部分,但省略时的语义不是"随便哪个版本",而是默认补 :latest。
于是发生了这个链条:
记录里的镜像名: lj-check-01-trap
│
▼ Docker 补全
实际查找的引用: lj-check-01-trap:latest
│
▼ 本地镜像表里只有 :v1
本地找不到 → 转向远程仓库拉取
│
▼ 仓库里没有 :latest(或拉取失败)
启动失败
用 docker images 印证:本地只有 lj-check-01-trap:v1,没有 :latest。
$ docker images | grep check-01
lj-check-01-trap:v1 42206e37b9e4 148MB 37.7MB
而 :latest 这个标签在语义上并无特殊地位 —— 它只是一个普通标签名。构建时如果不显式 -t name:latest,就不会产生它。所以"上传了镜像"和"本地存在 :latest“是两件事。
顺带一个常见误判:删掉 :v1 并不会让 :latest 出现,反而会一起报错 ——
$ docker rmi lj-check-01-trap
Error response from daemon: No such image: lj-check-01-trap:latest
这也反向证明了 docker rmi 同样会做 :latest 补全。
4. 结论
容器起不来的直接原因是:引用时省略了 tag,Docker 将其补全为 :latest,而本地只有 :v1(远程也无 :latest),镜像解析失败。
5. 修复
最小改动 —— 补上 tag:
docker run -d --name app lj-check-01-trap:v1
如果确实需要 latest 语义(例如平台按无 tag 引用):
# 给现有版本打上 :latest
docker tag lj-check-01-trap:v1 lj-check-01-trap:latest
# 或者用 tag 指向不可变摘要,避免 latest 漂移
docker tag lj-check-01-trap@sha256:42206e37b9e4... lj-check-01-trap:latest
从根上修 —— 记录侧不要存裸仓库名:
- 镜像上传记录里永远存完整坐标(
name:tag)或摘要(name@sha256:...); - 生产环境优先用 digest 而非 tag 引用,因为 tag 可被覆盖,digest 不可变;
- 若平台需要"最新"语义,构建流水线里显式打
:latest并同时打版本 tag,别指望 Docker 自动生成。
校验一下:
$ docker inspect --format '{{<.RepoTags>}}' lj-check-01-trap:v1
[lj-check-01-trap:v1]
如果在 RepoTags 里看不到 latest,就一定不能用裸名引用。
6. 顺带记住的几个坑
| 写法 | Docker 实际解释 |
|---|---|
nginx |
docker.io/library/nginx:latest |
myrepo/app |
docker.io/myrepo/app:latest |
registry:5000/app |
registry:5000/app:latest(端口不会被误判为 tag) |
app@sha256:... |
按摘要引用,tag 被忽略 |
app:v1 |
docker.io/library/app:v1 |
注意第三行:很多人以为 registry:5000/app 里的 :5000 是 tag —— 不会,Docker 只在最后一个 / 之后的 : 才当 tag 分隔符。所以 registry:5000/app 会被补成 registry:5000/app:latest。
7. 小结
这道题考的不是技巧,而是对镜像引用规则的确切记忆:
- tag 省略 ⇒ 默认
:latest; :latest只是一个普通标签,不是"最新版本"的保证;- 上传记录里丢了 tag,等于把一个能启动的镜像变成了无法解析的引用。
一句话答案:镜像引用缺 tag,Docker 补成 :latest,而实际镜像只有 :v1,因此找不到镜像、容器启动失败 —— 补上 :v1 即可。
(本题无 flag,判定依据为诊断结论是否正确。)