从 Docker Hub 到 Harbor——镜像的存储、分发、安全治理
前置回顾
第 05 篇讲过:Registry 是镜像的存储和分发中心,推拉按层传输。第 06 篇讲过:好的 Dockerfile 产出小而安全的镜像——但镜像构建出来之后怎么办?谁来存、谁可以拉、有没有漏洞?这就是本篇要解决的问题。
先快速回顾第 05 篇的核心模型,然后我们往深处走:
docker build → docker tag → docker push → Registry → docker pull → docker run
│
└── 本篇聚焦这里
Registry 不光是一个"存镜像的地方"。在企业级场景中它还要回答:
| 问题 | Registry 要做什么 |
|---|---|
| 谁能 push?谁能 pull? | 认证 + 权限控制(RBAC) |
| 镜像里有漏洞吗? | 自动漏洞扫描(CVE 检测) |
| 怎么同步到另一个机房? | 镜像复制(Replication) |
| 磁盘被旧镜像占满了? | 垃圾回收(GC)+ 保留策略 |
| 能不能对外网不暴露? | 私有部署、HTTPS + 自签证书 |
Docker Hub 上最特殊的一批镜像叫 Docker Official Images——由 Docker 公司和相关社区维护,经过审核才发布。你在前几篇用的 nginx、postgres、redis、alpine 都在这个名单里。
如何区分仓库里谁的镜像可信?
# Docker Hub 上的三种身份标识
nginx ← Docker Official Image(官方维护,名字不带用户名前缀)
library/nginx ← 和上面是同一个,library 是官方镜像的隐式命名空间
mycompany/nginx ← Verified Publisher(企业认证发布者,有蓝色对勾)
randomuser/nginx ← 社区镜像(任何人都能上传,需谨慎使用)
不要看到 nginx 名字就放心——只有不带用户名前缀的那个才是官方的。someuser/nginx 是社区用户随便传的,可能是恶意镜像。
| 免费版 | 付费版(Pro / Team) | |
|---|---|---|
| 私有仓库 | 1 个 | 无限 |
| Pull 频率 | 每 6 小时 100 次(匿名)/ 200 次(登录) | 5000 次/天 起 |
| 存储空间 | 无限制(公共仓库) | 无限制 |
| 漏洞扫描 | 有限(仅官方镜像的部分 tag) | 完整 Snyk 扫描 |
| 团队协作 | 无 | RBAC + 审计日志 |
Rate Limiting 的影响
免费匿名用户每 6 小时只能 pull 100 次。如果你的 CI 流水线每次 push 代码都从 Docker Hub 拉基础镜像,10 个开发者一天推 30 次代码 = 300 次 pull → 很快就会触发限流,CI 报错 toomanyrequests。解决方案:登录后 pull(200 次/6h)、部署本地缓存 Registry(pull-through cache)、或者换用云厂商的镜像源。
用 Docker Hub 够了吗?对于个人项目和小团队,够。但以下几件事 Docker Hub 免费版做不到:
| 企业需求 | Docker Hub 免费版能做到? | 为什么做不到 |
|---|---|---|
| 镜像不经过公网 | ❌ | Docker Hub 在公网上,敏感业务的镜像不能传到外部服务器 |
| 谁 push 了生产镜像? | ❌ | 没有操作审计日志 |
| 这个镜像有 CVE 吗? | ❌ | 没有主动扫描机制(免费版扫不了私有仓库) |
| 深圳和新加坡的集群用同一份镜像 | ❌ | 没有跨区域复制,每个集群各自从 Docker Hub 拉 |
| 镜像保留 30 天自动清理 | ❌ | 没有保留策略和垃圾回收 |
Harbor(读作 "哈勃")是 CNCF 毕业项目(和 Kubernetes 同级),目前企业私有 Registry 的事实标准。它本质上是给开源 Docker Registry 加了一层完整的企业功能外壳。
┌─────────────────────────────────────────────────────────────┐
│ Harbor │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────┐ │
│ │ Portal │ │ API │ │ Auth │ │ Notary │ │
│ │ (Web UI) │ │ Server │ │ (OIDC) │ │ (签名) │ │
│ └──────────┘ └────┬─────┘ └──────────┘ └────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ Core │ │
│ │ (配置管理) │ │
│ └──────┬──────┘ │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Registry│ │Trivy │ │PostgreSQL│ │
│ │(镜像存储)│ │(漏洞扫描) │ │(元数据库) │ │
│ └────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌────────┐ ┌──────────┐ │
│ │ Redis │ │ Job │ ← 异步任务(复制/垃圾回收/扫描) │
│ │(缓存) │ │ Service │ │
│ └────────┘ └──────────┘ │
└─────────────────────────────────────────────────────────────┘
各组件职责(别被数量吓到——它们都是有原因才拆出来的):
| 组件 | 做什么 | 为什么单独 |
|---|---|---|
| Core | 配置管理中枢,管理项目/用户/权限/复制策略 | 业务逻辑集中,其他组件各司其职 |
| Registry | 就是开源 Docker Registry——存镜像、接收 push/pull | Harbor 是它的壳,不改 Registry 本身的代码 |
| Trivy | 扫描镜像每一层,查已知 CVE 漏洞 | 独立服务,可替换为其他扫描器(Clair、Snyk) |
| PostgreSQL | 存项目、用户、权限、扫描结果等元数据 | 镜像本身在 Registry 存,这些"关于镜像的信息"在 DB 存 |
| Redis | 缓存用户 session、API 限流计数 | — |
| Job Service | 跑异步任务:镜像复制、垃圾回收、触发扫描 | 耗时操作不阻塞 API,走任务队列 |
| Portal | Web UI(浏览器里操作 Harbor 的界面) | 和 API 分离,可以禁用只用 API/CLI |
Harbor = 仓库管理系统 + 开源 Docker Registry。Docker Registry 就是仓库里的一排排货架(存镜像数据),Harbor 是门禁系统 + 摄像头 + 质检员 + 登记表——它不代替货架,但让整个仓库变得安全、可管理。
Harbor 的权限体系分三层:系统级 → 项目级 → 仓库级。
系统级(整个 Harbor 实例):
├─ 系统管理员 → 可以创建项目、管理用户、配置全局设置
└─ 匿名用户 → 只能访问设为"公开"的项目
项目级(每个 Project 内):
├─ 项目管理员 → 管理该项目内的成员和配置
├─ 维护者 → 可以 push / pull / 删除镜像 / 配置复制策略
├─ 开发者 → 可以 push / pull(不能做管理操作)
└─ 访客 → 只能 pull
典型企业配置:
Project: backend(后端服务)
├─ 张三 → 维护者(可以发布新版本)
├─ 李四 → 开发者(日常 push)
└─ CI 机器人 → 开发者(CI 流水线 push 用)
Project: frontend(前端服务)
├─ 王五 → 项目管理员
└─ CI 机器人 → 开发者
→ 前端团队看不到后端项目的镜像,后端也看不到前端的
→ 都在同一个 Harbor 实例上,通过 RBAC 隔离开
# 不用每个开发者在 Harbor 里再注册一遍账号
# Harbor 可以直接对接公司现有的账号体系:
公司 LDAP / AD → Harbor 直接从域控同步用户和分组
OIDC(如 Keycloak / Okta)→ 单点登录,浏览器打开 Harbor 自动跳公司登录页
# 然后权限配置直接用 LDAP 的分组:
# "backend-team" 这个 LDAP 组的成员 → 自动获得 backend 项目的开发者权限
回顾第 06 篇:镜像由多层组成,每一层可能包含有漏洞的系统库。Harbor 用 Trivy 扫描每一层:
Trivy 怎么工作:
1. 拿到一个镜像(如 myapp:v1.0)
2. 解包每一层 → 提取出所有安装的软件包和版本号
3. 和 CVE 数据库比对(CVE = Common Vulnerabilities and Exposures,公共漏洞库)
→ libssl 版本 1.1.1k → 查 CVE 数据库 → CVE-2023-XXXX:高危!
→ openssl 版本 3.0.7 → 查 CVE 数据库 → CVE-2024-YYYY:严重!
4. 生成报告
Harbor 的可配置策略:
• 自动扫描:每次 push 新镜像自动触发
• 阻断策略:包含"严重"漏洞的镜像阻止部署(无法 pull)
• 白名单:某些 CVE 已知不影响你的业务,可以忽略
# 在 Harbor 项目设置里配置漏洞策略(概念示意)
vulnerability_policy:
on_push: auto_scan # 每次 push 自动扫描
prevent_pull:
severity: critical # 有"严重"漏洞的镜像不能 pull
allowlist:
- CVE-2024-0001 # 这个漏洞我们知道,不影响我们,放行
- CVE-2024-0002
这是 Harbor 最有价值的特性之一。多个 Harbor 实例之间可以自动同步镜像——不需要手动在每个机房 push 一遍。
场景:你的公司在深圳和新加坡各有一个数据中心
两个集群都需要跑同一个 myapp:v1.0 镜像
不用复制(低效):
深圳 CI → push 到深圳 Harbor → 深圳 K8s pull
新加坡 CI → 重新 build → push 到新加坡 Harbor → 新加坡 K8s pull
(两个地方各 build 一次,无法保证两次构建完全一致)
用复制(高效):
深圳 CI → build & push 到深圳 Harbor
→ Harbor 自动复制到新加坡 Harbor
→ 新加坡 K8s pull
(只 build 一次,Harbor 保证两边是同一个 digest 的镜像)
复制的两种模式:
Push 模式:深圳 Harbor 主动推到新加坡
┌─ 深圳 Harbor ─┐ ─── push ───→ ┌─ 新加坡 Harbor ─┐
└──────────────┘ └──────────────┘
Pull 模式:新加坡 Harbor 主动从深圳拉
┌─ 深圳 Harbor ─┐ ←── pull ─── ┌─ 新加坡 Harbor ─┐
└──────────────┘ └──────────────┘
复制触发方式:
• 事件驱动:每次 push 新镜像自动复制
• 定时:每天早上 8 点同步一次
• 手动:在 UI 里点"立即同步"
复制过滤器:
• 只复制标签匹配 release-* 的镜像(不复制 dev-* 的)
• 只复制仓库名为 backend/* 的(不复制 frontend/* 的)
如果你用云(AWS / 阿里云 / 腾讯云),通常不需要自己搭 Harbor——各云都有托管版的 Registry。选择标准很简单:
| Registry | 优势 | 劣势 |
|---|---|---|
| Harbor 自建 | 完全控制、无额外费用、功能最全 | 需要自己搭、自己维护、自己升级 |
| 云厂商托管 | 零维护、和云上其他服务深度集成(IAM 权限、VPC 内网免流量费) | 花钱(存储+流量)、功能不如 Harbor 丰富、换云需要迁移 |
选择建议:公司有运维团队 → Harbor 自建;小团队全在某一朵云上 → 用云的托管版;生产 Harbor + 云托管做镜像复制 → 双保险。
Harbor 官方提供了一套 Compose 文件,一键部署(注意——这和 07 篇学的完全对应,Harbor 自己就是用 Compose 跑的):
# 1. 下载 Harbor 安装包(选择 offline 版本,自带所有镜像)
wget https://github.com/goharbor/harbor/releases/download/v2.10.0/harbor-offline-installer-v2.10.0.tgz
tar xzf harbor-offline-installer-v2.10.0.tgz
cd harbor
# 2. 复制配置模板
cp harbor.yml.tmpl harbor.yml
# 3. 编辑 harbor.yml(最小配置)
# hostname: harbor.local ← 改成你的域名或 IP
# harbor_admin_password: xxxx
# 如果不用 HTTPS 先注释掉 https 部分,用 http
# 4. 安装并启动(本质就是 docker compose up -d)
sudo ./install.sh
# Harbor 会用 Compose 启动所有组件(nginx/proxy + core + registry + trivy + ...)
# 5. 浏览器打开 http://harbor.local
# 用户名 admin,密码你设的那个
# 6. 在 Harbor UI 里创建一个项目,然后配置本地 Docker
docker login harbor.local
# 按提示输入 admin / 密码
# 7. 推送镜像
docker tag myapp:v1 harbor.local/myproject/myapp:v1
docker push harbor.local/myproject/myapp:v1
学习用:Harbor 也可以用 Compose 一键起
Harbor 的 install.sh 做的事情无非就是:生成 docker-compose.yml → docker compose up -d。你可以去 harbor/ 目录下翻 docker-compose.yml,会看到 07 篇学到的所有东西:services、networks、volumes、healthcheck、depends_on——全部用上了。这又是一个"学了底层后回头看上层工具"的典型案例。
| 要点 | 一句话概括 |
|---|---|
| Docker Hub 官方镜像 | 没有用户名前缀的才是官方镜像(nginx),xxx/nginx 是社区上传的,需谨慎 |
| Docker Hub 限流 | 免费匿名每 6h 只 100 pull,CI 密集使用会触发 toomanyrequests |
| 为什么私有 Registry | 不经过公网、有审计日志、可主动扫漏洞、可跨机房同步、可设保留策略 |
| Harbor 架构 | Core(配置) + Registry(存镜像) + Trivy(扫漏洞) + PostgreSQL + Redis + Job Service |
| Harbor RBAC | 系统级 → 项目级(管理员/维护者/开发者/访客)→ 可对接公司 LDAP/OIDC 账号 |
| 漏洞扫描 | Trivy 解包每层 → 提取软件包版本 → 和 CVE 数据库比对 → 可配置阻断策略(有严重漏洞禁止 pull) |
| 镜像复制 | 推模式 / 拉模式,事件驱动或定时,支持按 tag/仓库名过滤——多数据中心自动同步 |
| 部署方式 | Harbor 自己就用 Compose 部署(你在 07 篇学的全部技能在此刻闭环) |
docker pull 回来运行docker logout 退出登录,然后跑 docker pull 几次,感受一下限流的实际体验(如果触发了的话)node:10),观察 Trivy 的扫描结果