GitLabで管理されているリポジトリの移動

GitLabで管理しているすべてのリポジトリを別のファイルシステムや別のサーバーに移動することができます。

GitLabインスタンス内のデータの移動

GitLab APIはGitリポジトリを移動するための推奨方法です:

  • サーバー間
  • 異なるストレージ間
  • シングルノードからGitalyクラスタへ。

詳細については

  • Gitalyのための追加ストレージの設定。この例では、storage1storage2 という追加のストレージを設定します。
  • API ドキュメントには、プロジェクトリポジトリのクエリと移動のスケジューリングのためのエンドポイントの詳細が記載されています。
  • APIドキュメントでは、スニペットリポジトリの移動に関するクエリやスケジューリングのエンドポイントについて詳しく説明しています。
  • APIドキュメントでは、グループリポジトリの移動のクエリとスケジューリングのエンドポイントを詳しく説明しています。 .
  • Gitaly Clusterへのマイグレーション

リポジトリの移動

GitLabリポジトリはプロジェクト、グループ、スニペットと関連付けることができます。これらのタイプはそれぞれ、リポジトリを移動するスケジュールを立てるための個別のAPIを持っています。GitLabインスタンス上のすべてのリポジトリを移動するには、それぞれのストレージに対してこれらのタイプの移動スケジュールを設定する必要があります。

caution
GitLabバージョン13.12から14.1でGitalyクラスタにリポジトリを移動するには、gitaly_replicate_repository_direct_fetch 機能フラグを有効にする必要があります。
caution
すでにGitalyクラスターに保存されているプロジェクトをそのクラスターに戻そうとする/projects/:project_id/repository_storage_moves の呼び出しによって、リポジトリが永久に削除される可能性があります。詳細はこのイシューを参照してください。このイシューは GitLab 14.3.0 で修正され、14.2.4,14.1.6,14.0.11,13.12.12にバックポートされました。

各リポジトリは移動の間、読み取り専用になります。リポジトリは移動が完了するまで書き込みできません。

リポジトリを移動するには

  1. ローカルとクラスターのすべてのストレージがGitLab インスタンスからアクセス可能であることを確認します。この例では、これらは<original_storage_name><cluster_storage_name> です。
  2. リポジトリストレージの重み付けを設定し、新しいストレージがすべての新しいプロジェクトを受け取るようにします。これにより、マイグレーションが進行している間、既存のストレージに新しいプロジェクトが作成されなくなります。
  3. リポジトリ移動のスケジュールを設定します:
  4. Geoが有効な場合、すべてのリポジトリを再同期します。

すべてのプロジェクトを移動

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. 直近のリポジトリの移動をクエリします。応答は次のいずれかを示します:
    • 移動は正常に完了しました。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. 直近のリポジトリの移動をクエリします。応答は次のいずれかを示します:
    • 移動は正常に完了しました。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 にコピーする方法をいくつか見ていきます。

3つのシナリオを見てみましょう:

  • ターゲットディレクトリが空の場合。
  • ターゲットディレクトリにリポジトリの古いコピーが含まれています。
  • 何千ものリポジトリに対処する方法。

/mnt/gitlab/repositories ここで挙げた各アプローチは、ターゲットディレクトリ/mnt/gitlab/repositoriesのデータを上書きする可能性があります。ソースとターゲットを混同しないでください。

GitalyまたはGitaly Clusterターゲットのいずれについても、GitLabのバックアップとリストア機能を使用する必要があります。Gitリポジトリは、GitalyによってGitLabサーバー上でデータベースとしてアクセス、管理、保存されます。rsync のようなツールを使ってGitalyファイルに直接アクセスし、コピーすると、データ損失が発生する可能性があります。

Gitalyクラスターターゲットでは他の方法は使えません。

ターゲット・ディレクトリが空です:tar パイプを使用してください。

Gitalyターゲット(Gitalyクラスターターゲットには推奨アプローチを使用)の場合、ターゲットディレクトリ/mnt/gitlab/repositories が空の場合、最も簡単なのはtar パイプを tar使用することです。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 -'

もし、データを圧縮してからネットワークに流したい場合は、sshssh -C に置き換えてください。

ターゲット・ディレクトリにはリポジトリの古いコピーが含まれます。rsync

caution
rsync を使って Git データをマイグレーションすると、データの損失やリポジトリの破損を引き起こす可能性があります。rsyncこれらの手順はレビュー中rsyncです。

移行先のディレクトリにすでにリポジトリの一部または古いコピーが含まれている場合、tar を使ってすべてのデータを再度コピーするのは無駄な場合があります。このシナリオでは、Gitaly ターゲットにはrsync を使う方がよいでしょう(Gitaly Cluster ターゲットには推奨される方法を使用してください)。

このユーティリティは、すでにシステムにインストールされているか、apt またはyum を使用してインストール可能です。

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

上記のコマンドの/. は非常にインポートで、これがないとターゲット・ディレクトリのディレクトリ構造がおかしくなります。進捗を確認したい場合は、-a-avに置き換えてください。

rsync を別のサーバーにシングルコピーします。

caution
rsync を使って Git データをマイグレーションすると、データの損失やリポジトリの破損を引き起こす可能性があります。rsyncこれらの手順はレビュー中rsyncです。

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
Rake タスクgitlab:list_repos は GitLab 16.4 で非推奨となり、17.0 では削除される予定です。代わりにbackup and restoreを使ってください。
caution
rsync を使って Git データをマイグレーションすると、データの損失やリポジトリの破損を引き起こす可能性があります。これらの手順はレビュー中です。

rsync ジョブを開始するたびに、ジョブは実行されなければなりません:

  • ソース・ディレクトリのすべてのファイルを検査します。
  • ターゲットディレクトリのすべてのファイルを検査します。
  • ファイルをコピーするかどうかを決定します。

ソースディレクトリやターゲットディレクトリに多くのコンテンツがある場合、rsync GitLabサーバーにとって rsyncこの起動フェーズがrsync 負担になることがあります rsync。作業を小分けにして、一度にひとつのリポジトリを同期することで、GitLabrsync サーバーの負担を rsync減らすことができます。

rsync に加えて、GNU Parallelsを使います。このユーティリティはGitLabには含まれていないので、apt またはyumを使って自分でインストールする必要があります。

このプロセスは

  • ソースに存在しなくなったリポジトリをターゲットの場所にクリーンアップしません。
  • Gitalyターゲットでのみ動作します。Gitalyクラスターターゲットには推奨アプローチを使用してください。

GitLabに知られているすべてのリポジトリのParallelsrsync

caution
Rake タスクgitlab:list_repos は GitLab 16.4 で非推奨となり、17.0 では削除される予定です。代わりにbackup and restoreを使ってください。
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 Parallelsが実行したジョブの数はゼロに収束するはずです。収束しない場合は、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
`

Parallelsrsync 最近アクティビティがあったリポジトリのみを対象とします。

caution
Rake タスクgitlab:list_repos は GitLab 16.4 で非推奨となり、17.0 では削除される予定です。代わりにbackup and restoreを使ってください。
caution
rsync を使って Git データをマイグレーションすると、データの損失やリポジトリの破損を引き起こす可能性があります。これらの手順はレビュー中です。

2015-10-1 12:00 UTC 以降に開始した同期を既に一度行ったとします。その後に GitLab を使って変更されたリポジトリだけを同期したいかもしれません。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