镜像仓库

从 Docker Hub 到 Harbor——镜像的存储、分发、安全治理

阶段一 · 08 · 返回阶段大纲

前置回顾

第 05 篇讲过:Registry 是镜像的存储和分发中心,推拉按层传输。第 06 篇讲过:好的 Dockerfile 产出小而安全的镜像——但镜像构建出来之后怎么办?谁来存、谁可以拉、有没有漏洞?这就是本篇要解决的问题。

回顾:Registry 解决了什么问题

先快速回顾第 05 篇的核心模型,然后我们往深处走:

docker build → docker tag → docker push → Registry → docker pull → docker run
                            │
                            └── 本篇聚焦这里

Registry 不光是一个"存镜像的地方"。在企业级场景中它还要回答:

问题Registry 要做什么
谁能 push?谁能 pull?认证 + 权限控制(RBAC)
镜像里有漏洞吗?自动漏洞扫描(CVE 检测)
怎么同步到另一个机房?镜像复制(Replication)
磁盘被旧镜像占满了?垃圾回收(GC)+ 保留策略
能不能对外网不暴露?私有部署、HTTPS + 自签证书

Docker Hub

官方镜像与认证

Docker Hub 上最特殊的一批镜像叫 Docker Official Images——由 Docker 公司和相关社区维护,经过审核才发布。你在前几篇用的 nginxpostgresredisalpine 都在这个名单里。

如何区分仓库里谁的镜像可信?

# 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)、或者换用云厂商的镜像源。

为什么企业需要私有 Registry

用 Docker Hub 够了吗?对于个人项目和小团队,够。但以下几件事 Docker Hub 免费版做不到:

企业需求Docker Hub 免费版能做到?为什么做不到
镜像不经过公网Docker Hub 在公网上,敏感业务的镜像不能传到外部服务器
谁 push 了生产镜像?没有操作审计日志
这个镜像有 CVE 吗?没有主动扫描机制(免费版扫不了私有仓库)
深圳和新加坡的集群用同一份镜像没有跨区域复制,每个集群各自从 Docker Hub 拉
镜像保留 30 天自动清理没有保留策略和垃圾回收

Harbor 企业级 Registry

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/pullHarbor 是它的壳,不改 Registry 本身的代码
Trivy扫描镜像每一层,查已知 CVE 漏洞独立服务,可替换为其他扫描器(Clair、Snyk)
PostgreSQL存项目、用户、权限、扫描结果等元数据镜像本身在 Registry 存,这些"关于镜像的信息"在 DB 存
Redis缓存用户 session、API 限流计数
Job Service跑异步任务:镜像复制、垃圾回收、触发扫描耗时操作不阻塞 API,走任务队列
PortalWeb UI(浏览器里操作 Harbor 的界面)和 API 分离,可以禁用只用 API/CLI

Harbor = 仓库管理系统 + 开源 Docker Registry。Docker Registry 就是仓库里的一排排货架(存镜像数据),Harbor 是门禁系统 + 摄像头 + 质检员 + 登记表——它不代替货架,但让整个仓库变得安全、可管理。

RBAC 权限模型

Harbor 的权限体系分三层:系统级项目级仓库级

系统级(整个 Harbor 实例):
  ├─ 系统管理员    → 可以创建项目、管理用户、配置全局设置
  └─ 匿名用户      → 只能访问设为"公开"的项目

项目级(每个 Project 内):
  ├─ 项目管理员    → 管理该项目内的成员和配置
  ├─ 维护者        → 可以 push / pull / 删除镜像 / 配置复制策略
  ├─ 开发者        → 可以 push / pull(不能做管理操作)
  └─ 访客          → 只能 pull

典型企业配置:
  Project: backend(后端服务)
    ├─ 张三 → 维护者(可以发布新版本)
    ├─ 李四 → 开发者(日常 push)
    └─ CI 机器人 → 开发者(CI 流水线 push 用)

  Project: frontend(前端服务)
    ├─ 王五 → 项目管理员
    └─ CI 机器人 → 开发者

  → 前端团队看不到后端项目的镜像,后端也看不到前端的
  → 都在同一个 Harbor 实例上,通过 RBAC 隔离开

对接企业账号(LDAP / OIDC)

# 不用每个开发者在 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/* 的)

云厂商 Registry

如果你用云(AWS / 阿里云 / 腾讯云),通常不需要自己搭 Harbor——各云都有托管版的 Registry。选择标准很简单:

Registry优势劣势
Harbor 自建 完全控制、无额外费用、功能最全 需要自己搭、自己维护、自己升级
云厂商托管 零维护、和云上其他服务深度集成(IAM 权限、VPC 内网免流量费) 花钱(存储+流量)、功能不如 Harbor 丰富、换云需要迁移

选择建议:公司有运维团队 → Harbor 自建;小团队全在某一朵云上 → 用云的托管版;生产 Harbor + 云托管做镜像复制 → 双保险。

实践:5 分钟自建 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.ymldocker 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 篇学的全部技能在此刻闭环)

动手练习

  1. 在 Docker Hub 注册账号,把 06 篇或 07 篇写的镜像推上去。然后换一台机器(或删掉本地镜像后)docker pull 回来运行
  2. docker logout 退出登录,然后跑 docker pull 几次,感受一下限流的实际体验(如果触发了的话)
  3. 用 Compose 在本地部署 Harbor(根据上面实践小节的步骤),创建两个项目,给不同项目设置不同的成员权限,验证权限隔离生效
  4. 在 Harbor 里开启自动扫描,push 一个老旧镜像(比如 node:10),观察 Trivy 的扫描结果
  5. 思考题:为什么 Harbor 自己要用 Compose 来部署?如果 Harbor 的容器都停了,镜像数据还在吗?(提示:回顾 07 篇的 Volume)