恢复 GitLab
适用层级:Free、Premium、Ultimate;部署方式:GitLab Self-Managed。
GitLab 恢复操作从备份中恢复数据,以维持系统连续性并应对数据丢失。它可以恢复数据库记录和配置、Git 仓库和容器镜像与上传内容、软件包仓库数据与 CI/CD 制品、账户和群组设置、项目和群组 Wiki、项目级安全文件,以及存储在外部的合并请求差异。
恢复需要一个已经安装好的 GitLab 实例,且版本必须与备份一致。请满足下列前提条件,并在用于生产环境之前测试完整的恢复流程。
恢复前提条件
目标 GitLab 实例必须已经能够正常运行
执行恢复前,必须有一个可正常工作的 GitLab 安装。这是因为执行恢复操作的系统用户(git)通常无权创建或删除用于导入数据的 SQL 数据库(gitlabhq_production)。
目标 GitLab 实例不应已有数据
不同类型的既有数据会受到不同处理:
- PostgreSQL 数据会在恢复过程中自动清除。
- Git 仓库:如果已经存在同名仓库,恢复会报“repository already exists”。参见 issue 118459。
- 文件系统中的数据会在条件允许时先移到单独目录,再进行恢复。
- 对象存储数据不会自动清除。必须在恢复前手动清空对象存储桶,避免残留孤立数据。
为了保证恢复可靠,例如自动把生产环境恢复到预发布环境时,应使用与备份版本相同的全新 GitLab 安装。恢复 SQL 数据时,会跳过由 PostgreSQL 扩展拥有的视图。
目标实例必须具有完全相同的版本
备份只能恢复到与创建备份时完全相同的 GitLab 版本和类型(CE 或 EE),例如 CE 15.1.4。如果当前安装与备份版本不同,必须先降级或升级安装,再恢复备份。
必须恢复 GitLab 密钥
恢复备份时也必须恢复 GitLab secrets。如果迁移到新实例,需要从旧服务器复制 secrets 文件。其中包含数据库加密密钥、CI/CD 变量以及双因素身份验证使用的变量。缺少密钥会导致多种问题,包括启用了双因素身份验证的用户无法访问,以及 GitLab Runner 无法登录。
按安装方式恢复以下文件或密钥:
Linux 软件包:
/etc/gitlab/gitlab-secrets.json
Helm chart(Kubernetes):恢复 secrets;如有需要,可将 Helm chart secrets 转换为 Linux 软件包格式。
Docker:若已将 /etc/gitlab 挂载在 /srv/gitlab/config 下:
/srv/gitlab/config/gitlab-secrets.json
自行从源码编译:
/home/git/gitlab/.secret
某些配置必须与原备份环境一致
通常还需要分别恢复原来的 /etc/gitlab/gitlab.rb(Linux 软件包安装)或 /home/git/gitlab/config/gitlab.yml(自行编译安装),以及 TLS 或 SSH 密钥和证书。
某些配置与 PostgreSQL 中的数据相互关联。例如,原环境若有三个仓库存储(如 default、my-storage-1、my-storage-2),目标环境配置中也必须至少定义这些存储名称。从使用本地存储的环境恢复备份时,即使目标环境配置了对象存储,数据仍会恢复到本地存储;迁移到对象存储必须在恢复之前或之后进行。参见备份不包含的数据。
恢复到作为挂载点的目录
如果目标目录是挂载点,尝试恢复前必须确保目录为空,否则 GitLab 会在恢复新数据前尝试移动这些目录,进而报错。参见配置 NFS 挂载。
恢复 Linux 软件包安装
本流程假定:已安装与备份完全相同的版本和类型(CE/EE);至少运行过一次 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
# Verify
sudo gitlab-ctl status
确认满足恢复前提条件。如果恢复到新服务器,应先复制 secrets 文件,再运行 gitlab-ctl reconfigure。
接着恢复备份,并指定要使用的备份标识。这会覆盖 GitLab 数据库内容。
# NOTE: "_gitlab_backup.tar" is omitted from the name
sudo gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce
如果安装版本与备份不符,恢复命令会中止并显示错误:
GitLab version mismatch:
Your current GitLab version (16.5.0-ee) differs from the GitLab version in the backup!
Please switch to the following version and try again:
version: 16.4.3-ee
安装与备份相同的版本后,重新尝试恢复。
重新配置 GitLab;如果有独立 PostgreSQL 节点,应在该节点执行:
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
为进一步确认数据完整性,可以检查上传文件、CI/CD 制品与 LFS 对象:
sudo gitlab-rake gitlab:artifacts:check
sudo gitlab-rake gitlab:lfs:check
sudo gitlab-rake gitlab:uploads:check
恢复后建议生成数据库统计信息,以改善数据库性能,避免界面出现不一致。进入数据库控制台,执行以下 SQL:
SET STATEMENT_TIMEOUT=0 ; ANALYZE VERBOSE;
issue 276184 讨论了把这一步整合进恢复流程。另见实例检查、GitLab doctor和上传文件检查指南。
恢复 Docker 和 Helm chart 安装
Docker 或 Kubernetes 部署的恢复过程基本相同。恢复的目标目录必须为空;挂载卷根目录中常见的 lost+found 目录归 root 所有,而恢复任务以 git 用户运行,会因此发生权限错误。应确保恢复涉及的卷目录为空。默认备份位置与 Linux 软件包安装相同。
Helm chart(Kubernetes)
Docker 和 Docker Swarm
Docker Swarm 中,恢复过程中停止 Puma 会使健康检查失败,并触发服务重启。应暂时禁用健康检查,在 docker-compose.yml 文件中加入:
healthcheck:
disable: true
然后重新部署 stack:
docker stack deploy --compose-file docker-compose.yml mystack
有关此问题的背景,参见 issue 6846。从宿主机执行恢复:
# Stop the processes that are connected to the database
docker exec -it <name of container> gitlab-ctl stop puma
docker exec -it <name of container> gitlab-ctl stop sidekiq
# Verify that the processes are all down before continuing
docker exec -it <name of container> gitlab-ctl status
# Run the restore. NOTE: "_gitlab_backup.tar" is omitted from the name
docker exec -it <name of container> gitlab-backup restore BACKUP=11493107454_2018_04_25_10.6.4-ce
# Restart the GitLab container
docker restart <name of container>
# Check GitLab
docker exec -it <name of container> gitlab-rake gitlab:check SANITIZE=true
恢复自行编译的安装
确保备份归档位于 gitlab.yml 的 backup 配置指定的目录:
## Backup settings
backup:
path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/)
默认位置为 /home/git/gitlab/tmp/backups,归档文件必须归 git 用户所有。开始恢复:
# Stop processes that are connected to the database
sudo service gitlab stop
sudo -u git -H bundle exec rake gitlab:backup:restore RAILS_ENV=production
示例输出如下:
Unpacking backup... [DONE]
Restoring database tables:
-- create_table("events", {:force=>true})
-> 0.2231s
[...]
- Loading fixture events...[DONE]
- Loading fixture issues...[DONE]
- Loading fixture keys...[SKIPPING]
- Loading fixture merge_requests...[DONE]
- Loading fixture milestones...[DONE]
- Loading fixture namespaces...[DONE]
- Loading fixture notes...[DONE]
- Loading fixture projects...[DONE]
- Loading fixture protected_branches...[SKIPPING]
- Loading fixture schema_migrations...[DONE]
- Loading fixture services...[SKIPPING]
- Loading fixture snippets...[SKIPPING]
- Loading fixture taggings...[SKIPPING]
- Loading fixture tags...[SKIPPING]
- Loading fixture users...[DONE]
- Loading fixture users_projects...[DONE]
- Loading fixture web_hooks...[SKIPPING]
- Loading fixture wikis...[SKIPPING]
Restoring repositories:
- Restoring repository abcd... [DONE]
- Object pool 1 ...
Deleting tmp directories...[DONE]
如有需要,恢复 secrets 文件 /home/git/gitlab/.secret,然后重启 GitLab:
sudo service gitlab restart
恢复单个或少数项目、群组
恢复任务不能直接恢复单个或少数项目、群组。可采用以下流程:
- 安装一个与备份版本相同的临时 GitLab 实例。
- 把备份恢复到临时实例。
- 导出项目或导出群组(已弃用)。使用前请查看相应导出功能的限制。
- 把导出的项目或群组导入原实例。
- 完成后删除临时实例。
直接恢复单个项目的功能请求见 issue 17517。
从增量仓库备份恢复
常规 gitlab-backup 创建的增量备份归档是自包含的:它包含恢复所需的完整备份链。恢复方式与普通备份相同,内部会依次应用归档中的增量。
服务器端仓库备份则不同:备份归档不包含仓库数据;各次增量独立存放在 Gitaly 对象存储中,恢复时根据清单按顺序应用。不要删除中间增量;对象存储的生命周期策略若删掉备份链中的任何一环,也会破坏恢复所需的完整链。
恢复选项
选择要恢复的备份
备份目录存在多个归档时,使用 BACKUP 环境变量指定备份 ID。归档名为 <backup-id>_gitlab_backup.tar,变量写作 BACKUP=<backup-id>。
禁用提示
恢复流程可能在三处请求确认:启用了写入 authorized_keys 设置时,删除并重建该文件之前;删除数据库表之前;以及数据库 schema 恢复报错后继续之前。设置 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:Git LFS 对象。terraform_state:Terraform 状态文件。registry:容器镜像仓库。pages:GitLab 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
恢复指定仓库存储
多仓库存储环境中,可以通过 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 19.4 起,SKIP_REPOSITORIES_PATHS 不再删除备份中被排除的仓库,参见 issue 610910。
使用 REPOSITORIES_PATHS 指定恢复范围,使用 SKIP_REPOSITORIES_PATHS 排除指定范围。值可以是项目路径或群组路径;群组路径会包括其后代项目。有关群组或项目必须存在于备份或目标实例中。
例如,恢复 group-a 和 group-b/project-c,但跳过 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
只指定排除路径时,Linux 软件包安装:
sudo gitlab-backup restore BACKUP=<backup-id> SKIP_REPOSITORIES_PATHS=group-a/project-d
自行编译安装:
sudo -u git -H bundle exec rake gitlab:backup:restore BACKUP=<backup-id> SKIP_REPOSITORIES_PATHS=group-a/project-d
从未打包的备份恢复
使用 SKIP=tar 创建的备份未打包成 tar。未指定 BACKUP 时,恢复任务会检测并使用该备份。
Linux 软件包安装:
sudo gitlab-backup restore
自行编译安装:
sudo -u git -H bundle exec rake gitlab:backup:restore
恢复服务器端仓库备份
版本历史:GitLab 17.0 增加了 backup-utility 对服务器端仓库恢复的支持,参见 issue 438393。
如果创建备份时使用了服务器端仓库备份,恢复默认也使用这种方式。每个 Gitaly 节点会从对象存储取回自己的仓库数据。先配置 Gitaly 服务器端备份存储,再使用对应备份 ID 恢复。
Linux 软件包安装:
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
Helm chart 安装,在 Toolbox pod 中执行:
kubectl exec <Toolbox pod name> -it -- backup-utility --restore -t <backup_ID> --repositories-server-side
若通过定时备份任务管理备份,应在该任务的额外参数中加入服务器端仓库备份标志 --repositories-server-side。
故障排查
Linux 软件包安装中预期出现的警告
恢复可能输出以下 PostgreSQL 扩展所有权警告:
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" (two occurrences)
WARNING: no privileges were granted for "public" (two occurrences)
这些警告不影响备份恢复成功。恢复 Rake 任务以 gitlab 用户运行,该用户不是数据库超级用户,恢复过程试图修改其不拥有的对象,因此 PostgreSQL 发出警告。相关背景见 PostgreSQL 邮件列表讨论、扩展所有权讨论和相关问答。
恢复 Git 服务器钩子失败
若备份通过 GitLab 15.10 或更早版本的方法创建,而恢复环境为 GitLab 15.11 或更高版本,并且服务器钩子包含指向托管目录以外的符号链接,恢复可能失败:
{"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"}
应在新版本中按更新后的方式配置服务器钩子,然后重新创建备份。
启用 fapolicyd 后仓库为空
若恢复报告成功,但仓库显示为空,且系统启用了 fapolicyd,请参见 Gitaly 故障排查。











暂无评论内容