GitLab 官方备份与恢复
本方案基于 GitLab 官方备份与恢复方案。详细信息请参考 GitLab 官方文档。
目录
适用范围
本方案仅适用于运行 17.8 版本及以上 且已配置 对象存储 的 GitLab 实例。
如果您的 GitLab 实例尚未配置对象存储,GitLab 提供了 数据迁移方案,您可以参考该方案先完成数据迁移,再使用本方案进行备份与恢复。
如何检查是否配置了对象存储
export GITLAB_NAMESPACE=<待备份 GitLab 实例所在命名空间>
export GITLAB_NAME=<待备份 GitLab 实例名称>
kubectl get gitlabofficial ${GITLAB_NAME} -n ${GITLAB_NAMESPACE} -o jsonpath='{.spec.helmValues.global.appConfig.object_store}'
# 输出示例:
# {"connection":{"key":"connection","secret":"gitlab-rails-storage"},"enabled":true}
当 enabled
字段为 true
且 connection
字段不为空时,表示该实例已配置对象存储。
术语说明
术语 | 定义 |
---|
源实例 | 备份前的 GitLab 实例 |
目标实例 | 恢复后的 GitLab 实例 |
源命名空间 | 源实例所在的命名空间 |
目标命名空间 | 目标实例所在的命名空间 |
GitLab CR 资源 | 描述 GitLab 实例部署配置的自定义资源,由 Operator 用于部署 GitLab 实例 |
前提条件
- 部署 MinIO 对象存储:官方备份与恢复方案依赖对象存储保存备份数据,需预先部署 MinIO 实例。ACP 提供了 。
- 安装 mc 命令行工具:mc 是 MinIO 的命令行工具,用于管理 MinIO 实例。安装方法请参考 MinIO 官方文档。
- 安装 kubectl 命令行工具:kubectl 是 Kubernetes 的命令行工具,用于管理 Kubernetes 集群。安装方法请参考 Kubernetes 官方文档。
为方便后续操作,请先设置以下环境变量:
export MINIO_HOST=<MinIO 实例访问地址> # 示例:http://192.168.1.100:32008
export MINIO_ACCESS_KEY=<MinIO 实例访问密钥> # 示例:minioadmin
export MINIO_SECRET_KEY=<MinIO 实例访问密钥密码> # 示例:minioadminpassword
export MINIO_ALIAS_NAME=<MinIO 实例别名> # 示例:myminio
export GITLAB_NAMESPACE=<待备份 GitLab 实例所在命名空间>
export GITLAB_NAME=<待备份 GitLab 实例名称>
执行以下命令配置 mc 命令行工具并测试连接:
mc alias set ${MINIO_ALIAS_NAME} ${MINIO_HOST} ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY}
mc ping ${MINIO_ALIAS_NAME}
# 输出示例:
# 1: http://192.168.131.56:32571:32571 min=98.86ms max=98.86ms average=98.86ms errors=0 roundtrip=98.86ms
# 2: http://192.168.131.56:32571:32571 min=29.57ms max=98.86ms average=64.21ms errors=0 roundtrip=29.57ms
# 3: http://192.168.131.56:32571:32571 min=29.57ms max=98.86ms average=52.77ms errors=0 roundtrip=29.88ms
若能成功 ping 通 MinIO 实例,说明 mc 配置正确。
备份
前置准备
创建 Bucket
需创建两个 Bucket:
- 用于存储备份数据的 Bucket,命名为:
gitlab-backups
- 用于备份过程临时数据的 Bucket,命名为:
gitlab-backups-tmp
执行以下命令创建 Bucket:
mc mb ${MINIO_ALIAS_NAME}/gitlab-backups
mc mb ${MINIO_ALIAS_NAME}/gitlab-backups-tmp
# 输出示例:
# Bucket created successfully `myminio/gitlab-backups`.
# Bucket created successfully `myminio/gitlab-backups-tmp`.
执行以下命令验证 Bucket 是否创建成功:
mc ls ${MINIO_ALIAS_NAME} | grep gitlab-backups
# 输出示例:
# [2025-06-30 11:58:09 CST] 0B gitlab-backups/
# [2025-06-30 11:58:13 CST] 0B gitlab-backups-tmp/
手动备份
部署 Toolbox 组件
执行官方 GitLab 备份需在 toolbox pod
内运行备份命令,备份文件会上传至对象存储,因此需提前准备对象存储配置文件。运行以下脚本生成所需配置文件:
set -e
if [[ -z "${GITLAB_NAMESPACE}" ]]; then
echo "GITLAB_NAMESPACE 未设置,请先设置后重试"
exit 1
fi
CLEAN_HOST=${MINIO_HOST#http://}
CLEAN_HOST=${CLEAN_HOST#https://}
use_https="False"
if [[ $MINIO_HOST == https://* ]]; then
use_https="True"
fi
CONFIG_DATA=$(cat << EOF
[default]
host_base = ${CLEAN_HOST}
host_bucket = ${CLEAN_HOST}/%(bucket)
access_key = ${MINIO_ACCESS_KEY}
secret_key = ${MINIO_SECRET_KEY}
bucket_location = us-east-1
use_https = ${use_https}
EOF
)
kubectl create secret generic s3cfg \
-n ${GITLAB_NAMESPACE} \
--from-literal=config="$CONFIG_DATA"
# 输出示例:
# secret/s3cfg created
在 GitLab 所在集群执行以下命令编辑 GitLab 实例 CR:
kubectl edit gitlabofficial ${GITLAB_NAME} -n ${GITLAB_NAMESPACE}
根据注释先编辑以下 yaml 配置,然后添加到 CR 中:
spec:
helmValues:
global:
appConfig:
backups:
# 这两个 Bucket 名称必须与前面创建的 Bucket 名称一致
bucket: gitlab-backups
tmpBucket: gitlab-backups-tmp
gitlab:
toolbox:
backups:
objectStorage:
config:
key: config
# 上一步创建的 Secret 名称
secret: s3cfg
enabled: true
persistence:
accessMode: ReadWriteMany
enabled: true
# 备份需要在本地打包所有文件,因此需要足够空间
# PVC 容量根据实例已用磁盘空间确定
size: 10Gi
# 存储类名称
storageClass: nfs
更新 GitLab CR 后,会自动部署新的 toolbox 组件。使用以下命令检查 toolbox 组件是否部署成功:
kubectl get pod -n ${GITLAB_NAMESPACE} | grep toolbox
# 输出示例:
# xx-gitlab-toolbox-6f578f6b-f7wlw 1/1 Running 0 4h11m
若 Pod 状态为 Running
,表示 toolbox 组件部署成功。
执行备份
使用以下命令进入 toolbox pod 终端环境:
export TOOLBOX_POD_NAME=$(kubectl get pod -n ${GITLAB_NAMESPACE} | grep ${GITLAB_NAME}-toolbox | awk '{print $1}')
kubectl exec -it ${TOOLBOX_POD_NAME} -n ${GITLAB_NAMESPACE} -- bash
执行备份:
cd ~/; nohup backup-utility > output.log 2>&1 &
备份过程需要一定时间,使用以下命令查看备份日志以确认备份进度:
cd ~/; tail -f output.log
# 输出示例:
# Bucket not found: gitlab-packages. Skipping backup of packages ...
# Bucket not found: gitlab-mr-diffs. Skipping backup of external_diffs ...
# Bucket not found: gitlab-terraform-state. Skipping backup of terraform_state ...
# Bucket not found: gitlab-pages. Skipping backup of pages ...
# Bucket not found: gitlab-ci-secure-files. Skipping backup of ci_secure_files ...
# Packing up backup tar
# WARNING: Module python-magic is not available. Guessing MIME types based on file extensions.
# [DONE] Backup can be found at s3://gitlab-backups/1751272314_2025_06_30_17.11.4_gitlab_backup.tar
程序成功完成后,备份结束。
备份 ID
备份文件名根据备份时间和版本信息动态生成,例如 1751272314_2025_06_30_17.11.4_gitlab_backup.tar
,其中 1751272314_2025_06_30_17.11.4
是该备份的唯一标识(备份 ID)。执行恢复操作时需提供对应的备份 ID。
定时备份
GitLab 定时备份通过 toolbox 组件完成。与手动备份不同,定时备份使用 Crontab 实现周期性备份。
在 GitLab 所在集群执行以下命令编辑 GitLab 实例 CR:
kubectl edit gitlabofficial ${GITLAB_NAME} -n ${GITLAB_NAMESPACE}
根据注释先编辑以下 yaml 配置,然后添加到 CR 中:
spec:
helmValues:
global:
appConfig:
backups:
# 这两个 Bucket 名称必须与前面创建的 Bucket 名称一致
bucket: gitlab-backups
tmpBucket: gitlab-backups-tmp
gitlab:
toolbox:
enabled: true
backups:
cron:
enabled: true
# 配置备份周期
schedule: "0 1 * * *"
persistence:
enabled: true
accessMode: ReadWriteMany
# 备份需要在 toolbox pod 内打包所有文件,因此需要足够空间
# PVC 容量根据实例已用磁盘空间确定
size: 10Gi
# 存储类名称
storageClass: nfs
objectStorage:
config:
key: config
# 上一步创建的 Secret 名称
secret: s3cfg
如何配置备份周期
Crontab 规则由五个时间字段组成,字段间以空格分隔,从左至右依次为:
- 分钟(Minute):任务执行的分钟,范围 0-59
- 小时(Hour):任务执行的小时,范围 0-23
- 日期(Day of the month):任务执行的日期,范围 1-31
- 月份(Month):任务执行的月份,范围 1-12(也可使用缩写,如 Jan、Feb、Mar 等)
- 星期(Day of the week):任务执行的星期几,范围 0-7(0 和 7 均代表星期日,1 代表星期一,依此类推。也可使用缩写,如 Sun、Mon、Tue 等)
示例:
- 每天凌晨 3 点执行:
0 3 * * *
- 每月 1 日和 15 日凌晨 3 点执行:
0 3 1,15 * *
- 每 10 分钟执行一次:
*/10 * * * *
等待 GitLab 触发备份后,可进行备份文件验证。
验证备份文件
执行以下命令检查备份文件是否已上传至对象存储:
mc ls ${MINIO_ALIAS_NAME}/gitlab-backups
# 输出示例:
# [2025-06-30 16:33:18 CST] 570KiB STANDARD 1751272314_2025_06_30_17.8.5_gitlab_backup.tar
# [2025-06-30 18:19:26 CST] 570KiB STANDARD 1751278684_2025_06_30_17.8.5_gitlab_backup.tar
若能成功列出备份文件,说明备份成功。
恢复
前置准备
选择恢复的备份
使用 mc 命令获取备份文件列表:
mc ls ${MINIO_ALIAS_NAME}/gitlab-backups
# 输出示例:
# [2025-06-30 16:33:18 CST] 570KiB STANDARD 1751272314_2025_06_30_17.8.5_gitlab_backup.tar
# [2025-06-30 18:19:26 CST] 570KiB STANDARD 1751278684_2025_06_30_17.8.5_gitlab_backup.tar
根据备份文件名中的日期信息,选择需要恢复的备份,并从备份文件名中复制备份 ID,格式如 1751272314_2025_06_30_17.11.4
。
确定 GitLab 实例恢复方式
恢复有两种选择:
- 直接在源实例上恢复,会用备份数据覆盖实例数据
- (推荐)部署新实例进行恢复,新实例需满足以下条件:
- 新实例必须启用对象存储
- 新实例应部署 toolbox 组件,并配置与源实例相同的对象存储配置
恢复操作
请先设置以下环境变量:
export NEW_GITLAB_NAMESPACE=<新 GitLab 实例所在命名空间>
export NEW_GITLAB_NAME=<新 GitLab 实例名称>
停止工作负载
为保证恢复顺利进行,恢复期间需停止 sidekiq 和 webservice 组件。
kubectl annotate deployment -n ${NEW_GITLAB_NAMESPACE} -l release=${NEW_GITLAB_NAME},app=sidekiq skip-sync="true"
kubectl scale deployment -n ${NEW_GITLAB_NAMESPACE} -l release=${NEW_GITLAB_NAME},app=sidekiq --replicas=0
kubectl annotate deployment -n ${NEW_GITLAB_NAMESPACE} -l release=${NEW_GITLAB_NAME},app=webservice skip-sync="true"
kubectl scale deployment -n ${NEW_GITLAB_NAMESPACE} -l release=${NEW_GITLAB_NAME},app=webservice --replicas=0
# 输出示例:
# deployment.apps/xx-gitlab-sidekiq-all-in-1-v2 annotated
# deployment.apps/xx-gitlab-sidekiq-all-in-1-v2 scaled
# deployment.apps/xx-gitlab-webservice-default annotated
# deployment.apps/xx-gitlab-webservice-default scaled
执行恢复
使用以下命令进入 toolbox pod 终端:
export NEW_TOOLBOX_POD_NAME=$(kubectl get pod -n ${NEW_GITLAB_NAMESPACE} | grep ${NEW_GITLAB_NAME}-toolbox | awk '{print $1}')
kubectl exec -it ${NEW_TOOLBOX_POD_NAME} -n ${NEW_GITLAB_NAMESPACE} -- bash
DANGER
恢复数据库前会删除所有现有表,以避免后续升级问题。请注意,如果 GitLab 数据库中有自定义表,这些表及其所有数据将被删除。
在终端执行以下命令进行恢复,backup ID 替换为所需的备份 ID,如 1751272314_2025_06_30_17.11.4
:
export BACKUP_ID=<backup ID>
rm -rf /srv/gitlab/tmp/*
backup-utility --restore -t ${BACKUP_ID}
# 输出示例:
# 2025-06-30 15:33:53 UTC -- [DONE]
# 2025-06-30 15:33:53 UTC -- Source backup for the database ci doesn't exist. Skipping the task
# 2025-06-30 15:33:53 UTC -- Restoring database ... done
# 2025-06-30 15:33:53 UTC -- Deleting backup and restore PID file at [/srv/gitlab/tmp/backup_restore.pid] ... done
# 2025-06-30 15:34:12 UTC -- Restoring repositories ...
# 2025-06-30 15:34:12 UTC -- Restoring repositories ... done
# 2025-06-30 15:34:12 UTC -- Deleting backup and restore PID file at [/srv/gitlab/tmp/backup_restore.pid] ... done
程序成功完成后,恢复结束。
新实例恢复注意事项
若在新部署实例上恢复,完成上述步骤后,还需执行以下操作:
恢复 Rails Secrets
需将新实例的 Rails secrets 更新为与源实例一致。
从源实例获取 Rails secrets 内容:
kubectl get secret ${GITLAB_NAME}-rails-secret -n ${GITLAB_NAMESPACE} -o jsonpath='{.data.secrets\.yml}' | base64 --decode
更新新实例的 Rails secrets,具体操作请参考 如何设置 Rails Secrets。
切换域名
若源实例使用域名部署,恢复到新实例后需将新实例的域名切换为源实例的域名,以恢复业务访问。请参考 配置实例网络访问 修改实例访问域名。
恢复工作负载
恢复期间停止的 sidekiq 和 webservice 组件需在恢复完成后重启:
kubectl annotate deployment -n ${NEW_GITLAB_NAMESPACE} -l release=${NEW_GITLAB_NAME},app=sidekiq skip-sync-
kubectl scale deployment -n ${NEW_GITLAB_NAMESPACE} -l release=${NEW_GITLAB_NAME},app=sidekiq --replicas=1
kubectl annotate deployment -n ${NEW_GITLAB_NAMESPACE} -l release=${NEW_GITLAB_NAME},app=webservice skip-sync-
kubectl scale deployment -n ${NEW_GITLAB_NAMESPACE} -l release=${NEW_GITLAB_NAME},app=webservice --replicas=1
# 输出示例:
# deployment.apps/xx-gitlab-sidekiq-all-in-1-v2 annotated
# deployment.apps/xx-gitlab-sidekiq-all-in-1-v2 scaled
# deployment.apps/xx-gitlab-webservice-default annotated
# deployment.apps/xx-gitlab-webservice-default scaled
验证恢复
等待实例状态恢复正常后,登录 GitLab 检查数据是否恢复成功。检查项包括但不限于: