並行CIジョブのためのGitLab Runnerの同時実行を管理する方法
GitLabの継続的インテグレーション(CI)パイプラインは、コードをリポジトリにプッシュするたびにビルド、テスト、リリースを自動化するための一般的な方法です。パイプラインは同時に実行され、一連の順次ステージで構成されています。各ステージには、ステージの間に並行して実行される複数のジョブが含まれる場合があります。並行ジョブとクロスインスタンスパイプラインの両方の最大同時実行数は、サーバーの構成に依存します。
ジョブはGitLab Runnerインスタンスによって実行されます。ランナーは、制御しているGitLabサーバーから新しいジョブを受け取る孤立したプロセスとして動作します。ジョブが発行されると、ランナーはCIスクリプトを実行するサブプロセスを作成します。ランナーがジョブを受け入れ、実行を開始する条件を制御する複数の変数があります。このガイドでは、並列ジョブとパイプラインを構成する方法を見ていきます。
ランナー数を増やす
同時に実行できるジョブを増やす一つの方法は、単により多くのランナーを登録することです。GitLab Runnerの各インストールは、複数の異なるランナーインスタンスを登録できます。これらはそれぞれ独立して動作し、すべてが同じ調整サーバーを参照する必要はありません。
使用してください
gitlab-runner register
新しいランナーを追加するコマンド:
sudo gitlab-runner registerGitLabサーバーからの登録情報を入力するように求められます。この情報は、GitLabプロジェクトまたはグループの設定 > CI/CD ページにあります。または、インスタンスレベルのランナーについては、管理センターの概要 > ランナーにアクセスしてください。ランナーは、登録された範囲内から発生したジョブのみを実行します。
各登録ランナーは、あなたの/etc/gitlab-runner/config.tomlファイルのそれぞれのセクションを持ちます:
Runner 1
executor = "shell"
...
Runner 2
executor = "shell"
...
Runner 3
executor = "shell"
...
もし3人のランナー全員が同じサーバーに登録されていた場合、現在最大で3つのジョブが並行して実行されているのが見えるでしょう。
同時実行制限の引き上げ
特定のランナー登録の許可された同時実行数を、その設定ブロック内のlimitフィールドを使用して設定できます。
Runner 1
executor = "shell"
limit = 4
この変更により、最初のランナーはサブプロセスで最大4つの同時ジョブを実行できるようになります。別のランナーをlimit=2で登録すると、両方のランナーが同じ制御GitLabサーバーを参照していると仮定すると、同時実行レベルが合計6つのジョブに引き上げられます。
リクエストの同時処理を扱う
実行中のライブジョブの数だけが同時実行性に影響を与える変数ではありません。GitLab Runner は、別の request_concurrency 変数を介して、受け入れられるジョブリクエストの数を管理します。
この値は、ランナーがGitLabから受け取るキューに入れられたリクエストの数を制御します。サーバーが新しいCIジョブをスケジューリングする必要があるとき、ランナーはそれを受け取るのに十分な容量があるかどうかを示さなければなりません。ランナーは、キューに入れられたリクエストがrequest_concurrencyが許可する以上であれば、そのジョブを受け入れません。
この例を考えてみてください:
Runner 1
executor = "shell"
limit = 2
request_concurrency = 4
このランナーは最大四つの同時ジョブリクエストを受け入れ、最大二つを同時に実行します。最初の二つが完了するまで、追加のジョブは受け付けません。
グローバル同時実行レベル
GitLab Runnerは、個別の登録によって公開されるlimit値に全体的な上限を設定するグローバル並行処理係数も維持しています。この値は、あなたのconfig.tomlの先頭にあるconcurrency設定で制御できます:
concurrency = 4
Runner 1
executor = "shell"
limit = 4
Runner 2
executor = "shell"
limit = 2
ここで、2つのランナーの構成は、合計ジョブの同時実行数が6であることを示唆しています。しかし、グローバルなconcurrency設定があるため、実際に同時に実行されるジョブは4つを超えることはありません。この値は、GitLab Runnerのインストール全体によって作成できるサブプロセスの合計数を制限します。
変更を適用しています
必要な変更を行ったら、config.tomlを保存して、パイプラインの実行に戻ることができます。ファイルへの変更はGitLab Runnerによって自動的に検出され、ほぼ即座に適用されるはずです。
新しい同時実行レベルが適用されていないようであれば、GitLab Runnerプロセスを再起動してみてください:
sudo gitlab-runner restartこれにより、GitLab Runnerサービスが停止し、再起動し、設定ファイルが再読み込みされます。
並行ジョブのためのパイプラインの配置
もしあなたの単一のパイプライン内のジョブが並列実行されていない場合、あなたの .gitlab-ci.yml 構成の基本を確認する価値があります。デフォルトでは同時に実行されるのはジョブだけであり、パイプラインステージではありません。
stages:
test:
build:
deploy:
test:
stage: test
# ...
build_ios:
stage: build
# ...
build_android:
stage: build
# ...
deploy_ios:
stage: deploy
# ...
deploy_android:
stage: deploy
# ...
このパイプラインは、GitLab UIで横に表示される三つのステージを定義しています。各ステージは、次のステージが始まる前に完了しなければなりません。buildステージとdeployステージには、それぞれ二つのジョブがあります。これらのジョブは、ランナーが設定された同時実行制限内に収まるだけのキャパシティを持っている場合、並行して実行されます。
「ステージは順次実行される」というルールは、needsキーワードを使用して有向非循環グラフを構築することで破ることが可能です:
stages:
test:
build:
deploy:
test:
stage: test
# ...
build_ios:
stage: build
# ...
build_android:
stage: build
# ...
deploy_ios:
stage: deploy
needs: ["test", "build_ios"]
# ...
deploy_android:
stage: deploy
needs: ["test", "build_android"]
# ...
ここでは、build_ios ジョブが完了すると、iOS のデプロイメントがすぐに進行できるようになっています。たとえ build ステージの残りが完了していなくてもです。needs を使用すると、パイプラインの並列化の新たな機会を追加することにより、より柔軟になります。しかし、パイプラインにジョブを追加するにつれて、維持が難しくなる可能性がある複雑さももたらします。
キャッシングについてはどうですか?
同時実行の使用は、特定のパイプラインを通るたびに異なるランナーによってジョブが処理される可能性があることを意味します。ランナーはそれぞれ独自のキャッシュインスタンスを保持するため、ジョブがキャッシュにヒットすることは保証されません。たとえ以前のパイプラインの実行がキャッシュを生成してもです。キャッシュは、2番目のジョブを実行しているランナーとは異なるランナーに存在する可能性があります。
これに対処するには、S3互換のオブジェクトストレージシステムを使用して共有キャッシュプロバイダーを設定します。これにより、ジョブが完了した後、キャッシュがそのプロバイダーにアップロードされ、特定のランナーとは独立してコンテンツが保存されます。他のランナーインスタンスは、それを作成していなくても、オブジェクトストレージサーバーからキャッシュを取得できるようになります。
共有キャッシュは、キャッシュヒットの確率を高めることによりパフォーマンスを向上させ、ジョブが完了するために必要な作業量を減らすことができます。ただし、あなたのパイプラインは成功したキャッシュ解決を必要としないべきです。キャッシュは最善の努力に基づいて使用されるため、CIスクリプトはミスに対して耐性があることを意図しています。
要約
GitLab Runnerには、同時実行を管理するための3つの主要な制御があります。それは、個々のランナーのlimitおよびrequest_concurrencyフィールド、そして全体のインストールのconcurrency値です。特定のランナーのインストールは、<concurrency>ジョブを同時に実行することはなく、その登録のlimit値の合計がより多くを処理できることを示していても、同様です。
ランナーを追加することは、全体の同時実行に影響を与えるもう一つの方法です。一般的には、同じ構成でより多くのジョブを実行したい場合、既存のランナーの同時実行数を増やすのが最善です。新しいエグゼキュータや、既存のフリートとは異なる設定でジョブを実行する必要がある場合は、新しいランナーを追加し、そのlimit値を設定してください。

