GitLab 官方备份与恢复

此解决方案基于 GitLab 官方的备份与恢复方案。有关详细信息,请参阅 GitLab 官方文档。

适用范围

此解决方案仅适用于运行 17.8 或更高版本且已配置对象存储的 GitLab 实例。

如果您的 GitLab 实例尚未配置对象存储,GitLab 提供了数据迁移方案。您可以先参考此方案迁移数据,然后使用此方案进行备份和恢复。

如何检查是否已配置对象存储
export GITLAB_NAMESPACE=<namespace of the GitLab instance to be backed up>
export GITLAB_NAME=<name of the GitLab instance to be backed up>

kubectl get gitlabofficial ${GITLAB_NAME} -n ${GITLAB_NAMESPACE} -o jsonpath='{.spec.helmValues.global.appConfig.object_store}'

# Output:
# {"connection":{"key":"connection","secret":"gitlab-rails-storage"},"enabled":true}

如果 enabled 字段为 true,且 connection 字段不为空,则表示该实例已配置对象存储。

术语

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

前提条件

  1. 部署 MinIO 对象存储:官方备份与恢复方案依赖对象存储来保存备份数据,因此需要预先部署 MinIO 实例。ACP 提供 MinIO Object Storage,用于快速创建 MinIO 实例。
  2. 安装 mc 命令行工具:mc 是 MinIO 用于管理 MinIO 实例的命令行工具。有关安装说明,请参阅 MinIO 官方文档。
  3. 安装 kubectl 命令行工具:kubectl 是 Kubernetes 用于管理 Kubernetes 集群的命令行工具。有关安装说明,请参阅 Kubernetes 官方文档。

为便于后续操作,请先设置环境变量:

export MINIO_HOST=<MinIO instance access address> # Example: http://192.168.1.100:32008
export MINIO_ACCESS_KEY=<MinIO instance access key> # Example: minioadmin
export MINIO_SECRET_KEY=<MinIO instance secret key> # Example: minioadminpassword
export MINIO_ALIAS_NAME=<MinIO instance alias name> # Example: myminio

export GITLAB_NAMESPACE=<namespace of the GitLab instance to be backed up>
export GITLAB_NAME=<name of the GitLab instance to be backed up>

执行以下命令配置 mc 命令行工具并测试连接:

mc alias set ${MINIO_ALIAS_NAME} ${MINIO_HOST} ${MINIO_ACCESS_KEY} ${MINIO_SECRET_KEY}
mc ping ${MINIO_ALIAS_NAME}

# Output:
#   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 配置正确。

备份

前提条件

创建存储桶

您需要创建两个存储桶:

  1. 用于存储备份数据的存储桶,名称为:gitlab-backups
  2. 用于在备份期间存储临时数据的存储桶,名称为:gitlab-backups-tmp

执行以下命令创建存储桶:

mc mb ${MINIO_ALIAS_NAME}/gitlab-backups
mc mb ${MINIO_ALIAS_NAME}/gitlab-backups-tmp

# Output:
# Bucket created successfully `myminio/gitlab-backups`.
# Bucket created successfully `myminio/gitlab-backups-tmp`.

执行以下命令,验证存储桶是否创建成功:

mc ls ${MINIO_ALIAS_NAME} | grep gitlab-backups

# Output:
# [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 is not set, please set it and try again"
    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"

# Output:
# secret/s3cfg created

在 GitLab 所在的集群中执行以下命令,编辑 GitLab 实例 CR:

kubectl edit gitlabofficial ${GITLAB_NAME} -n ${GITLAB_NAMESPACE}

请先根据注释编辑以下 yaml 配置,然后将其添加到 CR 中:

spec:
  helmValues:
    global:
      appConfig:
        backups:
          # These two bucket names must match the bucket names created in previous steps
          bucket: gitlab-backups
          tmpBucket: gitlab-backups-tmp
    gitlab:
      toolbox:
        backups:
          objectStorage:
            config:
              key: config
              # Name of the secret created in the previous step
              secret: s3cfg
        enabled: true
        persistence:
          accessMode: ReadWriteMany
          enabled: true
          # Backup requires packaging all files locally, so sufficient space is needed
          # Determine PVC capacity based on instance's used disk space
          size: 10Gi
          # Storage class name
          storageClass: nfs

更新 GitLab CR 后,系统将自动部署新的 Toolbox 组件。使用以下命令检查 Toolbox 组件是否部署成功:

kubectl get pod -n ${GITLAB_NAMESPACE} | grep toolbox

# Output:
# 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

# Output:
# 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:
          # These two bucket names must match the bucket names created in previous steps
          bucket: gitlab-backups
          tmpBucket: gitlab-backups-tmp
    gitlab:
      toolbox:
        enabled: true
        backups:
          cron:
            enabled: true
            # Configure backup cycle
            schedule: "0 1 * * *"
            persistence:
              enabled: true
              accessMode: ReadWriteMany
              # Backup requires packaging all files in the toolbox pod, so sufficient space is needed
              # Determine PVC capacity based on instance's used disk space
              size: 10Gi
              # Storage class name
              storageClass: nfs
          objectStorage:
            config:
              key: config
              # Name of the secret created in the previous step
              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:00 执行:0 3 * * *
  2. 每月 1 日和 15 日凌晨 3:00 执行:0 3 1,15 * *
  3. 每 10 分钟执行一次:*/10 * * * *

等待 GitLab 触发备份,然后您可以验证备份文件。

验证备份文件

执行以下命令,检查备份文件是否已上传到对象存储:

mc ls ${MINIO_ALIAS_NAME}/gitlab-backups

# Output:
# [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

# Output:
# [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=<namespace of the new GitLab instance>
export NEW_GITLAB_NAME=<name of the new GitLab instance>

停止工作负载

为确保恢复操作顺利进行,您需要在恢复期间停止 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

# Output:
# 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 数据库中存在自定义表,这些表及其所有数据都将被删除。

在终端中执行以下命令以进行恢复,其中需要将备份 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}
 
# Output:
# 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 一致。

从源实例获取 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

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

  • 组
  • 仓库
  • 用户
  • 合并请求

GitLab 是 GitLab Inc. 的商标。

Alauda 是独立供应商。本产品与 GitLab Inc. 无关联,也未获得其认可或赞助。所有商标均为其各自所有者的财产,此处仅用于标识目的。