一、镜像不能只存在自己电脑上
小陈构建好了直播模块的镜像,正要部署到生产服务器,发现一个问题:
"师傅,生产服务器上没有我构建的镜像啊……难道我要把镜像文件拷过去?"
"对,这就是镜像仓库(Registry)存在的意义。"老周说,"镜像仓库 = 镜像的'中央仓库'——开发机构建好镜像,推送到仓库;生产服务器从仓库拉取。镜像有了一个'官方来源',部署才有了标准流程。"
镜像仓库 Registry:
┌──────────┐ push(推) ┌──────────┐ pull(拉) ┌──────────┐
│ 开发机 │ ────────────▶ │ 仓库 │ ────────────▶ │ 生产服务器 │
│ (构建镜像) │ │ Registry │ │ (部署) │
└──────────┘ └──────────┘ └──────────┘
作用:
① 集中存放:所有镜像统一管理,不散落在各机器
② 版本管理:同一镜像多个 tag(v1/v2/latest)
③ 权限控制:谁能推、谁能拉,可以精细管理
④ 安全扫描:扫描镜像漏洞(下面讲)
二、公共仓库 vs 私有仓库
"镜像仓库分两种:公共的和私有的。"老周说:
公共仓库:
Docker Hub(官方,最常用)
- 拉公共镜像(nginx、mysql、python...)从这里
- 也可以把自己的镜像公开分享
- 问题:公共的,企业敏感镜像不能放这
私有仓库:
自建的、只有自己人能访问
- Docker Registry(官方轻量版)
- Harbor(企业级,功能全:权限/扫描/复制,最常用)
- 云厂商的容器镜像服务(阿里云 ACR 等)
云间书店方案:
公共镜像(mysql/nginx/python)→ 从 Docker Hub 拉
业务镜像(yunjian/web、yunjian/api)→ 推到私有 Harbor
"公共的拉基础,私有的存业务——这是镜像仓库的标准用法。"
三、搭建私有仓库:Harbor
老周带小陈部署 Harbor(企业级私有仓库):
# 方式一:docker run 起一个轻量私有仓库(开发测试用)
docker run -d -p 5000:5000 --name registry registry:2
# 方式二:企业级 Harbor(生产推荐,功能全)
# 下载安装包后
./install.sh # 安装 Harbor(自带 UI、权限、扫描)
# 使用流程
# 1. 登录私有仓库
docker login harbor.yunjian.com
# 2. 给镜像打上仓库地址的标签
docker tag yunjian/web:v1 harbor.yunjian.com/library/web:v1
# 3. 推送
docker push harbor.yunjian.com/library/web:v1
# 4. 生产服务器拉取
docker pull harbor.yunjian.com/library/web:v1
"注意镜像名的格式:仓库地址/项目/镜像名:版本。 生产上镜像名带上仓库地址,pull 的时候才知道从哪拉。"
四、镜像安全:别让"供应链"变成"漏洞链"
"镜像从仓库来,那仓库里的镜像安全吗?"老周话锋一转,严肃起来,"2021 年有一个真实的供应链攻击案例:有攻击者往 Docker Hub 上上传了伪装成热门工具的恶意镜像,下载量超过 100 万次——开发者拉下来一跑,服务器就被种了后门。 这就是镜像供应链攻击。"
镜像安全三大威胁:
① 恶意镜像:伪装成热门工具,内藏后门/挖矿程序
→ 只从官方/可信源拉取,不拉来路不明的镜像
② 漏洞镜像:基础镜像或依赖有已知漏洞(如 Log4j)
→ 定期扫描(trivy/Clair/Harbor 自带扫描)
③ 篡改镜像:镜像被中间人篡改(推拉过程中被替换)
→ 用内容信任(Docker Content Trust)签名验证
# 用 trivy 扫描镜像漏洞
trivy image harbor.yunjian.com/library/web:v1
# 输出:发现 3 个高危漏洞 → 升级基础镜像修复
# 只拉可信来源(安全习惯)
docker pull nginx:1.25 # 官方库
docker pull hub.example.com/... # 自建可信仓库
# ❌ 不要从陌生人的仓库拉不明镜像!
"镜像安全的核心是'来源可信':从哪里拉、有没有签名、有没有漏洞——生产环境的镜像,必须是受控的。 这就是为什么企业都要自建 Harbor + 扫描,而不是随便从公共仓库拉业务镜像。"
五、镜像版本管理:tag 的艺术
"最后讲镜像的版本管理。tag 起得不好,部署就是灾难。"老周说:
坏的 tag 习惯:
❌ latest:永远指向最新,但"最新"是什么?没法回滚!
❌ v1:太模糊,v1 改了几十次,哪个是哪个?
❌ 不带 tag:默认 latest,同上
好的 tag 习惯:
✅ 语义化版本:v1.2.3(主版本.次版本.补丁)
✅ 带构建号:v1.2.3-build20260909(精确到这次构建)
✅ 加环境:web-prod-v1.2.3(明确环境)
云间书店的 tag 规范:
yunjian/api:1.2.3 # 正式版本
yunjian/api:1.2.3-rc1 # 候选版本(预发布)
yunjian/api:latest # 仅指向最新稳定版(方便测试)
# 部署永远用具体版本号,方便回滚!
"生产部署必须用具体版本号,绝不裸用 latest。 这样回滚就是一句 docker pull 旧版本号 的事。"
六、章末:老周的第七层总结
第七层:镜像仓库与安全
├── 仓库 Registry:镜像中央仓库(push/pull)
├── 公共 vs 私有:公共拉基础,私有存业务(Harbor)
├── 镜像名格式:仓库地址/项目/镜像名:版本
├── 镜像安全:来源可信 + 漏洞扫描(trivy)+ 内容信任
└── tag 规范:语义化版本,生产不用 latest(可回滚)
"小陈,镜像管理好了,部署也能一键完成了。但你现在部署的目标,还是'一台服务器'。如果云间书店要开 5 家分店、要搞双十一秒杀、流量翻 100 倍——一台服务器顶得住吗?"
"顶不住……那得上很多台服务器?"
"对,而且容器要在多台机器之间'自动调度':哪台闲跑哪台、挂了自动重启、流量大了自动扩容。这就是编排的终极形态——Kubernetes。 下一章,云间书店的容器要'上 K8s'了。"