2. Docker镜像核心:镜像仓库、命名规范与唯一标识
聊完了镜像的分层结构,咱们得聊聊怎么找到、管理和引用这些镜像。说白了,就是三个问题:镜像放哪儿?怎么叫它?怎么区分不同的版本?
这三个问题,对应着今天要讲的三个核心概念:镜像仓库(Registry)、命名规范(Name:Tag)、以及镜像ID与Digest。嗯,这三样东西,你每天用Docker都会碰到,但很多人其实没完全搞明白。
2.1 镜像仓库(Registry)——镜像的“超级网盘”
镜像仓库,你可以把它想象成一个专门存Docker镜像的网盘。只不过这个网盘是分布式的,而且有严格的版本管理。
公共仓库 vs 私有仓库
- Docker Hub:最常用的公共仓库。我刚开始用Docker时,基本全靠它。但后来发现,公司内部的项目不能随便往上传,于是开始搭私有仓库。
- 私有仓库:比如 Harbor、Nexus、或者直接用 Docker Registry 官方镜像搭一个。我个人习惯用 Harbor,因为它带 Web UI 和权限管理,省心不少。
仓库地址的完整格式
你平时可能只写 nginx:latest,但完整的镜像地址其实是这样的:
[仓库地址]/[命名空间]/[镜像名]:[标签]
# 例如:
docker.io/library/nginx:latest
myregistry.example.com/myproject/myapp:v1.0
如果不写仓库地址,Docker 默认去 docker.io(也就是 Docker Hub)拉取。我在项目中遇到过有人把私有仓库的镜像推到 Docker Hub 上去了,结果死活拉不下来——就是因为没写仓库地址。
/etc/docker/daemon.json 里的 insecure-registries,否则 HTTPS 证书问题会让你抓狂。
2.2 镜像命名规范(Name:Tag)——别让你的镜像“裸奔”
镜像名 + 标签,就是镜像的“身份证号+姓名”。但很多人只写镜像名,不写标签,结果拉下来的版本完全不对。
标签的常见用法
| 标签写法 | 含义 | 风险 |
|---|---|---|
nginx:latest |
最新版 | 每次拉取可能不同,生产环境慎用 |
nginx:1.21.5 |
具体版本号 | 稳定,推荐 |
nginx:1.21 |
大版本号 | 可能指向不同的小版本 |
myapp:20240301 |
日期标签 | 适合CI/CD流水线 |
我踩过的坑: 曾经有一次,生产环境的 CI 脚本里写的是 myapp:latest。结果某天开发团队推送了一个有 bug 的版本,标签也是 latest,生产环境自动拉取后直接崩溃。从那以后,我要求所有生产环境必须用 具体版本号 或 Git commit SHA 作为标签。
:latest 标签!你永远不知道它指向的是哪个版本。
2.3 镜像ID与Digest——真正的“指纹”
标签是可以变的,但镜像ID和Digest是唯一的。就像人的名字可以改,但指纹改不了。
镜像ID
每个镜像层都有一个唯一的 SHA256 哈希值,镜像ID 就是最顶层(也就是镜像的元数据层)的哈希值。你可以用 docker images 看到它:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest f0f8b8b8b8b8 2 weeks ago 187MB
这个 f0f8b8b8b8b8 就是镜像ID。但注意,它只取前12位,完整的哈希有64位。
Digest——更可靠的标识
镜像ID 可能会因为 docker tag 操作而改变?不会。但 Digest 是真正不可变的。它是对整个镜像清单(Manifest)的哈希值。
你可以这样查看 Digest:
$ docker images --digests nginx
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
nginx latest sha256:abc123...def456 f0f8b8b8b8b8 2 weeks ago 187MB
或者用 docker inspect:
$ docker inspect nginx:latest | grep -A 10 "RepoDigests"
"RepoDigests": [
"nginx@sha256:abc123...def456"
]
为什么 Digest 这么重要?
你想想看,如果有人把 nginx:latest 标签指向了一个恶意镜像,你拉下来就中招了。但如果你用 Digest 拉取:
docker pull nginx@sha256:abc123...def456
那无论标签怎么变,拉下来的永远是那个确定的镜像。我在做安全审计时,要求所有生产环境必须记录 Digest,而不是标签。这样即使镜像仓库被篡改,也能保证一致性。
- 标签(Tag)是给人看的,方便记忆
- 镜像ID 是给 Docker 引擎用的,用于本地识别
- Digest 是给安全审计用的,保证不可篡改
2.4 知识体系图:镜像核心概念关系
下面这张图,帮你理清 Registry、Name:Tag、ID、Digest 之间的关系:
2.5 实战建议
说了这么多,给你几个我实际工作中的建议:
- CI/CD 中永远用 Digest 记录版本:在构建完成后,用
docker images --digests获取 Digest,写入部署配置文件。这样回滚时也能精确找到之前的版本。 - 私有仓库一定要配清理策略:我见过有人把测试镜像堆了几百个,磁盘直接爆了。用 Harbor 的话,可以设置保留最近 N 个版本。
- 标签命名要有规范:比如
项目名-环境-版本号,像myapp-prod-v2.3.1。别用test1、final这种让人摸不着头脑的名字。 - 拉取镜像时指定平台:如果你在 ARM 机器上拉 x86 镜像,会报错。用
--platform linux/amd64指定一下就好。
curl 直接调 Registry API:curl -s https://hub.docker.com/v2/repositories/library/nginx/tags | jq '.results[].name'
嗯,镜像仓库、命名规范、ID 和 Digest,这三样东西搞明白了,你就能在镜像管理上少踩很多坑。说白了,标签是给人看的,Digest 是给机器用的,镜像ID 是给 Docker 自己用的——各司其职。
可可精品资料库