移动由极狐GitLab 管理的仓库

您可以将极狐GitLab 管理的所有仓库移动到另一个文件系统或另一个服务器。

在极狐GitLab 实例中移动数据

移动 Git 存储库的推荐方法是极狐GitLab API:

  • 在服务器之间移动。
  • 在不同的存储之间移动。
  • 从单节点 Gitaly 移动到 Gitaly 集群。

移动仓库

极狐GitLab 仓库可以与项目、群组和片段相关联。这些类型中的每一种都有一个单独的 API 来安排相应的仓库移动。要移动极狐GitLab 实例上的所有仓库,必须计划为每个存储移动这些类型中的每一个。

caution要将仓库移动到极狐GitLab 版本 13.12 到 14.1 中的 Gitaly 集群,您必须启用 gitaly_replicate_repository_direct_fetch 功能标志
caution可以通过调用 /projects/:project_id/repository_storage_moves永久删除仓库,该调用尝试将已存储在 Gitaly 集群中的项目移回该集群。

在移动期间,每个仓库都是只读的。在移动完成之前,仓库不可写。

移动仓库:

  1. 确保极狐GitLab 实例可以访问所有本地和集群存储。在此示例中,它们是 <original_storage_name><cluster_storage_name>
  2. 配置仓库存储权重以便新存储接收所有新项目。这会阻止在迁移过程中在现有存储上创建新项目。
  3. 为以下对象计划存储库移动:

移动所有项目

使用 API 计划项目移动:

  1. 使用 API 为存储分片上的所有项目安排仓库存储移动。例如:

    curl --request POST --header "Private-Token: <your_access_token>" \
         --header "Content-Type: application/json" \
         --data '{"source_storage_name":"<original_storage_name>","destination_storage_name":"<cluster_storage_name>"}' \
         "https://gitlab.example.com/api/v4/project_repository_storage_moves"
    
  2. 使用 API 查询最近的仓库移动。响应表明:
    • 移动已成功完成。state 字段是 finished
    • 移动正在进行中。重新查询仓库移动,直到它成功完成。
    • 移动失败。大多数故障都是暂时的,可以通过重新计划移动来解决。
  3. 移动完成后,使用 API 查询项目,并确认所有项目都已移动。不应返回任何项目并将 repository_storage 字段设置为旧存储。例如:

    curl --header "Private-Token: <your_access_token>" --header "Content-Type: application/json" \
    "https://gitlab.example.com/api/v4/projects?repository_storage=<original_storage_name>"
    

    或者使用 rails 控制台来确认所有项目都已移动。在 rails 控制台中运行以下命令:

    ProjectRepository.for_repository_storage('<original_storage_name>')
    
  4. 根据要求,重复每个存储。

移动所有代码片段

使用 API 计划片段移动:

  1. 为存储分片上的所有片段安排仓库存储移动。例如:

    curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
         --header "Content-Type: application/json" \
         --data '{"source_storage_name":"<original_storage_name>","destination_storage_name":"<cluster_storage_name>"}' \
         "https://gitlab.example.com/api/v4/snippet_repository_storage_moves"
    
  2. 使用 API 查询最近的仓库移动。响应表明:
    • 移动已成功完成。state 字段是 finished
    • 移动正在进行中。重新查询仓库移动,直到它成功完成。
    • 移动失败。大多数故障都是暂时的,可以通过重新计划移动来解决。
  3. 移动完成后,使用 rails 控制台,确认所有片段都已移动。不应为原始存储返回任何片段。在 rails 控制台中运行以下命令:

    SnippetRepository.for_repository_storage('<original_storage_name>')
    
  4. 根据要求,重复每个存储。

移动所有群组

使用 API 计划群组移动:

  1. 为存储分片上的所有群组计划存储库存储移动。例如:

     curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
          --header "Content-Type: application/json" \
          --data '{"source_storage_name":"<original_storage_name>","destination_storage_name":"<cluster_storage_name>"}' \
          "https://gitlab.example.com/api/v4/group_repository_storage_moves"
    
  2. 使用 API 查询最近的仓库移动。响应表明:
    • 移动已成功完成。state 字段是 finished
    • 移动正在进行中。重新查询仓库移动,直到它成功完成。
    • 移动失败。大多数故障都是暂时的,可以通过重新计划移动来解决。
  3. 移动完成后,使用 rails 控制台,确认所有群组都已移动。不应退回任何群组,进行原始存储。在 rails 控制台中运行以下命令:

    GroupWikiRepository.for_repository_storage('<original_storage_name>')
    
  4. 根据要求,重复每个存储。

迁移到另一个极狐GitLab 实例

如果您要迁移到新的极狐GitLab 环境,则不能选择使用 API,例如:

  • 从单节点极狐GitLab 到横向扩展架构。
  • 从您的私有数据中心的极狐GitLab 实例到云提供商。

文档的其余部分介绍了将所有仓库从 /var/opt/gitlab/git-data/repositories 复制到 /mnt/gitlab/repositories 的一些方法。

存在以下三个场景:

  • 目标目录为空。
  • 目标目录包含仓库的过时副本。
  • 如何处理数以千计的仓库。
caution我们列出的每种方法都可以或确实覆盖目标目录 /mnt/gitlab/repositories 中的数据。不要混淆源和目标。

在所有情况下推荐的方法

对于 Gitaly 或 Gitaly 集群目标,应使用极狐GitLab 备份和恢复功能。 Git 仓库由 Gitaly 作为数据库访问,管理和存储在极狐GitLab 服务器上。使用 rsync 等工具直接访问和复制 Gitaly 的文件可能会导致数据丢失。

  • 从 13.3 版本开始,通过同时处理多个仓库,可以提高备份性能。
  • 可以使用跳过功能,仅从仓库创建备份。

没有其他方法适用于 Gitaly 集群目标。

目标目录为空:使用 tar 管道

对于 Gitaly 目标(对 Gitaly 集群目标使用推荐方法),如果目标目录 /mnt/gitlab/repositories 为空,最简单的做法是使用 tar 管道。这种方法的开销很低,并且 tar 几乎总是已经安装在您的系统上。

但是,无法恢复中断的 tar 管道;如果发生这种情况,则必须再次复制所有数据。

sudo -u git sh -c 'tar -C /var/opt/gitlab/git-data/repositories -cf - -- . |\
  tar -C /mnt/gitlab/repositories -xf -'

如果您想查看进度,请将 -xf 替换为 -xvf

到另一台服务器的 tar 管道

对于 Gitaly 目标(对 Gitaly 集群目标使用推荐方法),您还可以使用 tar 管道将数据复制到另一台服务器。如果您的 git 用户以 git@newserver 的身份对新服务器具有 SSH 访问权限,则可以通过 SSH 管道传输数据。

sudo -u git sh -c 'tar -C /var/opt/gitlab/git-data/repositories -cf - -- . |\
  ssh git@newserver tar -C /mnt/gitlab/repositories -xf -'

如果您想在数据通过网络之前对其进行压缩(这会花费您的 CPU 周期)您可以将 ssh 替换为 ssh -C

目标目录包含仓库的过时副本:使用 rsync

caution使用 rsync 迁移 Git 数据可能会导致数据丢失和存储库损坏。

如果目标目录已经包含仓库的部分或过时副本,则使用 tar 再次复制所有数据可能会很浪费。在这种情况下,最好对 Gitaly 目标使用 rsync(对 Gitaly 集群目标使用推荐方法)。

这个实用程序要么已经安装在您的系统上,要么可以使用 aptyum 安装。

sudo -u git  sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \
  /mnt/gitlab/repositories'

上面命令中的 /. 非常重要,如果没有它,您会在目标目录中得到错误的目录结构。 如果您想查看进度,请将 -a 替换为 -av

单个 rsync 到另一台服务器

caution使用 rsync 迁移 Git 数据可能会导致数据丢失和仓库损坏。

对于 Gitaly 目标(对 Gitaly 集群目标使用推荐方法),如果源系统上的 git 用户对目标服务器具有 SSH 访问权限,则可以将仓库使用 rsync发送到网络。

sudo -u git sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \
  git@newserver:/mnt/gitlab/repositories'

数千个 Git 仓库:每个仓库使用一个 rsync

caution使用 rsync 迁移 Git 数据可能会导致数据丢失和仓库损坏。

每次您启动 rsync 作业时,它必须:

  • 检查源目录中的所有文件。
  • 检查目标目录中的所有文件。
  • 决定是否复制文件。

如果源目录或目标目录有很多内容,则 rsync 的这个启动阶段可能会成为极狐GitLab 服务器的负担。您可以通过将其工作分成更小的部分来减少 rsync 的工作量,并一次同步一个仓库。

除了 rsync 我们使用 GNU Parallel。 极狐GitLab 中不包含此实用程序,因此您必须使用 aptyum 自行安装。

这个过程:

  • 不清理源中不再存在的目标位置的仓库。
  • 仅适用于 Gitaly 目标。对 Gitaly 集群目标使用推荐方法

极狐GitLab 已知的所有存储库的并行 rsync

caution使用 rsync 迁移 Git 数据可能会导致数据丢失和仓库损坏。

这一次将存储库与 10 个 rsync 进程同步。我们会跟踪进度,以便在必要时可以重新开始传输。

首先,我们创建一个由 git 拥有的新目录来保存传输日志。在开始传输过程之前,我们假设目录是空的,并且我们是唯一在其中写入文件的人。

# Omnibus
sudo mkdir /var/opt/gitlab/transfer-logs
sudo chown git:git /var/opt/gitlab/transfer-logs

# Source
sudo -u git -H mkdir /home/git/transfer-logs

我们使用要复制的目录列表为该过程播种。

# Omnibus
sudo -u git sh -c 'gitlab-rake gitlab:list_repos > /var/opt/gitlab/transfer-logs/all-repos-$(date +%s).txt'

# Source
cd /home/git/gitlab
sudo -u git -H sh -c 'bundle exec rake gitlab:list_repos > /home/git/transfer-logs/all-repos-$(date +%s).txt'

现在我们可以开始传输了。下面的命令是幂等的,GNU Parallel 完成的作业数应该收敛到零。如果没有,则 all-repos-1234.txt 中列出的某些仓库可能在复制之前已被删除/重命名。

# Omnibus
sudo -u git sh -c '
cat /var/opt/gitlab/transfer-logs/* | sort | uniq -u |\
  /usr/bin/env JOBS=10 \
  /opt/gitlab/embedded/service/gitlab-rails/bin/parallel-rsync-repos \
    /var/opt/gitlab/transfer-logs/success-$(date +%s).log \
    /var/opt/gitlab/git-data/repositories \
    /mnt/gitlab/repositories
'

# Source
cd /home/git/gitlab
sudo -u git -H sh -c '
cat /home/git/transfer-logs/* | sort | uniq -u |\
  /usr/bin/env JOBS=10 \
  bin/parallel-rsync-repos \
    /home/git/transfer-logs/success-$(date +%s).log \
    /home/git/repositories \
    /mnt/gitlab/repositories
`

并行 rsync 仅适用于具有最近活动的仓库

caution使用 rsync 迁移 Git 数据可能会导致数据丢失和仓库损坏。

假设您已经完成了 2015 年 10 月 1 日 12:00 UTC 之后开始的同步。然后,您可能只想同步在那之后更改的仓库。您可以使用 SINCE 变量告诉 rake gitlab:list_repos 只打印具有最近活动的仓库。

# Omnibus
sudo gitlab-rake gitlab:list_repos SINCE='2015-10-1 12:00 UTC' |\
  sudo -u git \
  /usr/bin/env JOBS=10 \
  /opt/gitlab/embedded/service/gitlab-rails/bin/parallel-rsync-repos \
    success-$(date +%s).log \
    /var/opt/gitlab/git-data/repositories \
    /mnt/gitlab/repositories

# Source
cd /home/git/gitlab
sudo -u git -H bundle exec rake gitlab:list_repos SINCE='2015-10-1 12:00 UTC' |\
  sudo -u git -H \
  /usr/bin/env JOBS=10 \
  bin/parallel-rsync-repos \
    success-$(date +%s).log \
    /home/git/repositories \
    /mnt/gitlab/repositories