Help us learn about your current experience with the documentation. Take the survey.

恢复 GitLab

  • Tier: 免费版、专业版、旗舰版
  • Offering: GitLab 自托管版

GitLab 恢复操作通过从备份中恢复数据来维持系统连续性并应对数据丢失。恢复操作包括:

  • 恢复数据库记录和配置
  • 恢复 Git 仓库、容器注册表镜像和上传内容
  • 恢复包注册表数据和 CI/CD 制品
  • 恢复账户和群组设置
  • 恢复项目和群组维基
  • 恢复项目级安全文件
  • 恢复外部合并请求差异

恢复过程需要一个与备份版本相同的现有 GitLab 安装。在生产环境使用前,请遵循恢复先决条件并测试完整的恢复流程。

恢复先决条件

目标 GitLab 实例必须已正常运行

执行恢复前需要有一个正常工作的 GitLab 安装。这是因为执行恢复操作的系统用户 (git) 通常无权创建或删除导入数据所需的 SQL 数据库 (gitlabhq_production)。所有现有数据都会被清除 (SQL) 或移动到单独目录(如仓库和上传内容)。恢复 SQL 数据时会跳过 PostgreSQL 扩展拥有的视图。

目标 GitLab 实例版本必须完全一致

只能将备份恢复到创建备份时完全相同版本和类型(CE 或 EE)的 GitLab。例如 CE 15.1.4。

如果备份版本与当前安装版本不同,必须在恢复备份前降级升级 GitLab 安装。

必须恢复 GitLab 密钥

恢复备份时,必须同时恢复 GitLab 密钥。如果迁移到新的 GitLab 实例,必须从旧服务器复制 GitLab 密钥文件。这些密钥包括数据库加密密钥、CI/CD 变量以及用于双重身份验证的变量。没有这些密钥会引发多个问题,包括启用双重身份验证的用户无法访问,以及 GitLab Runner 无法登录。

恢复以下文件:

某些 GitLab 配置必须与原始备份环境匹配

建议单独恢复之前的 /etc/gitlab/gitlab.rb(Linux 包安装)或 /home/git/gitlab/config/gitlab.yml(自编译安装)以及任何 TLS 或 SSH 密钥和证书

某些配置与 PostgreSQL 中的数据耦合。例如:

  • 如果原始环境有三个仓库存储(如 defaultmy-storage-1my-storage-2),则目标环境必须在配置中定义至少这些存储名称。
  • 从使用本地存储的环境恢复备份时,即使目标环境使用对象存储,也会恢复到本地存储。对象存储迁移必须在恢复前或后完成。

恢复挂载点目录

如果恢复到挂载点目录,必须确保这些目录在恢复尝试前为空。否则 GitLab 会在恢复新数据前尝试移动这些目录,导致错误。

了解更多关于配置 NFS 挂载的信息。

Linux 包安装的恢复

此过程假设:

  • 已安装与备份创建时完全相同版本和类型(CE/EE)的 GitLab。
  • 至少运行过一次 sudo gitlab-ctl reconfigure
  • GitLab 正在运行。若未运行,使用 sudo gitlab-ctl start 启动。

首先确保备份 tar 文件位于 gitlab.rb 配置中 gitlab_rails['backup_path'] 指定的备份目录。默认位置是 /var/opt/gitlab/backups。备份文件必须由 git 用户拥有。

sudo cp 11493107454_2018_04_25_10.6.4-ce_gitlab_backup.tar /var/opt/gitlab/backups/
sudo chown git:git /var/opt/gitlab/backups/11493107454_2018_04_25_10.6.4-ce_gitlab_backup.tar

停止连接到数据库的进程。保持 GitLab 其余部分运行:

sudo gitlab-ctl stop puma
sudo gitlab-ctl stop sidekiq
# 验证
sudo gitlab-ctl status

接下来,确保已完成恢复先决条件步骤,并在从原始安装复制 GitLab 密钥文件后运行过 gitlab-ctl reconfigure

然后恢复备份,指定要恢复的备份 ID:

以下命令会覆盖 GitLab 数据库的内容!

# 注意:名称中省略了 "_gitlab_backup.tar"
sudo gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce

如果备份 tar 文件与已安装的 GitLab 版本不匹配,恢复命令会中止并显示错误消息:

GitLab 版本不匹配:
  当前 GitLab 版本 (16.5.0-ee) 与备份中的 GitLab 版本不同!
  请切换到以下版本并重试:
  版本:16.4.3-ee

安装正确的 GitLab 版本,然后重试。

当安装使用 PgBouncer(出于性能原因或与 Patroni 集群一起使用时),恢复命令需要额外参数

在 PostgreSQL 节点上运行 reconfigure:

sudo gitlab-ctl reconfigure

接下来,启动并检查 GitLab:

sudo gitlab-ctl start
sudo gitlab-rake gitlab:check SANITIZE=true

验证数据库值是否可解密,尤其是在恢复 /etc/gitlab/gitlab-secrets.json 或恢复目标为不同服务器时。

sudo gitlab-rake gitlab:doctor:secrets

为增加保障,可执行上传文件完整性检查

sudo gitlab-rake gitlab:artifacts:check
sudo gitlab-rake gitlab:lfs:check
sudo gitlab-rake gitlab:uploads:check

恢复完成后,建议生成数据库统计信息以提高数据库性能并避免 UI 不一致:

  1. 进入数据库控制台

  2. 运行以下命令:

    SET STATEMENT_TIMEOUT=0 ; ANALYZE VERBOSE;

关于将此命令集成到恢复命令的讨论正在进行中,详见issue 276184

Docker 镜像和 GitLab Helm chart 安装的恢复

对于使用 Docker 镜像或 Kubernetes 集群上 GitLab Helm chart 的安装,恢复任务要求恢复目录为空。但在 Docker 和 Kubernetes 卷挂载中,系统级目录(如 Linux 操作系统中的 lost+found)可能存在于卷根目录。这些目录通常由 root 拥有,而恢复 Rake 任务以 git 用户运行,可能导致访问权限错误。恢复 GitLab 安装时,用户必须确认恢复目标目录为空。

对于这两种安装类型,备份 tarball 必须位于备份位置(默认位置为 /var/opt/gitlab/backups)。

Helm chart 安装的恢复

GitLab Helm chart 使用恢复 GitLab Helm chart 安装中记录的流程。

Docker 镜像安装的恢复

如果使用Docker Swarm,恢复过程中容器可能因 Puma 关闭而重启,导致容器健康检查失败。要解决此问题,可临时禁用健康检查机制。

  1. 编辑 docker-compose.yml

    healthcheck:
      disable: true
  2. 部署堆栈:

    docker stack deploy --compose-file docker-compose.yml mystack

更多信息见issue 6846

恢复任务可从主机运行:

# 停止连接到数据库的进程
docker exec -it <容器名称> gitlab-ctl stop puma
docker exec -it <容器名称> gitlab-ctl stop sidekiq

# 继续前验证所有进程已停止
docker exec -it <容器名称> gitlab-ctl status

# 运行恢复。注意:名称中省略了 "_gitlab_backup.tar"
docker exec -it <容器名称> gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce

# 重启 GitLab 容器
docker restart <容器名称>

# 检查 GitLab
docker exec -it <容器名称> gitlab-rake gitlab:check SANITIZE=true

自编译安装的恢复

首先确保备份 tar 文件位于 gitlab.yml 配置指定的备份目录:

## 备份设置
backup:
  path: "tmp/backups"   # 相对路径相对于 Rails.root(默认:tmp/backups/)

默认位置是 /home/git/gitlab/tmp/backups,且必须由 git 用户拥有。现在可以开始备份过程:

# 停止连接到数据库的进程
sudo service gitlab stop

sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production

示例输出:

解包备份... [完成]
恢复数据库表:
-- create_table("events", {:force=>true})
   -> 0.2231s
[...]
- 加载事件数据...[完成]
- 加载问题数据...[完成]
- 加载密钥数据...[跳过]
- 加载合并请求数据...[完成]
- 加载里程碑数据...[完成]
- 加载命名空间数据...[完成]
- 加载笔记数据...[完成]
- 加载项目数据...[完成]
- 加载受保护分支数据...[跳过]
- 加载模式迁移数据...[完成]
- 加载服务数据...[跳过]
- 加载代码片段数据...[跳过]
- 加载标签关联数据...[跳过]
- 加载标签数据...[跳过]
- 加载用户数据...[完成]
- 加载用户项目关联数据...[完成]
- 加载 Web 钩子数据...[跳过]
- 加载维基数据...[跳过]
恢复仓库:
- 恢复仓库 abcd... [完成]
- 对象池 1 ...
删除临时目录...[完成]

接下来,如需要则恢复 /home/git/gitlab/.secret如前所述

重启 GitLab:

sudo service gitlab restart

从备份中恢复单个或少量项目或群组

虽然用于恢复 GitLab 实例的 Rake 任务不支持恢复单个项目或群组,但可通过将备份恢复到单独的临时 GitLab 实例,然后从中导出项目或群组作为变通方案:

  1. 安装新的 GitLab实例,版本与要恢复的备份实例相同。
  2. 将备份恢复到此新实例,然后导出项目群组。关于导出内容的详细信息,请参阅导出功能文档。
  3. 导出完成后,转到旧实例并导入。
  4. 导入所需项目或群组后,可删除新的临时 GitLab 实例。

提供直接恢复单个项目或群组的功能请求正在issue #17517中讨论。

恢复增量仓库备份

每个备份档案都包含完整的独立备份,包括通过增量仓库备份流程创建的备份。恢复增量仓库备份使用与其他常规备份档案相同的恢复说明。

恢复选项

GitLab 提供的命令行工具支持更多恢复选项。

存在多个备份时指定要恢复的备份

备份文件使用以备份 ID 开头的命名方案。当存在多个备份时,必须通过设置环境变量 BACKUP=<backup-id> 指定要恢复的 <backup-id>_gitlab_backup.tar 文件。

恢复期间禁用提示

从备份恢复时,恢复脚本会提示确认:

  • 如果启用了写入 authorized_keys设置,在恢复脚本删除并重建 authorized_keys 文件前。
  • 恢复数据库时,在恢复脚本删除所有现有表前。
  • 恢复数据库后,如果恢复模式时出错,在继续前(因为可能引发后续问题)。

要禁用这些提示,将环境变量 GITLAB_ASSUME_YES 设置为 1

  • Linux 包安装:

    sudo GITLAB_ASSUME_YES=1 gitlab-backup restore
  • 自编译安装:

    sudo -u git -H GITLAB_ASSUME_YES=1 bundle exec rake gitlab:backup:restore RAILS_ENV=production

环境变量 force=yes 也可禁用这些提示。

恢复时排除任务

可通过添加环境变量 SKIP(值为逗号分隔的选项列表)排除特定恢复任务:

  • db(数据库)
  • uploads(附件)
  • builds(CI 作业输出日志)
  • artifacts(CI 作业制品)
  • lfs(LFS 对象)
  • terraform_state(Terraform 状态)
  • registry(容器注册表镜像)
  • pages(Pages 内容)
  • repositories(Git 仓库数据)
  • packages(包)

排除特定任务:

  • Linux 包安装:

    sudo gitlab-backup restore BACKUP=<backup-id> SKIP=db,uploads
  • 自编译安装:

    sudo -u git -H bundle exec rake gitlab:backup:restore BACKUP=<backup-id> SKIP=db,uploads RAILS_ENV=production

恢复特定仓库存储

GitLab 17.1 及更早版本受竞态条件影响,可能导致数据丢失。此问题影响已分叉并使用 GitLab对象池的仓库。为避免数据丢失,请仅使用 GitLab 17.2 或更高版本恢复备份。

使用多个仓库存储时,可使用 REPOSITORIES_STORAGES 选项单独恢复特定仓库存储的仓库。该选项接受逗号分隔的存储名称列表。

例如:

  • Linux 包安装:

    sudo gitlab-backup restore BACKUP=<backup-id> REPOSITORIES_STORAGES=storage1,storage2
  • 自编译安装:

    sudo -u git -H bundle exec rake gitlab:backup:restore BACKUP=<backup-id> REPOSITORIES_STORAGES=storage1,storage2

恢复特定仓库

GitLab 17.1 及更早版本受竞态条件影响,可能导致数据丢失。此问题影响已分叉并使用 GitLab对象池的仓库。为避免数据丢失,请仅使用 GitLab 17.2 或更高版本恢复备份。

可使用 REPOSITORIES_PATHSSKIP_REPOSITORIES_PATHS 选项恢复特定仓库。两个选项均接受逗号分隔的项目和群组路径列表。如果指定群组路径,则该群组及其子群组中所有项目的仓库都会被包含或跳过(取决于使用的选项)。群组和项目必须存在于指定备份或目标实例中。

REPOSITORIES_PATHSSKIP_REPOSITORIES_PATHS 选项仅适用于 Git 仓库,不适用于项目或群组数据库条目。如果使用 SKIP=db 创建仓库备份,则无法单独用于将特定仓库恢复到新实例。

例如,要恢复群组 A (group-a) 中所有项目的仓库、群组 B (group-b) 中的项目 C (group-b/project-c) 仓库,并跳过群组 A 中的项目 D (group-a/project-d):

  • Linux 包安装:

    sudo gitlab-backup restore BACKUP=<backup-id> REPOSITORIES_PATHS=group-a,group-b/project-c SKIP_REPOSITORIES_PATHS=group-a/project-d
  • 自编译安装:

    sudo -u git -H bundle exec rake gitlab:backup:restore BACKUP=<backup-id> REPOSITORIES_PATHS=group-a,group-b/project-c SKIP_REPOSITORIES_PATHS=group-a/project-d

恢复未打包的备份

如果发现未打包的备份(使用 SKIP=tar 创建),且未通过 BACKUP=<backup-id> 选择备份,则使用未打包的备份。

例如:

  • Linux 包安装:

    sudo gitlab-backup restore
  • 自编译安装:

    sudo -u git -H bundle exec rake gitlab:backup:restore

使用服务器端仓库备份恢复

收集服务器端备份时,恢复过程默认使用创建服务器端仓库备份中所示的服务器端恢复机制。可配置备份恢复,使托管每个仓库的 Gitaly 节点负责直接从对象存储拉取必要的备份数据。

  1. 在 Gitaly 中配置服务器端备份目标
  2. 启动服务器端备份恢复过程并指定要恢复的备份ID
sudo gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce
sudo -u git -H bundle exec rake gitlab:backup:restore BACKUP=11493107454_2018_04_25_10.6.4-ce
kubectl exec <Toolbox pod 名称> -it -- backup-utility --restore -t <backup_ID> --repositories-server-side

使用基于 cron 的备份时,将 --repositories-server-side 标志添加到额外参数。

故障排除

以下是可能遇到的问题及解决方案。

Linux 包安装恢复数据库备份时输出警告

使用备份恢复流程时,可能遇到以下警告消息:

ERROR: must be owner of extension pg_trgm
ERROR: must be owner of extension btree_gist
ERROR: must be owner of extension plpgsql
WARNING:  no privileges could be revoked for "public" (两次出现)
WARNING:  no privileges were granted for "public" (两次出现)

请注意,尽管出现这些警告消息,备份仍成功恢复。

Rake 任务以 gitlab 用户身份运行,该用户没有数据库超级用户访问权限。启动恢复时也以 gitlab 用户身份运行,但会尝试修改其无权访问的对象。这些对象不影响数据库备份或恢复,但会显示警告消息。

更多信息请参阅:

因 Git 服务器钩子导致恢复失败

从备份恢复时,如果满足以下条件可能遇到错误:

  • 使用GitLab 15.10 及更早版本的方法配置了 Git 服务器钩子 (custom_hook)
  • GitLab 版本为 15.11 或更高版本
  • 创建了指向 GitLab 管理位置之外目录的符号链接

错误如下:

{"level":"fatal","msg":"restore: pipeline: 1 failures encountered:\n - @hashed/path/to/hashed_repository.git (path/to_project): manager: restore custom hooks, \"@hashed/path/to/hashed_repository/<BackupID>_<GitLabVersion>-ee/001.custom_hooks.tar\": rpc error: code = Internal desc = setting custom hooks: generating prepared vote: walking directory: copying file to hash: read /mnt/gitlab-app/git-data/repositories/+gitaly/tmp/default-repositories.old.<timestamp>.<temporaryfolder>/custom_hooks/compliance-triggers.d: is a directory\n","pid":3256017,"time":"2023-08-10T20:09:44.395Z"}

解决方案:更新 GitLab 15.11 及更高版本的 Git 服务器钩子,然后创建新备份。

使用 fapolicyd 时恢复成功但仓库显示为空

使用 fapolicyd 增强安全性时,GitLab 可能报告恢复成功但仓库显示为空。更多故障排除帮助请参阅Gitaly 故障排除文档