正式なドキュメントは英語版であり、この日本語訳はAI支援翻訳により作成された参考用のものです。日本語訳の一部の内容は人間によるレビューがまだ行われていないため、翻訳のタイミングにより英語版との間に差異が生じることがあります。最新かつ正確な情報については、英語版をご参照ください。

ファイルエクスポートのプロジェクト移行のトラブルシューティング

  • プラン: Free、Premium、Ultimate
  • 提供形態: GitLab.com、GitLab Self-Managed、GitLab Dedicated

ファイルエクスポートを使用したプロジェクトの移行で問題が発生した場合は、以下の解決策を参照してください。

トラブルシューティングコマンド

JIDを使用してインポートのステータスおよび追加ログに関する情報を、Railsコンソールを使用して検索します:

Project.find_by_full_path('group/project').import_state.slice(:jid, :status, :last_error)
> {"jid"=>"414dec93f941a593ea1a6894", "status"=>"finished", "last_error"=>nil}
# Logs
grep JID /var/log/gitlab/sidekiq/current
grep "Import/Export error" /var/log/gitlab/sidekiq/current
grep "Import/Export backtrace" /var/log/gitlab/sidekiq/current
tail /var/log/gitlab/gitlab-rails/importer.log

プロジェクトが不一致のためインポートに失敗しました

インスタンスRunnerの有効化が、エクスポートされたプロジェクトとプロジェクトのインポート間で一致しない場合、プロジェクトのインポートは失敗します。イシュー276930を確認し、以下のいずれかを実行します:

  • ソースプロジェクトとデスティネーションプロジェクトの両方でインスタンスRunnerが有効になっていることを確認します。
  • プロジェクトをインポートする際に、親グループのインスタンスRunnerを無効にします。

インポートされたプロジェクトからユーザーが不足しています

ユーザーがインポートされたプロジェクトにインポートされていない場合は、ユーザーコントリビュートの保持要件を参照してください。

ユーザーが見つからない一般的な理由は、公開メール設定がユーザーに対して構成されていないことです。このイシューを解決するには、GitLab UIを使用してこの設定を構成するようユーザーに依頼してください。

手動での設定が現実的ではないほど多数のユーザーがいる場合は、Railsコンソールを使用して、すべてのユーザープロファイルで公開メールアドレスを使用するように設定できます:

User.where("public_email IS NULL OR public_email = '' ").find_each do |u|
  next if u.bot?

  puts "Setting #{u.username}'s currently empty public email to #{u.email}…"
  u.public_email = u.email
  u.save!
end

大規模リポジトリのインポートの回避策

最大インポートサイズの制限により、インポートが正常に完了しない場合があります。インポートの制限を変更できない場合は、ここに記載されているいずれかの回避策を試すことができます。

回避策オプション1

以下のローカルワークフローを使用して、別のインポート試行のためにリポジトリサイズを一時的に縮小できます:

  1. エクスポートから一時的な作業ディレクトリを作成します:

    EXPORT=<filename-without-extension>
    
    mkdir "$EXPORT"
    tar -xf "$EXPORT".tar.gz --directory="$EXPORT"/
    cd "$EXPORT"/
    git clone project.bundle
    
    # Prevent interference with recreating an importable file later
    mv project.bundle ../"$EXPORT"-original.bundle
    mv ../"$EXPORT".tar.gz ../"$EXPORT"-original.tar.gz
    
    git switch --create smaller-tmp-main
  2. リポジトリサイズを縮小するには、このsmaller-tmp-mainブランチで作業します: 大きなファイルを特定して削除するか、インタラクティブにリベースして修正することで、コミットの数を減らします。

    # Reduce the .git/objects/pack/ file size
    cd project
    git reflog expire --expire=now --all
    git gc --prune=now --aggressive
    
    # Prepare recreating an importable file
    git bundle create ../project.bundle <default-branch-name>
    cd ..
    mv project/ ../"$EXPORT"-project
    cd ..
    
    # Recreate an importable file
    tar -czf "$EXPORT"-smaller.tar.gz --directory="$EXPORT"/ .
  3. この新しい、より小さいファイルをGitLabにインポートします。

  4. 元のリポジトリの完全なクローンで、git remote set-url origin <new-url> && git push --force --allを使用してインポートを完了します。

  5. インポートされたリポジトリのブランチ保護ルールとそのデフォルトブランチを更新し、一時的なsmaller-tmp-mainブランチとローカルの一時データを削除します。

回避策オプション2

この回避策はLFSオブジェクトを考慮していません。

すべての変更を一度にプッシュするのではなく、この回避策は以下のことを行います:

  • プロジェクトのインポートをGitリポジトリのインポートから分離します。
  • リポジトリをGitLabに段階的にプッシュする
  1. 移行するリポジトリのローカルクローンを作成します。後のステップで、このクローンをプロジェクトエクスポートの外部にプッシュする。

  2. エクスポートをダウンロードし、Gitリポジトリを含むproject.bundleを削除します:

    tar -czvf new_export.tar.gz --exclude='project.bundle' @old_export.tar.gz
  3. Gitリポジトリなしでエクスポートをインポートします。リポジトリなしでのインポートを確認するように求められます。

  4. このbashスクリプトをファイルとして保存し、適切なoriginを追加した後に実行します。

    #!/bin/sh
    
    # ASSUMPTIONS:
    # - The GitLab location is "origin"
    # - The default branch is "main"
    # - This will attempt to push in chunks of 500 MB (dividing the total size by 500 MB).
    #   Decrease this size to push in smaller chunks if you still receive timeouts.
    
    git gc
    SIZE=$(git count-objects -v 2> /dev/null | grep size-pack | awk '{print $2}')
    
    # Be conservative and try to push 2 GB at a time
    # (given this assumes each commit is the same size - which is wrong)
    BATCHES=$(($SIZE / 500000))
    TOTAL_COMMITS=$(git rev-list --count HEAD)
    if (( BATCHES > TOTAL_COMMITS )); then
        BATCHES=$TOTAL_COMMITS
    fi
    
    INCREMENTS=$(( ($TOTAL_COMMITS / $BATCHES) - 1 ))
    
    for (( BATCH=BATCHES; BATCH>=1; BATCH-- ))
    do
      COMMIT_NUM=$(( $BATCH - $INCREMENTS ))
      COMMIT_SHA=$(git log -n $COMMIT_NUM --format=format:%H | tail -1)
      git push -u origin ${COMMIT_SHA}:refs/heads/main
    done
    git push -u origin main
    git push -u origin --all
    git push -u origin --tags

プロジェクトのインポート時にエラー: HTTP 524 A timeout occurred

GitLab.comでは、プロジェクトのインポートがHTTP 524 A timeout occurredエラーで失敗する場合があります。このエラーは、数ギガバイトのサイズのアーカイブで発生する可能性があります。

各アップロードは制限時間内に完了する必要があります。サイズの大きいアーカイブはその制限を超過する可能性があり、その場合、アップロードが完了する前に接続が閉じられます。

このエラーを回避するには、アーカイブをHTTPSロケーション(例: AWS S3バケット)でホストし、GitLabがインポート中にダウンロードするようにします。次のいずれかのエンドポイントを使用します:

GitLabがバックグラウンドでアーカイブをダウンロードするため、アーカイブのサイズがタイムアウトの原因になることはありません。

Sidekiqプロセスがプロジェクトのエクスポートに失敗しました

Sidekiqプロセスは、実行中に終了した場合など、プロジェクトのエクスポートに失敗することがあります。

GitLab.comユーザーは、このイシューを解決するためにサポートに連絡してください。

GitLab Self-Managedの管理者は、Railsコンソールを使用してSidekiqプロセスをバイパスすることで、プロジェクトのエクスポートを手動でトリガーすることができます:

project = Project.find(1)
current_user = User.find_by(username: 'my-user-name')
RequestStore.begin!
ActiveRecord::Base.logger = Logger.new(STDOUT)
params = {}

::Projects::ImportExport::ExportService.new(project, current_user, params).execute(nil)

これにより、UIを通じてエクスポートが利用可能になりますが、ユーザーへのメールはトリガーされません。プロジェクトのエクスポートを手動でトリガーする、およびメールを送信するには:

project = Project.find(1)
current_user = User.find_by(username: 'my-user-name')
RequestStore.begin!
ActiveRecord::Base.logger = Logger.new(STDOUT)
params = {}

ProjectExportWorker.new.perform(current_user.id, project.id)

エクスポートステップを手動で実行する

プロジェクトは通常、WebインターフェースまたはプロジェクトインポートおよびエクスポートAPIを介してエクスポートします。これらの方法を使用してエクスポートすると、トラブルシューティングを行うのに十分な情報が得られずに失敗する場合があります。これらの場合、Railsコンソールセッションを開き、定義されているすべてのexporterをループします。各コマンドが返すエラーを確認できるように、ブロック全体を一度に貼り付けるのではなく、各行を個別に実行してください。

# User needs to have permission to export
u = User.find_by_username('someuser')
p = Project.find_by_full_path('some/project')
e = Projects::ImportExport::ExportService.new(p,u)

e.send(:version_saver).send(:save)
e.send(:repo_saver).send(:save)
e.send(:avatar_saver).send(:save)
e.send(:project_tree_saver).send(:save)
e.send(:uploads_saver).send(:save)
e.send(:wiki_repo_saver).send(:save)
e.send(:lfs_saver).send(:save)
e.send(:snippets_repo_saver).send(:save)
e.send(:design_repo_saver).send(:save)
## continue using `e.send(:exporter_name).send(:save)` going through the list of exporters

# The following line should show you the export_path similar to /var/opt/gitlab/gitlab-rails/shared/tmp/gitlab_exports/@hashed/49/94/4994....
s = Gitlab::ImportExport::Saver.new(exportable: p, shared: p.import_export_shared, user: u)

# Prior to GitLab 17.0, the `user` parameter was not supported. If you encounter an
# error with the above or are unsure whether or not to supply the `user`
# argument, use the following check:
Gitlab::ImportExport::Saver.instance_method(:initialize).parameters.include?([:keyreq, :user])
# If the preceding check returns false, omit the user argument:
s = Gitlab::ImportExport::Saver.new(exportable: p, shared: p.import_export_shared)

# To try and upload use:
s.send(:compress_and_save)
s.send(:save_upload)

プロジェクトが正常にアップロードされると、エクスポートされたプロジェクトは/var/opt/gitlab/gitlab-rails/uploads/-/system/import_export_upload/export_file/.tar.gzファイルにあります。

エラー: PG::QueryCanceled: ERROR: canceling statement due to statement timeout

一部の移行は、PG::QueryCanceled: ERROR: canceling statement due to statement timeoutというエラーでタイムアウトすることがあります。この問題を回避する1つの方法は、移行のバッチサイズを小さくすることです。これにより、移行がタイムアウトする可能性は低くなりますが、移行は遅くなります。

バッチサイズを小さくするには、機能フラグを有効にする必要があります。詳細については、イシュー456948を参照してください。

エラー: command exited with error code 15 and Unable to save [FILTERED] into [FILTERED]

ファイルエクスポートを使用してプロジェクトを移行するときに、ログに次のエラーが表示される場合があります:

command exited with error code 15 and Unable to save [FILTERED] into [FILTERED]

このエラーは、エクスポートまたはインポート中にSidekiqがSIGTERMを受信したときに発生します。これは、多くの場合、tarコマンドの実行中に発生します。

GitLab.comやGitLab DedicatedのようなKubernetes環境では、メモリまたはディスク不足、コードデプロイ、あるいはインスタンスのアップグレードにより、オペレーティングシステムがSIGTERMシグナルをトリガーします。根本原因を特定するには、管理者がKubernetesがインスタンスを終了した理由を調査する必要があります。

非Kubernetes環境では、tarコマンドの実行中にインスタンスが終了した場合にこのエラーが発生する可能性があります。ただし、このエラーはディスク不足によるものではないため、メモリ不足が最も可能性の高い原因です。

このエラーが発生した場合:

  • ファイルをエクスポートすると、GitLabは最大再試行回数に達するまでエクスポートを再試行し、その後エクスポートを失敗としてマークします。GitLab.comの場合、インスタンスへの負荷が少ない週末にエクスポートを試してください。
  • ファイルをインポートする場合は、自分でインポートを再試行する必要があります。GitLabはインポートを自動的に再試行しません。

パフォーマンスイシューのトラブルシューティング

以下のインポート/エクスポートを使用して、現在のパフォーマンスの問題を確認してください。

OOMエラー

Out-of-memory(OOM)エラーは通常、Sidekiqメモリキラーによって引き起こされます:

SIDEKIQ_MEMORY_KILLER_MAX_RSS = 2000000
SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS = 3000000
SIDEKIQ_MEMORY_KILLER_GRACE_TIME = 900

インポートステータスがstartedであり、以下のSidekiqログはメモリイシューを示しています:

WARN: Work still in progress <struct with JID>

タイムアウト

タイムアウトエラーは、Gitlab::Import::StuckProjectImportJobsWorkerがプロセスを失敗としてマークするために発生します:

module Gitlab
  module Import
    class StuckProjectImportJobsWorker
      include Gitlab::Import::StuckImportJob
      # ...
    end
  end
end

module Gitlab
  module Import
    module StuckImportJob
      # ...
      IMPORT_JOBS_EXPIRATION = 15.hours.to_i
      # ...
      def perform
        stuck_imports_without_jid_count = mark_imports_without_jid_as_failed!
        stuck_imports_with_jid_count = mark_imports_with_jid_as_failed!

        track_metrics(stuck_imports_with_jid_count, stuck_imports_without_jid_count)
      end
      # ...
    end
  end
end
Marked stuck import jobs as failed. JIDs: xyz
  +-----------+    +-----------------------------------+
  |Export Job |--->| Calls ActiveRecord `as_json` and  |
  +-----------+    | `to_json` on all project models   |
                   +-----------------------------------+

  +-----------+    +-----------------------------------+
  |Import Job |--->| Loads all JSON in memory, then    |
  +-----------+    | inserts into the DB in batches    |
                   +-----------------------------------+

問題と解決策

データベースからのJSONの低速な読み込み/ダンプモデル:

  • ワーカーを分割する
  • バッチエクスポート
  • SQLを最適化する
  • ActiveRecordコールバックから離れる(難しい)

高いメモリ使用量(一部の分析も参照):

  • メモリ使用量を抑えるコミットの最適なポイント
  • Netflix Fast JSON APIが役立つ可能性があります
  • ディスクへのバッチ読み取り/書き込みとあらゆるSQL