饮墨

子安饮墨馀三斗,留与卿儿作赋来

Harbor 私有容器镜像仓库:生产级部署与安全管控全流程

痛点

团队规模一大,容器镜像管理就失控:

  • Docker Hub 拉取限流(匿名用户 100 pulls/6h),CI/CD 流水线频繁卡死
  • 镜像散落在多个 registry,版本溯源困难,无法统一安全扫描
  • 合规要求镜像不能存放第三方公有云,必须内部托管
  • 缺乏细粒度权限控制,所有人都能 push/delete 生产镜像

如果你的 Kubernetes 集群超过 10 个节点、每天构建镜像超过 50 次,一个靠谱的私有 registry 就是刚需。Harbor 是 CNCF 毕业项目,目前最成熟的开源选择。

方案

Harbor = 私有镜像仓库 + 漏洞扫描 + RBAC + 镜像签名 + 复制策略,一套解决所有镜像管理问题。

核心架构:

┌─────────────────────────────────────────────┐
│                 Harbor Core                   │
├──────────┬──────────┬───────────┬───────────┤
│  Portal  │  API v2  │ Registry  │  Trivy    │
│  (Web UI)│  (REST)  │  (分发)    │  (扫描)   │
├──────────┴──────────┴───────────┴───────────┤
│  PostgreSQL  │  Redis  │  S3/MinIO (存储后端) │
└─────────────────────────────────────────────┘

关键能力对比:

特性 Docker Registry Harbor AWS ECR
漏洞扫描 ✅ (Trivy 集成)
RBAC ✅ (项目级) ✅ (IAM)
镜像签名 手动 ✅ (Cosign/Notation)
复制策略 ✅ (跨地域) ✅ (ECR Replication)
垃圾回收 手动 ✅ (定时) ✅ (Lifecycle)
成本 免费 免费 $0.10/GB/月

实操步骤

第一步:用 Docker Compose 快速部署(生产就绪)

# 下载 Harbor 离线安装包(v2.11.x)
wget https://github.com/goharbor/harbor/releases/download/v2.11.2/harbor-offline-installer-v2.11.2.tgz
tar xzf harbor-offline-installer-v2.11.2.tgz
cd harbor

# 复制并编辑配置
cp harbor.yml.tmpl harbor.yml

编辑 harbor.yml 核心配置:

hostname: registry.example.com

# HTTPS 配置(生产必开)
https:
  port: 443
  certificate: /etc/harbor/certs/server.crt
  private_key: /etc/harbor/certs/server.key

# 存储后端改用 S3/MinIO(默认是本地文件系统)
storage_service:
  s3:
    accesskey: YOUR_ACCESS_KEY
    secretkey: YOUR_SECRET_KEY
    region: us-east-1
    bucket: harbor-registry
    rootdirectory: /registry

# 数据库(生产建议外置 PostgreSQL)
database:
  password: <strong-password>
  max_idle_conns: 50
  max_open_conns: 1000

# Trivy 漏洞扫描器
trivy:
  ignore_unfixed: true
  skip_update: false
  security_check: vuln

执行安装:

./install.sh --with-trivy --with-chartmuseum

# 验证所有组件运行
docker compose ps
# 应看到 harbor-core, harbor-portal, registry, trivy-adapter 等全部 healthy

第二步:配置项目与 RBAC 权限

# 创建项目(通过 API)
curl -k -X POST "https://registry.example.com/api/v2.0/projects" \
  -H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "project_name": "production",
    "metadata": {
      "public": "false",
      "auto_scan": "true",
      "severity": "high",
      "prevent_vul": "true"
    },
    "storage_limit": 107374182400
  }'

关键安全配置说明: - auto_scan: true — 每次 push 自动触发 Trivy 扫描 - prevent_vul: true + severity: high — 含高危/严重漏洞的镜像禁止被 pull - storage_limit — 项目级存储配额(此处 100GB)

配置机器人账户(给 CI/CD 用):

# 创建机器人账户,限制只能 push 到 production 项目
curl -k -X POST "https://registry.example.com/api/v2.0/robots" \
  -H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ci-pusher",
    "duration": 365,
    "level": "project",
    "permissions": [{
      "namespace": "production",
      "kind": "project",
      "access": [
        {"resource": "repository", "action": "push"},
        {"resource": "repository", "action": "pull"}
      ]
    }]
  }'

第三步:Kubernetes 集群对接

创建 pull secret 并配置默认 ServiceAccount:

# 创建 registry secret
kubectl create secret docker-registry harbor-creds \
  --docker-server=registry.example.com \
  --docker-username=robot\$ci-pusher \
  --docker-password=<robot-token> \
  -n production

# 给 default ServiceAccount 添加 imagePullSecrets(全命名空间生效)
kubectl patch serviceaccount default -n production \
  -p '{"imagePullSecrets": [{"name": "harbor-creds"}]}'

在 CI/CD 中使用(GitHub Actions 示例):

- name: Build and Push
  run: |
    docker login registry.example.com -u robot\$ci-pusher -p ${{ secrets.HARBOR_TOKEN }}
    docker build -t registry.example.com/production/myapp:${{ github.sha }} .
    docker push registry.example.com/production/myapp:${{ github.sha }}

第四步:配置跨地域复制(灾备)

# 添加远端 registry endpoint
curl -k -X POST "https://registry.example.com/api/v2.0/registries" \
  -H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "dr-site",
    "type": "harbor",
    "url": "https://registry-dr.example.com",
    "credential": {
      "type": "basic",
      "access_key": "replication-user",
      "access_secret": "replication-password"
    }
  }'

# 创建复制策略:production 项目所有 tag 为 release-* 的镜像同步到灾备站
curl -k -X POST "https://registry.example.com/api/v2.0/replication/policies" \
  -H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "prod-to-dr",
    "src_registry": null,
    "dest_registry": {"id": 1},
    "dest_namespace": "production",
    "filters": [
      {"type": "name", "value": "production/**"},
      {"type": "tag", "value": "release-*"}
    ],
    "trigger": {"type": "event_based"},
    "enabled": true
  }'

避坑

1. 存储爆炸 — 不清理旧镜像导致磁盘告警

Harbor 默认不删除未被 tag 引用的 blob。必须开启垃圾回收:

# 通过 API 触发 GC(建议 cron 每周执行)
curl -k -X POST "https://registry.example.com/api/v2.0/system/gc/schedule" \
  -H "Authorization: Basic $(echo -n 'admin:Harbor12345' | base64)" \
  -H "Content-Type: application/json" \
  -d '{"schedule": {"type": "Weekly", "cron": "0 0 2 * * 0"}}'

同时配置 Tag 保留策略:每个仓库只保留最近 10 个 tag + 最近 30 天的 tag,其余自动删除。

2. Trivy 数据库更新失败 — 扫描结果过时

离线环境下 Trivy 无法自动拉取漏洞数据库。解决方案:

# 在有网络的机器上定期下载 Trivy DB
oras pull ghcr.io/aquasecurity/trivy-db:2
# 将 db.tar.gz 传到 Harbor 服务器,配置 skip_update + 本地 DB 路径

生产环境建议:用内网 HTTP 代理让 Trivy 定时同步,或搭建 trivy-db 的内部 mirror。

3. Harbor 升级踩坑 — 数据库迁移失败

升级前必做:

# 1. 备份数据库
docker compose exec harbor-db pg_dump -U postgres registry > harbor_backup.sql
# 2. 备份配置
cp harbor.yml harbor.yml.bak
# 3. 停止服务后再解压新版本覆盖安装
docker compose down
# 4. 使用 migrate 工具
./install.sh --with-trivy

切勿跨大版本升级(如 2.8 直接到 2.11),必须逐版本滚动升级。

总结

Harbor 解决了企业容器镜像管理的三大核心问题:安全(漏洞扫描+镜像签名)权限(项目级 RBAC+机器人账户)可靠(跨地域复制+GC 策略)

落地建议: - 小团队(<20人):单节点 Docker Compose 部署,S3 后端,够用 - 中大规模:HA 部署(多副本 Harbor Core + 外置 PostgreSQL/Redis + 共享存储) - 存储后端优先选 S3/MinIO,本地文件系统不利于扩展和备份 - Day 2 运维:监控 Harbor 组件健康(Prometheus exporter 已内置)、定期 GC、告警磁盘水位

一句话:镜像数量超过 100 个或者团队超过 5 人,就该上 Harbor 了。

您还没有登录,请登录后发表评论。