1. 课程导入与GitLab数据架构

在开始学习备份与恢复之前,先要建立一个基本认识:GitLab 并不是一个"把代码放在磁盘上"的单一应用,而是一组协同工作的服务集合。代码仓库、议题、合并请求、流水线记录、制品、容器镜像、用户权限、密钥与配置,分别落在不同的存储组件中。备份与恢复之所以容易出错,根本原因往往不是命令写错,而是没有分清哪些数据在哪个组件里、它们之间是什么依赖关系。本章先厘清概念,再拆解 GitLab 的核心数据组件。

一、三个必须区分的概念

备份(Backup)是指对当前数据做一份可离线保存的副本,目标是"数据可重建"。它回答的问题是:如果数据被误删、被错误迁移、被勒索加密,我能不能把系统还原到某个时间点?备份通常是周期性的、自动化的,产物是归档文件或存储快照。

恢复(Restore)是把备份产物重新写回 GitLab,使实例回到备份时刻的状态。恢复的关键约束是版本一致性:备份文件由哪个 GitLab 版本产生,就应当恢复到相同或兼容的版本,跨大版本直接恢复通常失败。恢复还要求目标实例的组件拓扑与备份时基本一致,例如备份时使用了对象存储,恢复时也必须配置对象存储。

灾难恢复(Disaster Recovery,DR)的范围更大。它关注的不是"数据丢了怎么找回",而是"整个站点不可用了怎么办"。灾难包括机房断电、云区域故障、存储集群整体损坏、误删生产实例等。DR 方案通常包含:异地副本、定期演练、明确的 RTO(恢复时间目标)与 RPO(恢复点目标)、切换与回切流程。可以这样理解三者关系:备份恢复是 DR 的基础手段之一,但 DR 还包含架构冗余、故障切换和人员流程。

一个常见的误区是把"每天跑一次备份"等同于"具备灾难恢复能力"。如果备份文件与生产实例放在同一个存储、同一个机房,那么该存储或机房整体故障时,备份与生产一起消失,RPO 实际为无穷大。

二、GitLab 核心数据组件及其依赖关系

GitLab 的数据分布在五类组件中,它们各自保存不同内容,且存在明确的依赖方向。理解这张"数据地图",是后续所有备份策略的前提。

  • PostgreSQL:保存几乎所有结构化元数据——用户、项目、议题、合并请求、评论、权限、CI/CD 流水线定义与状态、部分配置项。它是 GitLab 的"大脑",一旦丢失,即使代码仓库文件还在,平台也无法正常使用。
  • Gitaly:负责 Git 仓库的实际存储与访问。每个项目的提交历史、分支、标签、LFS 对象都落在 Gitaly 管理的仓库目录中。Gitaly 是"代码本体"的所在。
  • Redis:承担缓存、会话、Sidekiq 后台任务队列、分布式锁等职责。它保存的多为可重建的临时状态,但队列中可能含有尚未落库的任务,因此备份时仍需关注。
  • 对象存储:存放制品(artifacts)、作业日志、容器镜像仓库、上传附件、备份文件本身等大体积二进制内容。可以是本地磁盘,也可以是 S3 兼容服务。
  • 配置文件与密钥:/etc/gitlab/gitlab.rb、/etc/gitlab/gitlab-secrets.json 等。后者包含数据库加密密钥、CI 变量加密密钥、会话密钥等。缺少它,即使数据库和仓库都恢复成功,加密数据也无法解密,用户会无法登录。

依赖方向可以概括为:配置文件与密钥决定各组件如何连接;PostgreSQL 记录"有哪些项目、谁有权限";Gitaly 保存项目对应的代码实体;对象存储保存与项目关联的大文件;Redis 为上述访问提供加速与异步调度。恢复时必须按这个依赖顺序处理:先恢复配置与密钥,再恢复数据库,然后恢复仓库与对象存储,最后启动服务并校验。

GitLab 核心数据组件与依赖关系 箭头表示"被依赖 → 依赖方",恢复顺序应自左向右 配置文件与密钥 gitlab.rb gitlab-secrets.json 决定连接方式与解密能力 PostgreSQL 用户 / 项目 / 权限 议题 / MR / 流水线元数据 平台"大脑",不可缺失 Gitaly Git 仓库 / 提交历史 分支 / 标签 / LFS 对象 代码本体所在 对象存储 制品 / 作业日志 镜像仓库 / 上传附件 大体积二进制内容 Redis 缓存 / 会话 / 分布式锁 Sidekiq 任务队列 多为可重建的临时状态 恢复顺序 ① 配置与密钥 ② PostgreSQL ③ Gitaly 仓库 ④ 对象存储 ⑤ 启动并校验 顺序颠倒会导致:数据库指向不存在的仓库、加密数据无法解密、附件与记录不匹配。

三、从数据地图推导备份策略

有了上面的依赖关系,备份策略就不再是"跑一条命令",而是可以逐项对照。GitLab 官方提供的 gitlab-backup 工具会打包数据库、仓库和部分配置,但它默认不包含 gitlab-secrets.json 与 gitlab.rb,也不包含对象存储中的内容(当启用对象存储时,备份只记录引用)。因此一个完整的备份清单至少应覆盖:

数据组件备份方式是否被 gitlab-backup 覆盖恢复要点
PostgreSQLpg_dump 逻辑备份 / 物理快照是版本需匹配,恢复后执行迁移
Gitaly 仓库仓库目录打包 / Gitaly 快照是需与数据库中的项目记录对应
对象存储存储桶版本控制 / 跨区域复制否(仅记录引用)需单独保证桶内数据可用
Redis通常不单独备份否重启后重建,队列任务可能丢失
配置文件与密钥手工归档 / 配置管理工具否必须与备份文件同批次保存

以一个中等规模实例为例:假设有 800 个项目、数据库约 12 GB、仓库总量约 300 GB、对象存储约 1.5 TB。若只依赖 gitlab-backup,得到的归档大约 300 GB 量级,恢复后会发现制品与镜像全部缺失,因为它们在对象存储里。合理的做法是:数据库与仓库走每日全量加增量策略,对象存储开启版本控制并配置跨区域复制,配置文件与密钥在每次变更后立即归档到独立的密钥管理系统。

备份文件本身也需要保护。若备份归档与生产实例在同一台主机、同一块磁盘上,一次磁盘故障就会同时带走两者。备份必须落到独立介质或独立故障域,并定期做恢复演练——没有验证过的备份,不能算作备份。

四、本节要点回顾