跳到主要内容

GitLab 备份与恢复

GitLab 数据分散在 PostgreSQL、Redis、Gitaly 仓库、上传文件、LFS、Container Registry 和 CI Artifacts 中。只备份 Git 仓库不够;必须使用官方备份工具或等价的分组件备份,并定期做恢复演练。

本章以 Omnibus 安装为例。Helm/Kubernetes 部署需分别备份 PVC、Cloud SQL 和对象存储,但 RPO/RTO 设计原则相同。

1. GitLab数据组成

数据类型默认位置(Omnibus)是否包含在 gitlab-backup
PostgreSQL/var/opt/gitlab/postgresql
Git 仓库(Gitaly)/var/opt/gitlab/git-data
上传附件、LFS/var/opt/gitlab/gitlab-rails/shared是(含 uploads、builds 等)
CI Artifactsshared/artifacts
Container Registry对象存储或 registry 目录否,需单独备份
gitlab.rb / gitlab-secrets.json/etc/gitlab否,必须单独保存
Redis内存 + RDB否(可重建,会话会丢)

gitlab-secrets.json 丢失将无法解密数据库中的 OAuth、CI 变量等字段;与备份文件分开存放,且加密保存。

2. 官方备份机制

Omnibus 提供 gitlab-backup,在维护窗口内一致性导出 tar 包:

# 查看备份目录配置
sudo grep backup_path /etc/gitlab/gitlab.rb
# 默认 backup_path '/var/opt/gitlab/backups'

备份文件名形如 1234567890_2026_07_24_12.0.0_gitlab_backup.tar,其中时间戳与 GitLab 版本相关。恢复时 GitLab 版本必须与备份创建版本一致或按升级路径先恢复到同版本

不要依赖文件系统快照作为唯一手段:数据库与仓库文件若不 quiesce,快照可能不一致。快照可作为补充,与 gitlab-backup 配合使用。

3. gitlab-backup命令

手工全量备份:

sudo gitlab-ctl stop puma
sudo gitlab-ctl stop sidekiq
# 可选:stop gitaly 以获得更严格一致性(会短暂影响 git 操作)
sudo gitlab-backup create STRATEGY=copy
sudo gitlab-ctl start

STRATEGY=copy 对小中型实例更稳妥;超大实例可评估 STRATEGY=snapshot(需文件系统支持)。跳过某些组件:

sudo gitlab-backup create SKIP=registry,artifacts

仅当 Registry/Artifacts 已单独备份时使用 SKIP。查看已有备份:

sudo ls -lh /var/opt/gitlab/backups/

同时备份 secrets 和配置:

sudo install -d -m 0700 /backup/gitlab-config
sudo cp /etc/gitlab/gitlab.rb /backup/gitlab-config/gitlab.rb.$(date +%F)
sudo cp /etc/gitlab/gitlab-secrets.json /backup/gitlab-config/
sha256sum /var/opt/gitlab/backups/*_gitlab_backup.tar | tail -1

4. 对象存储备份

gitlab.rb 配置了 S3/OSS 作为 artifacts、uploads、lfs、registry 后端时,gitlab-backup tar 可能不包含这些对象,或只含元数据。

# /etc/gitlab/gitlab.rb 片段
gitlab_rails['object_store']['enabled'] = true
gitlab_rails['object_store']['connection'] = {
'provider' => 'AWS',
'region' => 'ap-southeast-1',
'aws_access_key_id' => '...',
'aws_secret_access_key' => '...'
}
gitlab_rails['artifacts_object_store_enabled'] = true
gitlab_rails['registry_object_store_enabled'] = true

对象存储侧应启用:

  1. 版本控制或定期 cross-region replication;
  2. 生命周期规则(非当前版本 30 天后转冷存储);
  3. 与 GitLab 备份时间对齐的 bucket 清单导出。
# AWS CLI 示例:同步到灾备 bucket
aws s3 sync s3://gitlab-prod-artifacts s3://gitlab-dr-artifacts --storage-class STANDARD_IA

Registry 使用独立 bucket 时,同样纳入 replication;恢复 GitLab 后若 bucket 完好,镜像通常无需从 tar 还原。

5. 定时备份方案

crontab(维护窗口,例如每日 02:00):

sudo crontab -e -u root
0 2 * * * /opt/gitlab/bin/gitlab-backup create CRON=1 STRATEGY=copy
15 2 * * * cp /etc/gitlab/gitlab-secrets.json /backup/gitlab-config/gitlab-secrets.json.$(date +\%F)
30 2 * * * find /var/opt/gitlab/backups -name '*_gitlab_backup.tar' -mtime +14 -delete

上传异地(示例 rsync 到备份服务器):

#!/bin/bash
set -euo pipefail
LATEST=$(ls -t /var/opt/gitlab/backups/*_gitlab_backup.tar | head -1)
rsync -av --progress "$LATEST" backup@dr-host:/backups/gitlab/
rsync -av /backup/gitlab-config/ backup@dr-host:/backups/gitlab-config/

监控:备份脚本退出码非 0 时告警;每日检查最新 tar 大小是否异常骤降(可能备份不完整)。GitLab 15+ 可配合 Prometheus 指标 gitlab_backup_success 等(若已启用监控)。

6. 数据恢复流程

干净同版本 Omnibus 节点上恢复(或先安装与备份一致的 GitLab 版本):

# 1. 停止写入
sudo gitlab-ctl stop puma
sudo gitlab-ctl stop sidekiq

# 2. 还原 secrets 和 gitlab.rb(全新安装后)
sudo cp /backup/gitlab-config/gitlab-secrets.json /etc/gitlab/
sudo cp /backup/gitlab-config/gitlab.rb /etc/gitlab/
sudo gitlab-ctl reconfigure

# 3. 放置备份 tar
sudo cp /backup/gitlab/1234567890_2026_07_24_12.0.0_gitlab_backup.tar /var/opt/gitlab/backups/
sudo chown git:git /var/opt/gitlab/backups/*_gitlab_backup.tar

# 4. 执行恢复(BACKUP 为文件名中的时间戳前缀)
sudo gitlab-backup restore BACKUP=1234567890_2026_07_24_12.0.0 force=yes

# 5. 重启并检查
sudo gitlab-rake gitlab:check SANITIZE=true
sudo gitlab-ctl restart
sudo gitlab-rake cache:clear

force=yes 仅在测试环境或确认覆盖时使用。生产恢复前应对当前损坏实例做取证备份。若仅 PostgreSQL 损坏而 Gitaly 完好,可联系 GitLab 支持或使用高级分组件恢复;默认流程仍是全量 tar。

7. 恢复验证

服务启动成功不等于数据完整。按下列清单验证:

# 版本与迁移状态
sudo gitlab-rake gitlab:env:info

# 抽样项目 clone
git clone https://gitlab.example.com/mygroup/known-project.git /tmp/verify-clone

# API 检查用户与项目数量
curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
"https://gitlab.example.com/api/v4/projects?membership=true&per_page=1" -I
# 对比 X-Total 与备份前记录

# Sidekiq 与 Redis
sudo gitlab-ctl status
sudo gitlab-rails runner 'puts User.count; puts Project.count'

业务验证:随机 MR 能否打开、Pipeline 能否运行、Registry 能否 pull、已有 CI 变量能否在 Job 中使用。记录实际 RTO(从决策恢复到验证通过的时间)和 RPO(备份点到故障点丢失的数据窗口)。

8. 灾备方案设计

典型两地三中心思路:

GitLab 两地灾备与恢复链路

批量备份决定基础恢复能力,WAL 流复制、Gitaly 温备或 GitLab Geo 用于缩小 RPO。无论采用哪个级别,gitlab-secrets.json 都必须与常规备份分离保存并定期验证。

级别RPORTO手段
基础24h4–8h每日 tar + secrets + S3 replication
标准1h1–2h数据库 WAL + 频繁 backup + 自动化恢复脚本
高级分钟级<1hGitLab Geo、Patroni、Gitaly Cluster

Geo 适合多只读副本与选择性复制;成本高,需 Premium/Ultimate 许可。中小团队优先把 secrets 分离备份 + 对象存储 replication + 季度恢复演练 做扎实,再评估 Geo。

灾备 Runbook 应包含:决策人、停写步骤、DNS 切换、恢复命令、验证清单、回切条件。每次 GitLab 大版本升级后,在 staging 用最新备份格式跑一遍恢复,避免版本不兼容导致 DR 失效。