生产环境 DevOps 实战 | 第 18 天:Harbor 复制规则——跨机房/跨集群镜像同步方案

第 18/60 天

引言

当你的业务从「单机房单集群」走向「跨机房容灾、多集群部署、多云分发」时,第一个被卡住的往往是镜像同步问题:生产集群在 A 机房,灾备集群在 B 机房,镜像到底怎么过去?手动 docker pull + docker push 显然不可行,写脚本批量搬运又容易漏镜像、断流程、没审计。

Harbor 内置的复制(Replication)机制正是为此而生:它允许你定义「复制规则」,把某个项目下的镜像与 OCI 制品,按筛选条件自动同步到另一个 Harbor 实例(或任意远端 Registry),支持手动、定时、事件驱动三种触发方式,并提供完整的执行记录与审计。

本文是「三件套集成」系列的镜像分发核心篇。读完你将掌握:

  • Harbor 复制的两种模式(Push 推模式 / Pull 拉模式)与三种触发方式
  • 复制规则的筛选条件、覆盖策略、删除策略如何配置
  • 跨机房/跨集群复制拓扑的设计思路(Hub-Spoke、网状、级联)
  • 用 curl + Harbor REST API 与 Python 脚本化创建和管理复制规则
  • 结合 Kubernetes CronJob 与 Argo CD 实现复制任务的自动化与 GitOps 化管理

核心概念

1. 复制(Replication)是什么

复制是把制品从源(Source)拷贝到目标(Destination)的异步任务机制。在 Harbor 2.x 中,复制的对象不仅是容器镜像,还包括 Helm Chart、SBOM、CVE 报告等 OCI 制品。每个复制规则(Replication Policy)定义了一次复制的完整策略,实际执行时会产生一条复制执行记录(Replication Execution),内部再拆分为多个子任务(Replication Task,每个制品一个)。

2. 复制模式:Push 与 Pull

Harbor 2.x 支持两种复制方向:

模式 目标 适用场景
Push(推模式) 本地 Harbor 项目 远端 Registry(Harbor/其他) 主动向灾备机房、边缘集群、云端推送,最常用
Pull(拉模式) 远端 Registry 本地 Harbor 项目 从上游/公网仓库拉取到内网,配合代理缓存做本地化

Push 模式把本地作为权威源(Source of Truth),适合「总部 → 分支」「生产 → 灾备」;Pull 模式把远端作为源,适合「内网从外网拉取」「镜像本地化加速」。

3. 筛选条件(Filters)

复制不是无脑全量拷贝,而是通过筛选条件精确控制复制哪些制品:

  • 资源类型(Resource)imagechart 等,只复制指定类型的制品
  • 名称(Name):按仓库路径匹配(支持 ** 通配符),例如 prod/** 只复制 prod 项目下所有仓库
  • 标签(Tag):按标签正则匹配,例如只复制 v2.*release-*
  • 标签数量(Labels):只复制带指定标签的制品

配合 maxNumArtifacts 可限制单次最多复制的制品数;copyExistingArtifacts 控制是否回溯复制规则创建前已有的历史制品。

4. 覆盖与删除策略

  • 覆盖(Override):目标已存在同名同 Tag 制品时,true 覆盖为最新版本,false 跳过保留远端版本
  • 删除远端多余制品(Deletion):源上已删除的制品,是否同步删除目标上的对应制品。⚠️ 这是双刃剑——配置不当会导致灾备端被「同步删除」,慎用

5. 触发方式(Trigger)

触发类型 说明 适用场景
手动(Manual) 在 UI 或 API 手动触发一次 一次性迁移、临时同步
定时(Scheduled) 按 Cron 表达式周期执行 定期增量同步、夜间带宽低谷同步
事件驱动(Event based) 本地有制品 Push 后自动触发复制 与 Tekton CI 联动,推送即同步,最实时

6. 复制与代理缓存项目(Proxy Cache)的区别

维度 复制规则 代理缓存项目
数据流向 按规则拷贝到目标实例 请求时按需拉取并缓存
是否产生副本 是,目标有完整副本 是,但缓存在代理项目内
触发方式 手动/定时/事件 首次拉取时触发
典型场景 灾备同步、多集群分发 内网加速拉取 Docker Hub 公共镜像

实战步骤

下面以「生产机房 Harbor(源)→ 灾备机房 Harbor(目标)」为例,完整演示跨机房镜像同步的配置全过程。假设两个 Harbor 实例均已启用 HTTPS 且可通过域名互相访问。

1. 准备目标实例的机器人账号

在目标 Harbor(灾备机房)上创建专用于复制的机器人账号,授予对应项目的拉取/推送权限:

# 在目标 Harbor 上创建机器人账号(以 REST API 为例)
# 注意:机器人账号用户名格式为 robot$<project>$<name>
curl -sf -X POST https://harbor-dr.stellardata.top/api/v2.0/robots 
  -H "Authorization: Bearer $ADMIN_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{
    "name": "sync-from-prod",
    "duration": -1,
    "level": "project",
    "permissions": [{
      "kind": "project",
      "namespace": "prod-mirror",
      "access": [
        {"resource": "repository", "action": "pull"},
        {"resource": "repository", "action": "push"},
        {"resource": "artifact", "action": "read"}
      ]
    }]
  }'

执行后返回的 secret 即为该机器人的访问密码,请妥善保存——它会在步骤 2 中作为目标注册库的认证凭据。

2. 在源 Harbor 添加远端注册库(Registry)

在源 Harbor(生产机房)中,把目标 Harbor 注册为「远端注册库」:

# 添加远端注册库 endpoint
curl -sf -X POST https://harbor.stellardata.top/api/v2.0/registries 
  -H "Authorization: Bearer $PROD_ADMIN_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{
    "name": "harbor-dr",
    "type": "harbor",
    "url": "https://harbor-dr.stellardata.top",
    "description": "灾备机房 Harbor 实例",
    "credential": {
      "type": "basic",
      "access_key": "robot$prod-mirror$sync-from-prod",
      "access_secret": "SvQmxxxxxxxxxxxxxxxxxxxx"
    },
    "insecure": false
  }'

生产环境务必保持 insecure: false,并确保两端证书链互相可信任(自签证书需在 Harbor 配置中导入 CA,详见第 16 天)。

3. 创建复制规则(Push 模式 + 定时触发)

创建复制规则的核心是构造 filters(筛选)与 trigger(触发)两部分。以下规则实现:每天凌晨 2 点,把 prod 项目下所有仓库中 v2.*release-* 标签的镜像,同步到灾备 Harbor 的 prod-mirror 项目

{
  "name": "sync-prod-to-dr",
  "description": "生产镜像每日同步到灾备机房",
  "src_registry": {"id": 1},
  "dest_registry": {"id": 2},
  "dest_namespace": "prod-mirror",
  "dest_namespace_replace_count": 1,
  "filters": [
    {"type": "resource", "value": "image"},
    {"type": "name", "value": "prod/**"},
    {"type": "tag", "value": "v[0-9].*|release-.*"}
  ],
  "trigger": {
    "type": "scheduled",
    "trigger_settings": {"cron": "0 2 * * *"}
  },
  "override": true,
  "deletion": false,
  "speed": -1,
  "copy_existing_artifacts": true,
  "enabled": true
}
# 创建复制规则(POST 上面的 JSON 到 replication/policies)
curl -sf -X POST https://harbor.stellardata.top/api/v2.0/replication/policies 
  -H "Authorization: Bearer $PROD_ADMIN_TOKEN" 
  -H "Content-Type: application/json" 
  -d @/tmp/replication-policy.json

# 立即手动触发一次(验证规则可用;policy_id 为上一步返回的 Location 中提取)
curl -sf -X POST https://harbor.stellardata.top/api/v2.0/replication/executions 
  -H "Authorization: Bearer $PROD_ADMIN_TOKEN" 
  -H "Content-Type: application/json" 
  -d '{"policy_id": 3}'

# 查询执行状态(idle / running / success / failed)
curl -sf https://harbor.stellardata.top/api/v2.0/replication/executions/3 
  -H "Authorization: Bearer $PROD_ADMIN_TOKEN" | python3 -m json.tool

4. 事件驱动:与 Tekton CI 联动(推送即同步)

若希望每次 Tekton 构建完推送镜像后立即复制到灾备端,把触发方式改为事件驱动:

{
  "name": "sync-prod-to-dr-event",
  "dest_registry": {"id": 2},
  "dest_namespace": "prod-mirror",
  "filters": [
    {"type": "resource", "value": "image"},
    {"type": "name", "value": "prod/**"}
  ],
  "trigger": {
    "type": "event_based"
  },
  "override": true,
  "deletion": false,
  "enabled": true
}

事件驱动模式下,Harbor 会在本地 prod 项目收到新 Push 后自动执行复制,无需 CI 流水线显式调用复制接口——你只需要保证第 29 天实现的「Tekton 推送 → Harbor」流水线正常工作即可,复制由 Harbor 内部完成,解耦且可靠。

5. 用 Kubernetes CronJob 兜底触发复制

如果你希望复制任务在 Kubernetes 中可见、可调度、可监控(而不是依赖 Harbor 内部调度),可以部署一个 CronJob 定期调用复制 API:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: harbor-replication-trigger
  namespace: devops
spec:
  schedule: "0 2 * * *"            # 每天 02:00,避开带宽高峰
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      backoffLimit: 3
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: trigger
              image: curlimages/curl:8.5.0
              command:
                - /bin/sh
                - -c
                - >-
                  curl -sf -X POST
                  -H "Authorization: Bearer $HARBOR_TOKEN"
                  -H "Content-Type: application/json"
                  -d '{"policy_id": 3}'
                  https://harbor.stellardata.top/api/v2.0/replication/executions
              env:
                - name: HARBOR_TOKEN
                  valueFrom:
                    secretKeyRef:
                      name: harbor-token
                      key: token

用 CronJob 触发复制的好处是:复制任务的执行频率、失败重试、告警都可以纳入已有的 K8s 运维体系,与 Tekton 的 Cron 或 Argo CD 的监控栈统一管理。

6. 用 Python 脚本批量管理复制规则

当复制规则数量多(比如按团队/按项目各一条),用脚本化批量管理更高效。以下使用 harborapi 库(python-harborapi):

#!/usr/bin/env python3
"""批量创建 Harbor 复制规则示例"""
import asyncio
from harborapi import HarborAsyncClient

HARBOR_URL = "https://harbor.stellardata.top"
USERNAME = "admin"
PASSWORD = "your-password"

async def create_replication_policies(client: HarborAsyncClient) -> None:
    """为每个需要灾备同步的项目创建复制规则"""
    projects_to_sync = ["prod-order", "prod-user", "prod-payment"]
    for project in projects_to_sync:
        policy = {
            "name": f"sync-{project}-to-dr",
            "dest_registry": {"id": 2},
            "dest_namespace": f"dr-{project}",
            "filters": [
                {"type": "resource", "value": "image"},
                {"type": "name", "value": f"{project}/**"},
            ],
            "trigger": {"type": "event_based"},
            "override": True,
            "deletion": False,
            "enabled": True,
        }
        await client.create_replication_policy(policy)
        print(f"[OK] created policy for {project}")

async def main() -> None:
    async with HarborAsyncClient(HARBOR_URL, USERNAME, PASSWORD, verify=True) as client:
        await create_replication_policies(client)

if __name__ == "__main__":
    asyncio.run(main())

7. 用 Argo CD 以 GitOps 方式管理复制配置

Harbor 本身不提供 Kubernetes CRD,但我们可以把「复制规则定义(JSON)」放进 Git 仓库,用 Argo CD 的 App of Apps 或纯同步机制,配合一个同步脚本,让复制规则的变更也走「声明式 + 可回滚」的 GitOps 流程。以下是用 Argo CD Application 管理一个「Harbor 配置仓库」的示例:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: harbor-config
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://git.stellardata.top/devops/harbor-config
    path: replication
    targetRevision: main
  destination:
    server: https://kubernetes.default.svc
    namespace: devops
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
  # 仓库 replication/ 目录下存放每个复制规则的 JSON 定义,
  # 由同步钩子调用 Harbor API 应用到实例(PostSync hook)

仓库结构建议:replication/ 放 JSON 规则定义,hooks/ 放同步脚本(kustomize 的 configMapGenerator 或 PreSync/PostSync Hook)。这样复制规则的任何变更都经过代码评审、可审计、可回滚——与整个系列倡导的 GitOps 理念一致。

常见问题

Q1:复制任务一直 Pending 或 Failed,错误提示 401/证书错误,怎么办?
先分三块排查:① 目标注册库的凭据(机器人账号的 access_key 必须带 robot$ 前缀,secret 正确);② TLS 证书——两端 Harbor 若用自签证书,必须在 registries 配置中把对方 CA 加入信任(或临时 insecure: true 仅用于排查,生产务必关闭);③ 网络连通性——在两个 Harbor 之间用 curl -k https://目标域名/api/v2.0/health 双向验证。

Q2:Push 模式和 Pull 模式怎么选?
以「谁是真源」判断:生产机房的镜像要分发到灾备,用 Push(源在生产 Harbor);内网要从公网仓库拉镜像本地化,用 Pull(源是 Docker Hub/GCR)。Push 模式对远端无写入权限要求更低、更可控;Pull 模式适合「远端不可写」的公有仓库。

Q3:跨机房带宽有限,复制很慢怎么办?
三个手段:① 用定时触发把复制放到夜间带宽低谷(如 0 2 * * *);② 用筛选条件(tag 正则、maxNumArtifacts)只复制需要的制品,避免全量;③ speed 字段设置限速(单位 KB/s,-1 不限速),配合 copy_existing_artifacts: false 避免首次全量回灌。必要时升级为「增量」思路——只同步最新 tag,历史 tag 按需补。

Q4:事件驱动和定时触发哪个好,会不会重复复制?
事件驱动实时性好(Push 即同步),适合对 RTO 要求高的灾备;定时触发带宽可控、适合批量增量。两者不冲突,可同时存在(不同规则)。Harbor 内部对同一规则、同一制品有幂等处理,不会因为重复触发而产生重复副本——但要注意别把两条规则配成「互相同步」造成复制风暴,复制规则之间要保证拓扑无环。

Q5:复制会把源上的删除操作同步过去吗?会不会误删灾备镜像?
这取决于规则里的 deletion 字段:true 会同步删除目标上「源已不存在」的制品;false(默认)则只增不改、不删。生产灾备场景强烈建议 deletion: false,避免源端某次误删把灾备副本也抹掉——「灾备副本」的价值恰恰在于它是源异常时最后的兜底。

Q6:复制和代理缓存项目(Proxy Cache)有什么区别,什么时候用哪个?
复制是「主动、全量/按规则」拷贝副本到目标,适合灾备与多集群分发;代理缓存是「按需拉取 + 本地缓存」,适合内网加速拉取公共镜像(Docker Hub 等)。内网优先用代理缓存项目加速,跨机房灾备用复制规则——两者可以并存。

总结

  1. 复制三要素:源/目标注册库 + 筛选条件(resource/name/tag)+ 触发方式(手动/定时/事件),理解这三块就能配出 90% 的生产复制场景。
  2. 模式看真源:主动分发用 Push,内网拉取用 Pull;灾备同步务必 deletion: false,保护灾备副本不被连带误删。
  3. 触发方式分场景:生产→灾备对实时性要求高用事件驱动;跨机房带宽受限用定时 + 限速;需要纳入 K8s 运维体系可用 CronJob 兜底触发。
  4. 脚本化 + GitOps 化:用 curl/Harbor REST API 或 harborapi Python 库批量管理复制规则,再把规则定义放进 Git 仓库用 Argo CD 统一管理,实现声明式、可审计、可回滚的复制配置。

下期预告:第 19 天将讲解 Harbor 镜像清理与存储策略——回收日程(GC)与镜像保留策略如何配置,让仓库存储不再无限膨胀。欢迎持续关注「生产环境的 Tekton + Argo CD + Harbor 方案实现」系列!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容