第 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):
image、chart等,只复制指定类型的制品 - 名称(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 等)。内网优先用代理缓存项目加速,跨机房灾备用复制规则——两者可以并存。
总结
- 复制三要素:源/目标注册库 + 筛选条件(resource/name/tag)+ 触发方式(手动/定时/事件),理解这三块就能配出 90% 的生产复制场景。
- 模式看真源:主动分发用 Push,内网拉取用 Pull;灾备同步务必
deletion: false,保护灾备副本不被连带误删。 - 触发方式分场景:生产→灾备对实时性要求高用事件驱动;跨机房带宽受限用定时 + 限速;需要纳入 K8s 运维体系可用 CronJob 兜底触发。
- 脚本化 + GitOps 化:用 curl/Harbor REST API 或
harborapiPython 库批量管理复制规则,再把规则定义放进 Git 仓库用 Argo CD 统一管理,实现声明式、可审计、可回滚的复制配置。
下期预告:第 19 天将讲解 Harbor 镜像清理与存储策略——回收日程(GC)与镜像保留策略如何配置,让仓库存储不再无限膨胀。欢迎持续关注「生产环境的 Tekton + Argo CD + Harbor 方案实现」系列!















暂无评论内容