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 字段为 trueconnection 字段不为空,表示该实例已配置对象存储。

术语

术语定义
Source Instance备份前的 GitLab 实例
Target Instance恢复后的 GitLab 实例
Source Namespace源实例所在的命名空间
Target Namespace目标实例所在的命名空间
GitLab CR Resource描述 GitLab 实例部署配置的 CR 资源,由 Operator 用于部署 GitLab 实例

前置条件

  1. 部署 MinIO 对象存储:官方备份与恢复方案依赖对象存储保存备份数据,需要预先部署 MinIO 实例。ACP 提供了 快速创建 MinIO 实例
  2. 安装 mc 命令行工具:mc 是 MinIO 的命令行工具,用于管理 MinIO 实例。安装说明请参考 MinIO 官方文档
  3. 安装 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:

  1. 存储备份数据的 Bucket,名称为:gitlab-backups
  2. 备份过程中存储临时数据的 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 等)

示例:

  1. 每天凌晨 3 点执行:0 3 * * *
  2. 每月 1 号和 15 号凌晨 3 点执行:0 3 1,15 * *
  3. 每 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 实例恢复方式

恢复有两种选择:

  1. 直接在源实例上恢复,会用备份数据覆盖实例数据
  2. (推荐)部署新实例恢复数据,新实例需满足以下要求:
    1. 新实例必须启用对象存储
    2. 新实例应部署 toolbox 组件,并配置与源实例相同的对象存储配置

恢复操作

WARNING

以下操作均在目标实例上执行。

请先设置以下环境变量:

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 检查数据是否恢复成功。检查项包括但不限于:

  • 仓库
  • 用户
  • 合并请求