Harbor 迁移指南:从 2.6.4 升级到 2.12
迁移说明
本指南介绍如何将 Harbor 从版本 2.6.4 升级到版本 2.12。鉴于版本跨度较大且升级稳定性考虑,我们采用数据迁移的方式进行升级。该方式的优势包括:
- 避免多版本中间升级的复杂性
- 复用 registry 存储数据,加快升级速度
整体迁移流程如下:
- 将 Helm Chart 数据迁移到 registry 存储。
- 备份 PostgreSQL 数据库并恢复到 PostgreSQL 14 实例。
- 停止旧的 Harbor 实例。
- 使用恢复后的 PostgreSQL 数据库和旧 Harbor 实例的原始 registry 存储部署新的 Harbor 实例。
迁移 Helm Chart 数据
Harbor 支持两种不同方式存储 Helm Chart 数据:
- 通过 OCI API 直接存储在 Harbor registry 存储中。
- 通过 Chartmuseum 的 API 存储在 Harbor 托管的 Chartmuseum 后端。
从 Harbor 2.6 开始,Chartmuseum 已被废弃,并在 Harbor 2.8 中移除。因此,如果旧实例使用的是 Chartmuseum,需要将 Chart 数据迁移到 registry 存储。
需求
迁移 Helm Chart 数据
该工具会复制 Helm Chart,但不会从 Chartmuseum 中删除它们。
将 Chart 数据迁移到 registry 存储:
export HARBOR_URL=<harbor url>
export HARBOR_USER=<harbor username>
export HARBOR_PASSWORD=<harbor password>
# 如果 Harbor 是 http,添加 -plain-http
# 如果 Harbor 是自签名 https,添加 -insecure
# 更多参数请运行 `podman run -ti --rm alaudadockerhub/chartmuseum2oci:v1.1.0-g41baf1e --help`
podman run -ti --rm alaudadockerhub/chartmuseum2oci:v1.1.0-g41baf1e --url $HARBOR_URL --username $HARBOR_USER --password $HARBOR_PASSWORD
预期输出:
2023/06/28 16:17:32 416 Helm charts to migrate from Chartmuseum to OCI
100% |████████████████████████████████████████████████████████████████████████████████████████████| (416/416, 20 it/min)
2023/06/28 16:38:14 416 Helm charts successfully migrated from Chartmuseum to OCI
如果只想迁移部分数据到 registry 存储,可以根据文档按项目过滤数据。
关于如何使用 OCI Helm Chart,请参考以下文档:
INFO
自 Harbor 2.8 起不再支持 Chartmuseum,相关支持已停止。
如果仍需使用 Chartmuseum 管理的 Chart 仓库,请联系我们获取支持。
迁移时长
迁移过程主要涉及数据库备份与恢复,迁移时间与数据库大小成正比,而非容器镜像占用的 Registry 存储空间大小。
基于对 7.6GB 数据库的测试,迁移通常耗时约 18 分钟(使用读 IOPS 6000、写 IOPS 2000 的存储性能)。
备份
执行以下命令,使用 pg_dump 备份旧实例的 pg 数据库:
export INSTANCE_NAME=<harbor instance name> INSTANCE_NAMESPACE=<harbor instance namespace>
kubectl -n ${INSTANCE_NAMESPACE} exec -it ${INSTANCE_NAME}-database-0 -- bash
# 执行备份命令
pg_dump -U postgres -d registry > /tmp/harbor_database.dump
# 将备份文件复制到本地
kubectl -n ${INSTANCE_NAMESPACE} cp ${INSTANCE_NAME}-database-0:/tmp/harbor_database.dump ./harbor_database.dump
Registry 数据备份为可选项
Registry 数据通常非常庞大,备份需要额外存储空间且耗时较长,难以实施。此外,Harbor 实例升级通常不会改变 registry 存储结构,因此新实例可直接使用旧实例的存储。
数据库迁移
从 Harbor 2.6 升级到 2.12 时,数据库版本也发生变化,由 PostgreSQL 12 升级到 PostgreSQL 14。因此,需要先将旧实例的数据库备份导入到新数据库(PostgreSQL 14)中,然后使用 Harbor 提供的数据迁移工具,将数据库结构和数据迁移为兼容 Harbor 2.12 的结构。
需求
准备一个运行 PostgreSQL 14 版本的新实例。将 Harbor 数据库备份恢复到该实例后,执行数据库结构迁移。
恢复数据库
将备份的数据库导入到新实例使用的数据库中。以下示例使用 psql 演示导入过程,具体导入方式请参考数据库厂商文档。
# 为新 PostgreSQL 实例创建新数据库。
# 示例中数据库名为 `registry`。
dropdb -U postgres registry
createdb -U postgres registry
# 旧实例使用 harbor 用户连接数据库,
# 但该用户可能在新实例数据库中不存在,
# 需将用户改为新 PostgreSQL 实例中存在的用户。
# 示例中使用 `postgres` 用户。
sed -i 's/OWNER TO harbor/OWNER TO postgres/g' /tmp/harbor_database.dump
psql -U postgres -d registry -f /tmp/harbor_database.dump
NOTE
由于数据库版本不一致,导入过程中可能出现关于不存在角色或函数的错误,可忽略。例如:
ERROR: role "admin" does not exist
ERROR: function metric_helpers.pg_stat_statements(boolean) does not exist
ERROR: schema "metric_helpers" already exists
ERROR: function "get_btree_bloat_approx" already exists with same argument types
数据库迁移
Harbor 2.6 的数据已导入新实例数据库。接下来,运行数据迁移任务,将数据库结构和数据迁移为兼容 Harbor 2.12 的结构。
设置新 PostgreSQL 实例信息,然后创建 Job 执行数据库迁移:
export POSTGRESQL_HOST=<database host>
export POSTGRESQL_PORT=<database port>
export POSTGRESQL_USERNAME=<database username>
export POSTGRESQL_PASSWORD=<database password>
# 如果旧实例使用 SSL,设置 SSL 模式为 `require`,否则设置为 `disable`。
export POSTGRESQL_SSLMODE="require"
export INSTANCE_NAMESPACE=<harbor instance namespace>
# 官方 migrator 镜像地址为 `https://hub.docker.com/r/mgle/standalone-db-migrator`,
# 可导入私有仓库并设置 MIGRATOR_IMAGE 环境变量使用。
export MIGRATOR_IMAGE=hub-mirrors.alauda.cn/mgle/standalone-db-migrator:v2.12.0
kubectl -n ${INSTANCE_NAMESPACE} apply -f - << EOF
apiVersion: batch/v1
kind: Job
metadata:
name: harbor-db-migrate
spec:
backoffLimit: 5
template:
spec:
restartPolicy: Never
containers:
- name: harbor-migrate
image: ${MIGRATOR_IMAGE}
command: ["/harbor/migrate"]
env:
- name: POSTGRESQL_HOST
value: "${POSTGRESQL_HOST}"
- name: POSTGRESQL_PORT
value: "${POSTGRESQL_PORT}"
- name: POSTGRESQL_USERNAME
value: "${POSTGRESQL_USERNAME}"
- name: POSTGRESQL_PASSWORD
value: "${POSTGRESQL_PASSWORD}"
- name: POSTGRESQL_DATABASE
value: "registry"
- name: POSTGRESQL_SSLMODE
value: "${POSTGRESQL_SSLMODE}"
EOF
任务完成后,可在 Job 日志中查看详细迁移进度和结果:
2024-12-23T02:43:05Z [INFO] [/cmd/standalone-db-migrator/main.go:53]: Migrating the data to latest schema...
2024-12-23T02:43:05Z [INFO] [/cmd/standalone-db-migrator/main.go:54]: DB info: postgres://harbor@test-6-database:5432/registry?sslmode=require
2024-12-23T02:43:05Z [INFO] [/common/dao/base.go:67]: Registering database: type-PostgreSQL host-test-6-database port-5432 database-registry sslmode-"require"
2024-12-23T02:43:05Z [INFO] [/common/dao/base.go:72]: Register database completed
2024-12-23T02:43:05Z [INFO] [/common/dao/pgsql.go:135]: Upgrading schema for pgsql ...
2024-12-23T02:43:05Z [INFO] [/go/pkg/mod/github.com/golang-migrate/migrate/v4@v4.18.1/migrate.go:765]: 100/u 2.7.0_schema (184.508549ms)
2024-12-23T02:43:05Z [INFO] [/go/pkg/mod/github.com/golang-migrate/migrate/v4@v4.18.1/migrate.go:765]: 110/u 2.8.0_schema (275.019668ms)
2024-12-23T02:43:05Z [INFO] [/go/pkg/mod/github.com/golang-migrate/migrate/v4@v4.18.1/migrate.go:765]: 111/u 2.8.1_schema (286.508359ms)
2024-12-23T02:43:05Z [INFO] [/go/pkg/mod/github.com/golang-migrate/migrate/v4@v4.18.1/migrate.go:765]: 120/u 2.9.0_schema (357.027979ms)
2024-12-23T02:43:05Z [INFO] [/go/pkg/mod/github.com/golang-migrate/migrate/v4@v4.18.1/migrate.go:765]: 130/u 2.10.0_schema (378.349099ms)
2024-12-23T02:43:05Z [INFO] [/go/pkg/mod/github.com/golang-migrate/migrate/v4@v4.18.1/migrate.go:765]: 140/u 2.11.0_schema (399.407785ms)
2024-12-23T02:43:05Z [INFO] [/go/pkg/mod/github.com/golang-migrate/migrate/v4@v4.18.1/migrate.go:765]: 150/u 2.12.0_schema (408.831695ms)
2024-12-23T02:43:05Z [INFO] [/cmd/standalone-db-migrator/main.go:63]: Migration done. The data schema in DB is now update to date.
停止旧 Harbor 实例
从 Operator Hub 页面卸载 harbor operator,然后执行以下命令缩容旧 Harbor 实例:
export INSTANCE_NAME=<harbor instance name> INSTANCE_NAMESPACE=<harbor instance namespace>
kubectl -n ${INSTANCE_NAMESPACE} scale deployment -l release=${INSTANCE_NAME} --replicas=0
kubectl -n ${INSTANCE_NAMESPACE} scale statefulset -l release=${INSTANCE_NAME} --replicas=0
kubectl -n ${INSTANCE_NAMESPACE} delete service -l release=${INSTANCE_NAME}
kubectl -n ${INSTANCE_NAMESPACE} delete ingress -l release=${INSTANCE_NAME}
部署新 Harbor 实例
TIP
新实例需要挂载原实例的存储,因此需与原实例处于同一命名空间。
请根据部署文档部署新实例,注意以下几点:
- 新实例需连接迁移后的 PostgreSQL 数据库(PostgreSQL 14)
- 不要复用旧 Harbor 实例的 Redis,需新建 Redis 实例
- registry 存储需使用旧实例的存储
- 访问方式需与旧实例保持一致,避免迁移完成后影响业务使用
以下章节介绍旧实例与新实例的配置迁移。
获取原实例配置
获取原实例配置并转换为新实例配置,命令如下:
export INSTANCE_NAME=<harbor instance name> INSTANCE_NAMESPACE=<harbor instance namespace>
helm -n ${INSTANCE_NAMESPACE} get values ${INSTANCE_NAME}
转换 Registry 存储配置
如果原实例使用 Host Path 存储部署,配置如下:
# 原实例配置
persistence:
hostPath:
registry:
host:
nodeName: <node name>
path: <registry storage path>
迁移为新实例配置:
# 新实例配置
helmValues:
persistence:
enabled: true
hostPath:
registry:
path: <registry storage path>
registry:
nodeSelector:
kubernetes.io/hostname: <node name>
如果原实例使用存储类部署,PVC 名称固定:
- registry PVC 名称:
<旧实例名>-harbor-registry
新实例使用旧 PVC。
# 新实例配置
helmValues:
persistence:
enabled: true
persistentVolumeClaim:
registry:
existingClaim: <旧实例名>-harbor-registry
如果原实例使用 PVC 部署,配置如下:
# 原实例配置
persistence:
persistentVolumeClaim:
registry:
existingClaim: <registry pvc 名称>
新实例配置:
# 新实例配置
helmValues:
persistence:
enabled: true
persistentVolumeClaim:
registry:
existingClaim: <registry pvc 名称>
转换访问方式配置
如果原实例使用 NodePort 部署,设置如下配置:
# 新实例配置
helmValues:
expose:
type: nodePort
nodePort:
name: harbor
ports:
http:
port: 80
nodePort: <node port 端口号>
externalURL: http://<node port IP>:<node port 端口号>
如果原实例使用域名部署,设置如下配置:
# 新实例 http 配置
helmValues:
expose:
type: ingress
tls:
enabled: false
ingress:
hosts:
core: <域名>
externalURL: http://<域名>
# 新实例 https 配置
helmValues:
expose:
type: ingress
tls:
enabled: true
certSource: "secret"
secret:
secretName: <tls 证书 secret>
ingress:
hosts:
core: <域名>
externalURL: https://<域名>
验证
-
检查所有 Pod 状态:
export INSTANCE_NAME=<harbor instance name> INSTANCE_NAMESPACE=<harbor instance namespace>
kubectl get pods -n ${INSTANCE_NAMESPACE} -l release=${INSTANCE_NAME}
-
验证 Harbor 服务可访问:
- 访问 Harbor Web UI,确认已有项目和镜像可见
- 测试 Podman 登录
-
测试镜像/Chart 的推送与拉取:
- 测试镜像推送与拉取
- 测试 OCI Chart 推送与拉取(可选)
-
确认迁移成功后,可在 DevOps Toolchain/Instances/ 页面手动删除旧 Harbor 实例。