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 Artifacts | shared/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
对象存储侧应启用:
- 版本控制或定期 cross-region replication;
- 生命周期规则(非当前版本 30 天后转冷存储);
- 与 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. 灾备方案设计
典型两地三中心思路:

批量备份决定基础恢复能力,WAL 流复制、Gitaly 温备或 GitLab Geo 用于缩小 RPO。无论采用哪个级别,gitlab-secrets.json 都必须与常规备份分离保存并定期验证。
| 级别 | RPO | RTO | 手段 |
|---|---|---|---|
| 基础 | 24h | 4–8h | 每日 tar + secrets + S3 replication |
| 标准 | 1h | 1–2h | 数据库 WAL + 频繁 backup + 自动化恢复脚本 |
| 高级 | 分钟级 | <1h | GitLab Geo、Patroni、Gitaly Cluster |
Geo 适合多只读副本与选择性复制;成本高,需 Premium/Ultimate 许可。中小团队优先把 secrets 分离备份 + 对象存储 replication + 季度恢复演练 做扎实,再评估 Geo。
灾备 Runbook 应包含:决策人、停写步骤、DNS 切换、恢复命令、验证清单、回切条件。每次 GitLab 大版本升级后,在 staging 用最新备份格式跑一遍恢复,避免版本不兼容导致 DR 失效。