Cells: CI ランナー

GitLab は GitLab Runner を通じて CI ジョブを実行します。これは多くの場合、顧客のインフラストラクチャで管理されています。 CI パイプラインの一部として作成されたすべての CI ジョブはプロジェクトのコンテキストで実行されます。 これは GitLab ランナーの管理方法に課題をもたらします。

1. 定義

ランナーには 3 種類あります:

  • インスタンス全体: 特定のタグ(選択基準)でグローバルに登録されたランナー
  • グループランナー: 特定のトップレベルグループまたはそのグループ内のプロジェクトのジョブを実行するランナー
  • プロジェクトランナー: 1 つまたは複数のプロジェクトのジョブを実行するランナー: 一部のランナーは異なるトップレベルグループのプロジェクトが割り当てられている場合があります。

これと、すべての種類のランナーを記述する ci_runners テーブルという既存のデータ構造が組み合わさると、Cells 環境で ci_runners をどのように管理するかという課題が生じます。

2. データフロー

GitLab ランナーは、グローバルスコープのエンドポイントのセットを使用します:

  • 登録トークンを使用して新しいランナーを登録する https://gitlab.com/api/v4/runners (削除予定) (registration token)
  • ユーザーのコンテキストで新しいランナーを作成する https://gitlab.com/api/v4/user/runners (runner token)
  • 認証済み https://gitlab.com/api/v4/jobs/request エンドポイントでジョブをリクエストする (runner token)
  • https://gitlab.com/api/v4/jobs/:job_id でジョブのステータスをアップロードする (build token)
  • https://gitlab.com/api/v4/jobs/:job_id/trace でトレースをアップロードする (build token)
  • https://gitlab.com/api/v4/jobs/:job_id/artifacts でアーティファクトをダウンロード/アップロードする (build token)

現在 3 種類の認証トークンが使用されています:

  • ランナー登録トークン(削除予定
  • 特定の設定(tagslocked など)を持つシステムに登録されたランナーを表すランナートークン
  • 特定のジョブの更新、アーティファクトのアップロード、依存アーティファクトのダウンロード、コンテナレジストリイメージのダウンロードとアップロードへの限定的なアクセスを与えるエフェメラルなトークンを表すビルドトークン

これらの各エンドポイントはヘッダー経由で認証トークンを受け取ります(/trace には JOB-TOKEN、その他のエンドポイントには token)。

CI パイプラインは特定の Cell のコンテキストで作成されるため、ビルドのピックアップはその特定の Cell によって処理される必要があります。 これにより、ソリューションによって異なりますが、ビルドのピックアップは以下のいずれかが必要です:

  • 最初から正しい Cell にルーティングされる
  • 二段階: グローバルプールからビルドをリクエストし、Cell 固有の URL を使用して特定の Cell でビルドを要求する

3. 提案

3.1. 認証トークン

CI ランナーのパスはルーティング可能ではありませんが、以下の 2 つの可能なソリューションでルーティング可能にできます:

  • https://gitlab.com/api/v4/jobs/request は(X-GitLab-Last-Update ヘッダーに基づく)チケットメカニズムを使用したロングポーリングメカニズムを使用します。ランナーが最初に起動すると、GitLab に対してリクエストを送信し、GitLab はランナーがピックアップするビルドか、last_update トークンを持つ 204 No job で応答します。この値は完全に GitLab によって制御されます。これにより、GitLab は JWT または他の手段を使用して、Router が簡単にデコードできる cell 識別子をエンコードできます。
  • 通信の大部分(ボリュームの観点から)は build token を使用しています。GitLab はランナーが特定のジョブに使用するトークンの唯一の所有者であるため、これが最も変更しやすいターゲットになります。build token を保存せず、代わりに定義されたスコープを持つ JWT トークンを使用することについての以前の議論がありました。このようなトークンは、Router がすべてのリクエストをルーティングできる cell をエンコードできます。

3.2. リクエストボディ

この文は今や正しくありません:

最も多く使用されるエンドポイントはリクエストボディで認証トークンを渡します。 Router がプロキシリクエストなしでこの情報に簡単にアクセスできる方法として、 HTTP ヘッダーを使用することが望ましいかもしれません。

ランナーは Add runner token to header MR がマージされた ことで、すべてのリクエストの HTTP ヘッダーにトークンを送信するようになりました。

3.3. インスタンス全体は Cell ローカル

すべてのランナーが常に特定の Cell に登録されローカルになる設計を選択できます:

  • 各 Cell は、独自のペースで更新されるインスタンス全体のランナーの独自のセットを持ちます
  • プロジェクトランナーは同じ Organization のプロジェクトにのみリンクでき、強い分離を作ります。
  • このモデルでは ci_runners テーブルは Cell にローカルです。
  • このモデルでは、上記のエンドポイントを何らかの方法で Cell にスコープするか、ルーティング可能にする必要があります。それはプレフィックスを付けたり、追加の Cell パラメーターを追加したり、ランナートークンをデコードして Cell に一致させるより堅牢な方法を提供したりすることによって行われるかもしれません。
  • ルーティング可能なトークンが使用される場合、データベースに保存される暗号学的ランダムから、代わりに JWT トークンを使用することを好むように移行できます。
  • 登録済みランナーを表示する管理エリアは Cell にスコープされる必要があります。

このモデルは強い分離保証を提供するため望ましいかもしれません。 このモデルは各 Cell が個別に管理されるため、メンテナンスのオーバーヘッドを大幅に増加させます。 このモデルでは、プロジェクトが Cell 間で一貫したランナーエクスペリエンスを持てるよう、ランナータグ機能の調整が必要かもしれません。

3.4. インスタンス全体はクラスター全体

すべてのランナーが Cell ローカルである提案とは対照的に、ランナーがグローバルである、またはインスタンス全体のランナーのみがグローバルであると考えることができます。

ただし、これにはシステムの大規模な刷新が必要であり、以下の側面を変更する必要があります:

  • ci_runners テーブルは ci_instance_runners などに分解される必要がある可能性があります。
  • すべてのインターフェースは正しいテーブルを使用するよう採用される必要があります。
  • ビルドキューイングは二段階式に刷新される必要があります。各 Cell はすべての保留中および実行中のビルドを把握しますが、実際のビルドの要求はデータを含む Cell に対して行われます。
  • ci_pending_buildsci_running_buildsクラスター全体 のテーブルになる必要がある可能性が高く、CI キューイングに関連してシステム内のホットスポットを作る可能性が高まります。

このモデルはエンジニアリングの観点から実装が複雑です。 一部のデータは Cell 間で共有されます。 これは、例えば悪用時に他の Cell の Organizations のエクスペリエンスに影響を与える可能性のある、システム内のホットスポット/スケーラビリティ問題を作ります。

3.5. GitLab CI デーモン

検討すべき別の潜在的なソリューションは、ビルドキューイングを担当し、独自のデータベースを所有し、シャードまたは Cell 化されたサービスのモデルで動作する専用サービスを持つことです。 CI/CD デーモン についての以前の議論がありました。

サービスがシャード化されている場合:

  • モデルによって異なりますが、ランナーがクラスター全体か Cell ローカルかに応じて、このサービスはすべての Cells からデータをフェッチする必要があります。
  • サービスと ci_pending_builds/ci_running_builds を含むデータベースを共有するモデルを採用できます。
  • 各 Cell がランナーによってピックアップされるべきビルドを CI/CD デーモンにプッシュするプッシュモデルを検討できます。
  • シャード化されたサービスは、特定のビルドを処理する責任を持つ Cell を把握し、指定された Cell に処理リクエストをルーティングできます。

サービスが Cell 化されている場合:

  • ルーティング可能なエンドポイントのすべての期待はまだ有効です。

一般的に、CI デーモンの使用は述べられた問題に対して著しくは役に立ちません。 ただし、より効率的な処理とデカップリングモデルに関していくつかのメリットを提供します: プッシュモデルであり、GitLab ランナーとのステートフルな通信(例: gRPC や Websockets)を提供する方法を開きます。

4. 評価

すべてのオプションを考慮すると、最も有望なソリューションは以下であるように思われます:

  • インスタンス全体は Cell ローカル を使用する
  • ルーティング可能なアイデンティティを持つエンドポイントを改善する(特定のパスまたはより優れたトークンによって)

もう一つの潜在的なメリットは ci_builds.token を廃止し、代わりに CI ランナーによって許可されるより広いスコープのセットをより適切かつ簡単にエンコードできる JWT トークン を使用することです。

4.1. メリット

4.2. デメリット