リソースグループ
- プラン: 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つのジョブbuildとdeployを持つ新しいパイプラインが実行されます。ただし、短い間隔で複数のコミットをプッシュすると、複数のパイプラインが同時に実行を開始します。次に例を示します:
- 最初のパイプラインはジョブ
build->deployを実行します。 - 2番目のパイプラインはジョブ
build->deployを実行します。
この場合、異なるパイプラインにまたがるdeployジョブがproduction環境で同時に実行されるおそれがあります。同じインフラストラクチャで複数のデプロイスクリプトを実行すると、インスタンスに悪影響や混乱をもたらし、最悪の場合、破損状態に陥る可能性があります。
deployジョブを一度に1つずつ実行するには、並行処理の影響を受けやすいジョブにresource_groupキーワードを指定します:
deploy:
# ...
resource_group: productionこの設定により、デプロイの安全性を確保しつつ、パイプラインの効率性を最大化するために複数のbuildジョブを同時に実行できます。
前提要件
- GitLab CI/CDパイプラインに関する知識
- GitLab環境とデプロイに関する知識
- CI/CDパイプラインを設定するには、プロジェクトのデベロッパーロール以上が必要です。
処理モード
デプロイ設定に合わせてジョブの並行処理を制御するために、処理モードを選択できます。次のモードがサポートされています:
| 処理モード | 説明 | 使用するケース |
|---|---|---|
unordered | デフォルトの処理モードです。ジョブの実行準備が整うと、すぐにジョブを処理します。 | ジョブの実行順序が重要でない場合。最も使いやすいオプションです。 |
oldest_first | リソースが空くと、パイプラインIDを昇順に並べた実行待ちジョブのリストから、最初のジョブを選択します。 | 最も古いパイプラインのジョブから順に実行したい場合。unorderedモードよりも効率は下がりますが、継続的デプロイではより安全です。 |
newest_first | リソースが空くと、パイプラインIDを降順に並べた実行待ちジョブのリストから、最初のジョブを選択します。 | 最新のパイプラインのジョブを実行し、古いデプロイメントジョブの実行を防ぎたい場合。各ジョブがべき等(同じ操作を繰り返し実行しても結果が同じ)でなければなりません。 |
newest_ready_first | リソースが空くと、このリソースでの実行待ちジョブのリストから、最初のジョブを選択します。ジョブは、パイプラインIDの降順でソートされています。 | newest_firstが現在のパイプラインをデプロイする前に新しいパイプラインを優先するのを防ぎたい場合。newest_firstよりも高速です。各ジョブがべき等(同じ操作を繰り返し実行しても結果が同じ)でなければなりません。 |
処理モードを変更する
リソースグループの処理モードを変更するには、APIを使用してprocess_modeを指定し、既存のリソースグループを編集するリクエストを送信する必要があります:
unorderedoldest_firstnewest_firstnewest_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: production3つのコミットが短い間隔でプロジェクトにプッシュされると、3つのパイプラインがほぼ同時に実行されることになります:
- 最初のパイプラインはジョブ
build->deployを実行します。このデプロイメントジョブをdeploy-1とします。 - 2番目のパイプラインはジョブ
build->deployを実行します。このデプロイメントジョブをdeploy-2とします。 - 3番目のパイプラインはジョブ
build->deployを実行します。このデプロイメントジョブをdeploy-3とします。
リソースグループの処理モードに応じて、次のように動作します:
- 処理モードが
unorderedの場合:deploy-1、deploy-2、deploy-3は同時には実行されません。- ジョブの実行順序は保証されません。たとえば、
deploy-1がdeploy-3より先に実行される場合も、後に実行される場合もあります。
- 処理モードが
oldest_firstの場合:deploy-1、deploy-2、deploy-3は同時には実行されません。deploy-1が最初に実行され、次にdeploy-2、最後にdeploy-3が実行されます。
- 処理モードが
newest_firstの場合:deploy-1、deploy-2、deploy-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: productiontrigger: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>(リソース待機中)というメッセージでハングすることがあります。解決するには、まずリソースグループが正しく動作していることを確認します:
ジョブの詳細ページに移動します。
リソースがジョブに割り当てられている場合は、現在リソースを使用しているジョブを表示を選択し、ジョブステータスを確認します。
- ステータスが
runningまたはpendingの場合、この機能は正常に動作しています。ジョブが完了してリソースをリリースするまで待ちます。 - ステータスが
createdであり、処理モードが古い順または新しい順のいずれかである場合、この機能は正しく動作しています。ジョブのパイプラインページにアクセスし、どのアップストリームステージまたはジョブが実行をブロックしているかを確認します。 - 前述の条件に当てはまらない場合、この機能が正しく動作していない可能性があります。GitLabにイシューを報告してください。
- ステータスが
現在リソースを使用しているジョブを表示が利用できない場合、リソースはジョブに割り当てられていません。代わりに、リソースの実行待ちジョブを確認します。
- REST APIでリソースの実行待ちジョブを取得します。
- リソースグループの処理モードが古い順であることを確認します。
- 実行待ちジョブのリストで最初のジョブを見つけ、GraphQLでそのジョブの詳細を取得します。
- 最初のジョブのパイプラインが古いパイプラインの場合は、そのパイプラインまたはジョブ自体をキャンセルしてみてください。
- オプション。次の実行待ちジョブが、実行されなくなった古いパイプラインに属している場合は、このプロセスを繰り返します。
- 問題が解決しない場合は、GitLabにイシューを報告してください。
複雑またはビジーなパイプラインでの競合状態
前述の方法でイシューを解決できない場合は、既知の競合状態の問題が発生している可能性があります。競合状態は、複雑またはビジーなパイプラインで発生します。たとえば、次のような場合に競合状態が発生する可能性があります:
- パイプラインに複数の子パイプラインが存在する
- 単一のプロジェクトで複数のパイプラインが同時に実行されている
このイシューが発生していると思われる場合は、GitLabにイシューを報告し、新しいイシューへのリンクを付けてイシュー436988にコメントを残してください。問題を確認するために、GitLabからパイプライン全体の設定などの追加の詳細を求められる場合があります。
一時的な回避策として、次のことができます:
新しいパイプラインを開始する。
スタックしたジョブと同じリソースグループを持つ完了したジョブを再実行する。
たとえば、同じリソースグループに属する
setup_jobとdeploy_jobがある場合、deploy_jobがwaiting for resourceで停滞している間に、setup_jobが完了する可能性があります。この場合、setup_jobを再起動してプロセス全体を再開し、deploy_jobを完了させることができます。
GraphQLを介してジョブの詳細を取得する
GraphQL APIからジョブ情報を取得できます。クロスプロジェクト/親子パイプラインによるパイプラインレベルの並行処理制御を使用する場合は、UIからはトリガージョブにアクセスできないため、GraphQL APIを使用する必要があります。
GraphQL APIからジョブ情報を取得するには、次のようにします:
パイプラインの詳細ページに移動します。
ジョブタブを選択し、スタックしたジョブのIDを見つけます。
インタラクティブGraphQLエクスプローラーに移動します。
次のクエリを実行します:
{ 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が含まれています。次のクエリを実行し、前述の基準に従って
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
ジョブステータス
問題の発生頻度
問題を再現する手順
サポートに連絡して、さらに支援を受けたり、開発チームとやり取りしたりすることもできます。