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

リソースグループ

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

デフォルトでは、GitLab CI/CDのパイプラインは複数同時に実行されます。並行処理は、マージリクエストのフィードバックループを改善するうえで重要な要素ですが、デプロイメントジョブの並行処理を制限して、一度に1つずつ実行したい場合があります。リソースグループを使用すると、ジョブの並行処理を戦略的に制御し、継続的デプロイメントワークフローを安全に最適化できます。

リソースグループを追加する

リソースグループに追加できるリソースは1つのみです。

次のようなパイプライン設定(リポジトリ内の.gitlab-ci.ymlファイル)があるとします:

build:
  stage: build
  script: echo "Your build script"

deploy:
  stage: deploy
  script: echo "Your deployment script"
  environment: production

ブランチに新しいコミットをプッシュするたびに、2つのジョブbuilddeployを持つ新しいパイプラインが実行されます。ただし、短い間隔で複数のコミットをプッシュすると、複数のパイプラインが同時に実行を開始します。次に例を示します:

  • 最初のパイプラインはジョブbuild -> deployを実行します。
  • 2番目のパイプラインはジョブbuild -> deployを実行します。

この場合、異なるパイプラインにまたがるdeployジョブがproduction環境で同時に実行されるおそれがあります。同じインフラストラクチャで複数のデプロイスクリプトを実行すると、インスタンスに悪影響や混乱をもたらし、最悪の場合、破損状態に陥る可能性があります。

deployジョブを一度に1つずつ実行するには、並行処理の影響を受けやすいジョブにresource_groupキーワードを指定します:

deploy:
  # ...
  resource_group: production

この設定により、デプロイの安全性を確保しつつ、パイプラインの効率性を最大化するために複数のbuildジョブを同時に実行できます。

前提要件

処理モード

デプロイ設定に合わせてジョブの並行処理を制御するために、処理モードを選択できます。次のモードがサポートされています:

処理モード説明使用するケース
unorderedデフォルトの処理モードです。ジョブの実行準備が整うと、すぐにジョブを処理します。ジョブの実行順序が重要でない場合。最も使いやすいオプションです。
oldest_firstリソースが空くと、パイプラインIDを昇順に並べた実行待ちジョブのリストから、最初のジョブを選択します。最も古いパイプラインのジョブから順に実行したい場合。unorderedモードよりも効率は下がりますが、継続的デプロイではより安全です。
newest_firstリソースが空くと、パイプラインIDを降順に並べた実行待ちジョブのリストから、最初のジョブを選択します。最新のパイプラインのジョブを実行し、古いデプロイメントジョブの実行を防ぎたい場合。各ジョブがべき等(同じ操作を繰り返し実行しても結果が同じ)でなければなりません。
newest_ready_firstリソースが空くと、このリソースでの実行待ちジョブのリストから、最初のジョブを選択します。ジョブは、パイプラインIDの降順でソートされています。newest_firstが現在のパイプラインをデプロイする前に新しいパイプラインを優先するのを防ぎたい場合。newest_firstよりも高速です。各ジョブがべき等(同じ操作を繰り返し実行しても結果が同じ)でなければなりません。

処理モードを変更する

リソースグループの処理モードを変更するには、APIを使用してprocess_modeを指定し、既存のリソースグループを編集するリクエストを送信する必要があります:

  • unordered
  • oldest_first
  • newest_first
  • newest_ready_first

処理モード間の違いの例

次の.gitlab-ci.ymlについて考えてみましょう。これには、buildジョブとdeployジョブがあります。各ジョブは独自のステージで実行され、deployジョブには、productionに設定されたリソースグループがあります:

build:
  stage: build
  script: echo "Your build script"

deploy:
  stage: deploy
  script: echo "Your deployment script"
  environment: production
  resource_group: production

3つのコミットが短い間隔でプロジェクトにプッシュされると、3つのパイプラインがほぼ同時に実行されることになります:

  • 最初のパイプラインはジョブbuild -> deployを実行します。このデプロイメントジョブをdeploy-1とします。
  • 2番目のパイプラインはジョブbuild -> deployを実行します。このデプロイメントジョブをdeploy-2とします。
  • 3番目のパイプラインはジョブbuild -> deployを実行します。このデプロイメントジョブをdeploy-3とします。

リソースグループの処理モードに応じて、次のように動作します:

  • 処理モードがunorderedの場合:
    • deploy-1deploy-2deploy-3は同時には実行されません。
    • ジョブの実行順序は保証されません。たとえば、deploy-1deploy-3より先に実行される場合も、後に実行される場合もあります。
  • 処理モードがoldest_firstの場合:
    • deploy-1deploy-2deploy-3は同時には実行されません。
    • deploy-1が最初に実行され、次にdeploy-2、最後にdeploy-3が実行されます。
  • 処理モードがnewest_firstの場合:
    • deploy-1deploy-2deploy-3は同時には実行されません。
    • deploy-3が最初に実行され、次にdeploy-2、最後にdeploy-1が実行されます。

クロスプロジェクト/親子パイプラインによるパイプラインレベルの並行処理制御

並行処理に影響されやすいダウンストリームパイプラインに対してresource_groupを定義できます。triggerキーワードはダウンストリームパイプラインをトリガーでき、resource_groupキーワードはそれと併用できます。resource_groupはデプロイメントパイプラインの並行処理を制御するのに効率的であり、他のジョブは引き続き同時に実行できます。

次の例では、1つのプロジェクトに2つのパイプライン設定があります。パイプラインの実行が開始されると、並行処理の影響を受けにくいジョブが最初に実行され、他のパイプラインの並行処理の影響を受けません。ただし、GitLabは、他のデプロイメントパイプラインが実行中でないことを確認してから、デプロイメント(子)パイプラインをトリガーします。他のデプロイメントパイプラインが実行中であれば、GitLabはこれらのパイプラインが完了するまで待機してから、別のパイプラインを実行します。

# .gitlab-ci.yml (parent pipeline)

build:
  stage: build
  script: echo "Building..."

test:
  stage: test
  script: echo "Testing..."

deploy:
  stage: deploy
  trigger:
    include: deploy.gitlab-ci.yml
    strategy: mirror
  resource_group: AWS-production
# deploy.gitlab-ci.yml (child pipeline)

stages:
  - provision
  - deploy

provision:
  stage: provision
  script: echo "Provisioning..."

deployment:
  stage: deploy
  script: echo "Deploying..."
  environment: production

trigger:strategyを定義して、ダウンストリームパイプラインが完了するまでロックが解除されないようにする必要があります。

トラブルシューティング

パイプライン設定でデッドロックを回避する

oldest_first処理モードでは、ジョブをパイプライン順に強制的に実行するため、他のCI機能とうまく連携しない場合があります。

たとえば、親パイプラインと同じリソースグループを必要とする子パイプラインを実行すると、デッドロックが発生する可能性があります。以下は不適切な設定の例です:

# BAD
test:
  stage: test
  trigger:
    include: child-pipeline-requires-production-resource-group.yml
    strategy: mirror

deploy:
  stage: deploy
  script: echo
  resource_group: production
  environment: production

親パイプラインでは、testジョブを実行し、その後に子パイプラインを実行します。strategy: mirrorオプションにより、testジョブは子パイプラインが完了するまで待機します。次のステージで、親パイプラインはdeployジョブを実行しますが、このジョブはproductionリソースグループのリソースを必要とします。処理モードがoldest_firstの場合、最も古いパイプラインからジョブが実行されます。つまり、次に実行されるのはdeployジョブになります。

ところが、子パイプラインもproductionリソースグループのリソースを必要とします。子パイプラインは親パイプラインよりも新しいため、deployジョブが完了するまで待機します。しかし、このジョブが完了することはありません。

この場合、代わりに親パイプラインの設定でresource_groupキーワードを指定する必要があります:

# GOOD
test:
  stage: test
  trigger:
    include: child-pipeline.yml
    strategy: mirror
  resource_group: production # Specify the resource group in the parent pipeline

deploy:
  stage: deploy
  script: echo
  resource_group: production
  environment: production

ジョブがWaiting for resourceで停止する

ジョブがWaiting for resource: <resource_group>(リソース待機中)というメッセージでハングすることがあります。解決するには、まずリソースグループが正しく動作していることを確認します:

  1. ジョブの詳細ページに移動します。

  2. リソースがジョブに割り当てられている場合は、現在リソースを使用しているジョブを表示を選択し、ジョブステータスを確認します。

    • ステータスがrunningまたはpendingの場合、この機能は正常に動作しています。ジョブが完了してリソースをリリースするまで待ちます。
    • ステータスがcreatedであり、処理モード古い順または新しい順のいずれかである場合、この機能は正しく動作しています。ジョブのパイプラインページにアクセスし、どのアップストリームステージまたはジョブが実行をブロックしているかを確認します。
    • 前述の条件に当てはまらない場合、この機能が正しく動作していない可能性があります。GitLabにイシューを報告してください。
  3. 現在リソースを使用しているジョブを表示が利用できない場合、リソースはジョブに割り当てられていません。代わりに、リソースの実行待ちジョブを確認します。

    1. REST APIでリソースの実行待ちジョブを取得します。
    2. リソースグループの処理モード古い順であることを確認します。
    3. 実行待ちジョブのリストで最初のジョブを見つけ、GraphQLでそのジョブの詳細を取得します。
    4. 最初のジョブのパイプラインが古いパイプラインの場合は、そのパイプラインまたはジョブ自体をキャンセルしてみてください。
    5. オプション。次の実行待ちジョブが、実行されなくなった古いパイプラインに属している場合は、このプロセスを繰り返します。
    6. 問題が解決しない場合は、GitLabにイシューを報告してください。

複雑またはビジーなパイプラインでの競合状態

前述の方法でイシューを解決できない場合は、既知の競合状態の問題が発生している可能性があります。競合状態は、複雑またはビジーなパイプラインで発生します。たとえば、次のような場合に競合状態が発生する可能性があります:

  • パイプラインに複数の子パイプラインが存在する
  • 単一のプロジェクトで複数のパイプラインが同時に実行されている

このイシューが発生していると思われる場合は、GitLabにイシューを報告し、新しいイシューへのリンクを付けてイシュー436988にコメントを残してください。問題を確認するために、GitLabからパイプライン全体の設定などの追加の詳細を求められる場合があります。

一時的な回避策として、次のことができます:

  • 新しいパイプラインを開始する。

  • スタックしたジョブと同じリソースグループを持つ完了したジョブを再実行する。

    たとえば、同じリソースグループに属するsetup_jobdeploy_jobがある場合、deploy_jobwaiting for resourceで停滞している間に、setup_jobが完了する可能性があります。この場合、setup_jobを再起動してプロセス全体を再開し、deploy_jobを完了させることができます。

GraphQLを介してジョブの詳細を取得する

GraphQL APIからジョブ情報を取得できます。クロスプロジェクト/親子パイプラインによるパイプラインレベルの並行処理制御を使用する場合は、UIからはトリガージョブにアクセスできないため、GraphQL APIを使用する必要があります。

GraphQL APIからジョブ情報を取得するには、次のようにします:

  1. パイプラインの詳細ページに移動します。

  2. ジョブタブを選択し、スタックしたジョブのIDを見つけます。

  3. インタラクティブGraphQLエクスプローラーに移動します。

  4. 次のクエリを実行します:

    {
      project(fullPath: "<fullpath-to-your-project>") {
        name
        job(id: "gid://gitlab/Ci::Build/<job-id>") {
          name
          status
          detailedStatus {
            action {
              path
              buttonTitle
            }
          }
        }
      }
    }

    job.detailedStatus.action.pathフィールドには、リソースを使用しているジョブのIDが含まれています。

  5. 次のクエリを実行し、前述の基準に従ってjob.statusフィールドを確認します。pipeline.pathフィールドからパイプラインページにアクセスすることもできます。

    {
      project(fullPath: "<fullpath-to-your-project>") {
        name
        job(id: "gid://gitlab/Ci::Build/<job-id-currently-using-the-resource>") {
          name
          status
          pipeline {
            path
          }
        }
      }
    }

イシューを報告する

次の情報を含む新しいイシューをオープンします:

  • 影響を受けたジョブのID

  • ジョブステータス

  • 問題の発生頻度

  • 問題を再現する手順

    サポートに連絡して、さらに支援を受けたり、開発チームとやり取りしたりすることもできます。