管理者のためのジョブ・アーティファクト・トラブルシューティング

ジョブ・アーティファクトを管理する際に、以下のようなイシューに遭遇することがあります。

ジョブアーティファクトのディスク使用量が多すぎる

ジョブのアーティファクトが予想以上に早くディスク容量をいっぱいにしてしまうことがあります。考えられる理由は以下の通りです:

このようなケースやその他のケースでは、ディスク領域の使用に最も責任があるプロジェクトを特定し、どのタイプのアーティファクトが最も領域を使用しているかを把握し、場合によっては手動でジョブのアーティファクトを削除してディスク領域を取り戻します。

アーティファクトのハウスキーピング

アーティファクトのハウスキーピングは、どのアーティファクトが期限切れで削除可能かを特定するプロセスです。

GitLab 14.6 から 15.2 ではハウスキーピングは無効です。

アーティファクトのハウスキーピングはGitLab 14.6では無効になっていました。GitLab 14.10で大幅に改善され、その変更はGitLab 14.6以降のパッチバージョンにバックポートされ、デフォルトで無効にされた機能フラグの背後に導入されました。フラグはGitLab 15.3でデフォルトで有効になりました。

もしGitLab 14.6からGitLab 15.2でアーティファクトのハウスキーピングが機能していないようであれば、機能フラグが有効になっているかどうかを確認する必要があります。

機能フラグが有効になっているか確認するには:

  1. Railsコンソールを起動します。

  2. 機能フラグが有効になっているか確認します。

    • GitLab 14.10 以前:

       Feature.enabled?(:ci_detect_wrongly_expired_artifacts, default_enabled: :yaml)
       Feature.enabled?(:ci_update_unlocked_job_artifacts, default_enabled: :yaml)
       Feature.enabled?(:ci_job_artifacts_backlog_work, default_enabled: :yaml)
      
    • GitLab 15.0 以降:

       Feature.enabled?(:ci_detect_wrongly_expired_artifacts)
       Feature.enabled?(:ci_update_unlocked_job_artifacts)
       Feature.enabled?(:ci_job_artifacts_backlog_work)
      
  3. 機能フラグが無効になっている場合は、有効にしてください:

    Feature.enable(:ci_detect_wrongly_expired_artifacts)
    Feature.enable(:ci_update_unlocked_job_artifacts)
    Feature.enable(:ci_destroy_unlocked_job_artifacts)
    

これらの変更には、アーティファクトを保持すべき場合、unlocked からlocked に切り替えることが含まれます。

unknown ステータスのアーティファクト

ハウスキーピングが更新される前に作成されたアーティファクトは、unknown のステータスを持ちます。有効期限が切れた後、これらのアーティファクトは新しいハウスキーピングでは処理されません。

インスタンスにunknown ステータスのアーティファクトがあるかどうかを確認するには、データベースをチェックできます:

  1. データベース・コンソールを起動します:

    Linux package (Omnibus)
    sudo gitlab-psql
    
    Helm chart (Kubernetes)
    # Find the toolbox pod
    kubectl --namespace <namespace> get pods -lapp=toolbox
    # Connect to the PostgreSQL console
    kubectl exec -it <toolbox-pod-name> -- /srv/gitlab/bin/rails dbconsole --include-password --database main
    
    Docker
    sudo docker exec -it <container_name> /bin/bash
    gitlab-psql
    
    Self-compiled (source)
    sudo -u git -H psql -d gitlabhq_production
    
  2. 次のクエリを実行します:

    select expire_at, file_type, locked, count(*) from ci_job_artifacts
    where expire_at is not null and
    file_type != 3
    group by expire_at, file_type, locked having count(*) > 1;
    

レコードが返された場合は、ハウスキーピング・ジョブが処理できないアーティファクトがあります。例えば

           expire_at           | file_type | locked | count
-------------------------------+-----------+--------+--------
 2021-06-21 22:00:00+00        |         1 |      2 |  73614
 2021-06-21 22:00:00+00        |         2 |      2 |  73614
 2021-06-21 22:00:00+00        |         4 |      2 |   3522
 2021-06-21 22:00:00+00        |         9 |      2 |     32
 2021-06-21 22:00:00+00        |        12 |      2 |    163

ロックされたステータス2 を持つアーティファクトはunknown です。詳細はイシュー#346261を確認してください。

unknown アーティファクトのクリーンアップ

すべてのunknown アーティファクトを処理する Sidekiq ワーカーは、GitLab 15.3 以降ではデフォルトで有効になっています。上記のデータベースクエリによって返されたアーティファクトを分析し、どれがlockedunlockedかを判断します。アーティファクトは必要に応じてこのワーカーによって削除されます。

このワーカーは、GitLab 14.10以降を実行しているセルフマネージド・インスタンスで有効にすることができます:

  1. Railsコンソールを起動します。

  2. 機能が有効になっているか確認します。

    • GitLab 14.10:

       Feature.enabled?(:ci_job_artifacts_backlog_work, default_enabled: :yaml)
      
    • GitLab 15.0 以降:

       Feature.enabled?(:ci_job_artifacts_backlog_work)
      
  3. 必要に応じて機能を有効にしてください:

    Feature.enable(:ci_job_artifacts_backlog_work)
    

ワーカーは7分ごとに10,000unknown アーティファクトを処理し、24時間でおよそ200万を処理します。

関連するci_job_artifacts_backlog_large_loop_limit 機能フラグがあり、ワーカーはunknown アーティファクトを5 倍の大きさのバッチで処理します。このフラグはセルフマネージドインスタンスでの使用はお勧めしません。

特定の有効期限がある (または有効期限がない) アーティファクトを含むプロジェクトとビルドの一覧表示

Railsコンソールを使うと、どちらかのジョブアーティファクトを持つプロジェクトを見つけることができます:

  • 有効期限がありません。
  • 7日以上先の有効期限。

アーティファクトの削除と同様に、以下の時間枠の例を使用し、必要に応じて変更してください:

  • 7.days.from_now
  • 10.days.from_now
  • 2.weeks.from_now
  • 3.months.from_now

以下の各スクリプトも、.limit(50) 、検索結果を50件に制限していますが、この数は必要に応じて変更することもできます:

# Find builds & projects with artifacts that never expire
builds_with_artifacts_that_never_expire = Ci::Build.with_downloadable_artifacts.where(artifacts_expire_at: nil).limit(50)
builds_with_artifacts_that_never_expire.find_each do |build|
  puts "Build with id #{build.id} has artifacts that don't expire and belongs to project #{build.project.full_path}"
end

# Find builds & projects with artifacts that expire after 7 days from today
builds_with_artifacts_that_expire_in_a_week = Ci::Build.with_downloadable_artifacts.where('artifacts_expire_at > ?', 7.days.from_now).limit(50)
builds_with_artifacts_that_expire_in_a_week.find_each do |build|
  puts "Build with id #{build.id} has artifacts that expire at #{build.artifacts_expire_at} and belongs to project #{build.project.full_path}"
end

保存されているジョブのアーティファクトの合計サイズでプロジェクトをリストします。

Railsコンソール(sudo gitlab-rails console)で以下のコードを実行することで、保存されているジョブアーティファクトの合計サイズ順に上位20プロジェクトをリストアップします:

include ActionView::Helpers::NumberHelper
ProjectStatistics.order(build_artifacts_size: :desc).limit(20).each do |s|
  puts "#{number_to_human_size(s.build_artifacts_size)} \t #{s.project.full_path}"
end

.limit(20) を変更することで、表示するプロジェクトの数を変更できます。

単一プロジェクトで最大のアーティファクトをリストアップ

Railsコンソール(sudo gitlab-rails console)で以下のコードを実行することで、1つのプロジェクトで最大のジョブアーティファクト50個をリストアップします:

include ActionView::Helpers::NumberHelper
project = Project.find_by_full_path('path/to/project')
Ci::JobArtifact.where(project: project).order(size: :desc).limit(50).map { |a| puts "ID: #{a.id} - #{a.file_type}: #{number_to_human_size(a.size)}" }

.limit(50) を好きな数に変更することで、リストアップされるジョブアーティファクトの数を変更できます。

単一プロジェクトのアーティファクトをリストアップ

単一のプロジェクトのアーティファクトを、アーティファクトのサイズ順に一覧表示します。出力には

  • アーティファクトを作成したジョブのID
  • アーティファクトサイズ
  • アーティファクト・ファイル・タイプ
  • アーティファクト作成日
  • アーティファクトのディスク上の場所
p = Project.find_by_id(<project_id>)
arts = Ci::JobArtifact.where(project: p)

list = arts.order(size: :desc).limit(50).each do |art|
    puts "Job ID: #{art.job_id} - Size: #{art.size}b - Type: #{art.file_type} - Created: #{art.created_at} - File loc: #{art.file}"
end

表示されるジョブのアーティファクトの数を変更するには、limit(50) の数字を変更します。

特定の日付より前に完了したジョブのアーティファクトを削除します。

caution
これらのコマンドは、データベースとストレージからデータを永久に削除します。これらのコマンドを実行する前に、サポートエンジニアのガイダンスを求めるか、念のためインスタンスのバックアップをリストアできる状態にしてテスト環境で実行することを強くお勧めします。

複数のジョブのジョブログを保持したまま、そのジョブに関連するアーティファクトを手動で削除する必要がある場合は、Rails コンソール (sudo gitlab-rails console) から行うことができます:

  1. 削除するジョブを選択します:

    1 つのプロジェクトのアーティファクトを含むすべてのジョブを選択します:

    project = Project.find_by_full_path('path/to/project')
    builds_with_artifacts =  project.builds.with_downloadable_artifacts
    

    GitLab インスタンス全体のアーティファクトを持つすべてのジョブを選択するには:

    builds_with_artifacts = Ci::Build.with_downloadable_artifacts
    
  2. 特定の日付より古いジョブのアーティファクトを削除します:

    note
    このステップでは、ユーザーが「保持」を選択したアーティファクトも消去されます。
    builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.week.ago)
    builds_to_clear.find_each do |build|
      Ci::JobArtifacts::DeleteService.new(build).execute
      build.update!(artifacts_expire_at: Time.now)
    end
    

    GitLab 15.3以前では、代わりに次のようにしてください:

    builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.week.ago)
    builds_to_clear.find_each do |build|
      build.artifacts_expire_at = Time.now
      build.erase_erasable_artifacts!
    end
    

    1.week.ago はRailsのActiveSupport::Duration メソッドで、過去の新しい日付や時刻を計算します。他の有効な例は次のとおりです:

    • 7.days.ago
    • 3.months.ago
    • 1.year.ago

    erase_erasable_artifacts! は同期メソッドで、実行されるとアーティファクトは直ちに削除されます。

特定の日付より前に完了したジョブのアーティファクトとログの削除

caution
これらのコマンドは、データベースとディスクの両方からデータを永久に削除します。これらのコマンドを実行する前に、サポート・エンジニアのガイダンスを求めるか、念のためインスタンスのバックアップをリストアできる状態にしてテスト環境で実行することを強くお勧めします。

ジョブログを含め、複数のジョブに関連するすべてのジョブアーティファクトを手動で削除する必要がある場合は、Rails コンソール (sudo gitlab-rails console) から行うことができます:

  1. 削除するジョブを選択します:

    単一のプロジェクトのアーティファクトを含むジョブを選択します:

    project = Project.find_by_full_path('path/to/project')
    builds_with_artifacts =  project.builds.with_downloadable_artifacts
    

    GitLab インスタンス全体のアーティファクトを持つジョブを選択するには:

    builds_with_artifacts = Ci::Build.with_downloadable_artifacts
    

    時折、アーティファクトを持つジョブを選択する際に、大量の行を選択するためにプロセスが終了してしまう危険性があります。その結果、メモリの使用量が多くなり、最終的には Out-of-Memory(OOM) エラーによってプロセスが終了してしまう可能性があります。これを解決するには、バッチを小分けにして実行します。以下の例では、各バッチを1000に制限しています。

    単一のプロジェクトのアーティファクトを含むジョブを選択します:

    project = Project.find_by_full_path('path/to/project')
    builds_with_artifacts =  project.builds.with_downloadable_artifacts.find_each(batch_size: 1000)
    

    GitLab インスタンス全体のアーティファクトを持つジョブを選択するには:

    builds_with_artifacts = Ci::Build.with_downloadable_artifacts.find_each(batch_size: 1000)
    
  2. Web UI でジョブを消去しているユーザーを選択します:

    admin_user = User.find_by(username: 'username')
    
  3. 特定の日付より古いジョブのアーティファクトとログを消去します:

    builds_to_clear = builds_with_artifacts.where("finished_at < ?", 1.week.ago)
    builds_to_clear.find_each do |build|
      print "Ci::Build ID #{build.id}... "
       
      if build.erasable?
        Ci::BuildEraseService.new(build, admin_user).execute
        puts "Erased"
      else
        puts "Skipped (Nothing to erase or not erasable)"
      end
    end
    

    GitLab 15.3 以前ではCi::BuildEraseService.new(build, admin_user).executebuild.erase(erased_by: admin_user)に置き換えてください。

    1.week.ago はRailsのActiveSupport::Duration メソッドで、過去の新しい日付や時刻を計算します。他の有効な例は次のとおりです:

    • 7.days.ago
    • 3.months.ago
    • 1.year.ago

ジョブアーティファクトのアップロードがエラー500で失敗します。

アーティファクトにオブジェクトストレージを使用していて、ジョブアーティファクトのアップロードに失敗した場合は、レビューしてください:

  • ジョブ・ログに次のようなエラー・メッセージが表示されます:

     WARNING: Uploading artifacts as "archive" to coordinator... failed id=12345 responseStatus=500 Internal Server Error status=500 token=abcd1234
    
  • Workhorseログに以下のようなエラーメッセージが表示されます:

     {"error":"MissingRegion: could not find region configuration","level":"error","msg":"error uploading S3 session","time":"2021-03-16T22:10:55-04:00"}
    

どちらの場合も、ジョブアーティファクトオブジェクトストレージ設定にregion

ジョブ・アーティファクトのアップロードに失敗します。500 Internal Server Error (Missing file)

フォルダパスを含むバケット名は、連結オブジェクトストレージではサポートされていません。例えば、bucket/path。バケツ名にパスが含まれている場合、以下のようなエラーが発生する可能性があります:

WARNING: Uploading artifacts as "archive" to coordinator... POST https://gitlab.example.com/api/v4/jobs/job_id/artifacts?artifact_format=zip&artifact_type=archive&expire_in=1+day: 500 Internal Server Error (Missing file)
FATAL: invalid argument

連結オブジェクトストレージを使用しているときに、ジョブアーティファクトが上記のエラーでアップロードに失敗する場合は、データ型ごとに別々のバケットを使用していることを確認してください。

Windows マウントを使用している場合、アーティファクトがFATAL: invalid argument でアップロードに失敗します。

ジョブのアーティファクトに CIFS で Windows マウントを使用している場合、ランナーがアーティファクトをアップロードしようとするとinvalid argument エラーが表示されることがあります:

WARNING: Uploading artifacts as "dotenv" to coordinator... POST https://<your-gitlab-instance>/api/v4/jobs/<JOB_ID>/artifacts: 500 Internal Server Error  id=1296 responseStatus=500 Internal Server Error status=500 token=*****
FATAL: invalid argument

このイシューを回避するには、以下をお試しください:

  • CIFSの代わりにext4マウントに切り替えます。
  • CIFSファイルリースに関連する多くの重要なバグフィックスが含まれるLinuxカーネル5.15以上にアップグレードすること。
  • 古いカーネルでは、nolease マウントオプションを使用してファイルリースを無効にします。

詳細については、調査の詳細を参照してください。

使用クォータでアーティファクト・ストレージの使用量が正しく表示されない

GitLab 14.10で導入されました

アーティファクトのストレージ使用量に、アーティファクトが使用するストレージ容量の合計が正しく表示されないことがありました。インスタンス内の全てのプロジェクトのアーティファクト使用統計を再計算するには、このバックグラウンドスクリプトを実行します:

gitlab-rake gitlab:refresh_project_statistics_build_artifacts_size[https://example.com/path/file.csv]

https://example.com/path/file.csv ファイルには、アーティファクト ストレージ使用量を再計算するすべてのプロジェクトのプロジェクト ID をリストする必要があります。フ ァ イ ルには こ の形式を使用 し ます:

PROJECT_ID
1
2

アーティファクト使用量の値は、スクリプトの実行中に0 に変動することがあります。再計算後、使用量は予想どおりに表示されるはずです。