リソースグループ
GitLab 12.7から導入されました。
デフォルトでは、GitLab CI/CDのパイプラインは同時に実行されます。同時実行はマージリクエストのフィードバックループを改善するために重要な要素ですが、デプロイジョブの同時実行を制限して1つずつ実行したい状況もあるでしょう。リソースグループを使用して、ジョブの同時実行を戦略的に制御し、継続的デプロイのワークフローを安全に最適化します。
リソースグループの追加
以下のパイプライン設定(.gitlab-ci.yml ファイルがリポジトリにあること)があることが前提です:
build:
stage: build
script: echo "Your build script"
deploy:
stage: deploy
script: echo "Your deployment script"
environment: production
ブランチに新しいコミットをプッシュするたびに、build とdeploy の 2 つのジョブを持つ新しいパイプラインが実行されます。しかし、短い間隔で複数のコミットをプッシュすると、たとえば複数のパイプラインが同時に動き始めます:
- 最初のパイプラインは
build-> のジョブを実行します。deploy - 2番目のパイプラインはジョブを実行します
build->deploy
この場合、異なるパイプラインのdeploy ジョブがproduction 環境に対して同時に実行される可能性があります。同じインフラストラクチャに対して複数のデプロイスクリプトを実行すると、インスタンスに悪影響/混乱が生じ、最悪の場合、インスタンスが破損した状態になる可能性があります。
deploy ジョブが一度に一度だけ実行されるようにするには、resource_group キーワード を同時実行に敏感なジョブに指定します:
deploy:
...
resource_group: production
この設定により、デプロイの安全性が保証される一方で、パイプラインの効率を最大化するためにbuild ジョブを同時に実行することができます。
前提条件
- GitLab CI/CDパイプラインの基礎知識
- GitLab環境とデプロイの基礎知識
- 少なくともCI/CDパイプラインを設定するプロジェクトの開発者ロール。
制限事項
リソースグループにアタッチできるリソースは1つだけです。
プロセスモード
- GitLab 14.3で導入されました。
- GitLab 14.4 で機能フラグ
ci_resource_group_process_modesが削除されました。- GitLab 14.4で一般的に利用可能。
デプロイの好みに合わせて、戦略的にジョブの同時実行を制御するプロセスモードを選択することができます。以下のモードがサポートされています:
- 順序なし:実行中のジョブの同時実行を制限するデフォルトのプロセスモードです。ジョブの実行順序を気にしない場合に最も使いやすいオプションです。ジョブの実行準備が整った時点で、ジョブの処理を開始します。
-
最も古いジョブを優先します:このプロセスモードはジョブの同時実行を制限します。リソースに空きがある場合、パイプラインIDの昇順でソートされた今後のジョブリスト (
created,scheduled, またはwaiting_for_resource状態) から最初のジョブを選択します。このモードは、ジョブが最も古いパイプラインから実行されるようにしたい場合に効率的です。パイプラインの効率という点では
unorderedモードより劣りますが、継続的なデプロイでは安全です。 -
新しいもの優先:このプロセスモードはジョブの同時実行を制限します。リソースに空きがある場合、パイプラインIDの降順でソートされた今後のジョブリスト(
created、scheduled、waiting_for_resource状態)から最初のジョブを選択します。このモードは、ジョブが最新のパイプラインから実行されることを保証し、古いデプロイジョブを防止する機能ですべての古いデプロイジョブを防止したい場合に効率的です。パイプラインの効率という点では最も効率的なオプションですが、各デプロイジョブが冪等であることを確認する必要があります。
プロセスモードの変更
リソースグループのプロセスモードを変更するには、APIを使用して、process_mode を指定して既存のリソースグループの編集リクエストを送信する必要があります:
unorderedoldest_firstnewest_first
プロセスモードの違いの例
次の.gitlab-ci.yml を考えてみましょう。2つのジョブ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-1の場合、deploy-2とdeploy-3は同時に実行されません。 - ジョブの実行順序は保証されていません。例えば、
deploy-3が実行される前または後にdeploy-1が実行される可能性があります。
-
- プロセスモードが
oldest_firstの場合:-
deploy-1の場合、deploy-2とdeploy-3は同時に実行されません。 -
deploy-1が最初に実行され、deploy-2が2番目に実行され、deploy-3が最後に実行されます。
-
- プロセスモードが
newest_firstの場合:-
deploy-1の場合、deploy-2とdeploy-3は同時に実行されません。 -
deploy-3が最初に実行され、deploy-2が2番目に実行され、deploy-1が最後に実行されます。
-
クロスプロジェクト/親子パイプラインによるパイプラインレベルの同時実行制御
GitLab 13.9 で導入されました。
同時実行に敏感なダウンストリームパイプラインのためにresource_group を定義することができます。trigger キーワード はダウンストリームパイプラインをトリガーすることができ、resource_group キーワード はそれと共存することができます。resource_group はデプロイパイプラインの同時実行を制御するのに効率的で、他のジョブは同時実行を続けることができます。
次の例では、プロジェクトに 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: depend
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: depend を定義する必要があります。これにより、ダウンストリームパイプラインが終了するまでロックがリリースされないようになります。
関連するトピック
トラブルシューティング
パイプライン設定のデッドロックを回避
oldest_first process mode はジョブをパイプラインの順番で実行することを強制するため、他のCI機能との相性が悪い場合があります。
例えば、親パイプラインと同じリソースグループを必要とする子パイプラインを実行すると、デッドロックが発生する可能性があります。以下に_悪い_設定の例を示します:
# BAD
test:
stage: test
trigger:
include: child-pipeline-requires-production-resource-group.yml
strategy: depend
deploy:
stage: deploy
script: echo
resource_group: production
environment: production
親パイプラインでは、test ジョブを実行し、その後子パイプラインを実行します。strategy: depend オプション は、子パイプラインが終了するまでtest ジョブを待機させます。親パイプラインは次のステージでdeploy ジョブを実行します。このジョブはproduction リソースグループのリソースを必要とします。プロセスモードがoldest_firstの場合、最も古いパイプラインからジョブを実行します。つまり、deploy ジョブが次に実行されます。
しかし、子パイプラインもproduction リソースグループのリソースを必要とします。子パイプラインは親パイプラインよりも新しいため、子パイプラインはdeploy ジョブが終了するまで待機します。
この場合、代わりに親パイプライン設定でresource_group キーワードを指定する必要があります:
# GOOD
test:
stage: test
trigger:
include: child-pipeline.yml
strategy: depend
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の場合、この機能は正常に動作しています。ジョブが終了し、リソースがリリースされるまで待ちます。 - ステータスが
runningまたはpendingでない場合、機能が正しく動作していない可能性があります。以下の情報で新しいイシューを作成してください:- ジョブID
- ジョブステータス。
- 問題の発生頻度
- 問題の再現手順
- ステータスが
GraphQL API からジョブ情報を取得することもできます。プロジェクト間/親子間のパイプラインでパイプラインレベルの同時実行制御を使用する場合は、トリガジョブに UI からアクセスできないため、GraphQL API を使用する必要があります。
GraphQL APIからジョブ情報を取得するには、以下の手順に従います:
- パイプラインの詳細ページに移動します。
- Jobsタブを選択し、スタックしたジョブのIDを探します。
- GraphiQLエクスプローラーに移動します。
-
次のクエリを実行します:
{ project(fullPath: "<fullpath-to-your-project>") { name job(id: "gid://gitlab/Ci::Bridge/<job-id>") { name 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::Bridge/<job-id-currently-using-the-resource>") { name status pipeline { path } } } }ステータスが
runningまたはpendingでない場合は、新しいイシューを作成し、サポートに連絡してください。