Cells: インフラストラクチャ

Cells: インフラストラクチャ
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリース、タイミングは変更または延期される可能性があり、GitLab Inc. の独自の判断に委ねられています。
StatusAuthorsCoachDRIsOwning StageCreated
proposed@sxuereb@andrewn

事前学習

  1. Cells イテレーション、特に Cells 1.0
  2. GitLab Dedicated
  3. GitLab Dedicated アーキテクチャ

哲学

  • デフォルトでセルローカル: すべてのサービスはセルローカルにすべきであり、セルローカルでない正当な理由が文書化されていない限り、グローバルであってはなりません。 セルローカルを維持することで、Cell とサービス間の通信が内部にとどまり、サービスはより小さなスケールで動作し、爆発半径がはるかに小さくなります。 例: Gitaly と GitLab Registry はセルローカルです。
  • 均質な環境: 現在のところ、すべての GitLab Cell は同じ外観であるべきです。ブートストラップとプロビジョニングは自動化された方法で行われるべきです。 最初のイテレーションではすべての Cell が同じサイズであり、異なるサイズを実行することにはメリットがありますが、複雑さとスコープが増します。
  • フレッシュスタート、でもそれほどでもない: 新しい GitLab インスタンスが作成されるため、すべてをやり直したくなります。既存のインフラストラクチャ、Dedicated ツール、そして時間のバランスを取る必要があります。
  • すべての操作が同じようにロールアウトされる: 設定変更、フィーチャーフラグ、デプロイメント、および運用タスクは、理想的にはすべて変更をロールアウトする同じプロセスを通じて行われます。 1 つのやり方を持つことで効率化と自動化の唯一の情報源をもたらします。
  • ツールの一元化: GitLab.com を管理するためのツールと GitLab Dedicated のための別のツールが多数あり、 サイロ化、作業の重複、移植性の低下を招いています。 GitLab.com に複数の Cell をプロビジョニングする必要があり、新しいツールが必要で、GitLab Dedicated はそのために専用ツールを構築しました。 このツールをできる限り使用するように努め、同意できないことがあれば不同意、コミット、そして再び不同意するようにして 1 つのツールを改善すべきです。 欠点があるツールから始めることは問題ありません。イテレーション的なアプローチにより、2 つではなく_1 つ_の成熟した製品が生まれます。

用語集/ユビキタス言語

ユビキタス言語

  • Provision(プロビジョン): 新しい Cell を作成するとき。例: Cell 5 を_プロビジョン_しました。これは全く新しい Cell です。
  • Deploy(デプロイ): 既存の Cell の中で実行されているコードを変更するとき。例: GitLab.com で新しい auto-deploy バージョンを_デプロイ_しました。
  • Configuration change(設定変更): アプリケーションまたはインフラストラクチャの設定を変更するとき。例: VM に追加されたラベルに対して_設定変更_を行いました。
  • Tenant(テナント): GitLab Dedicated ツール(Instrumentor)を通じてプロビジョニングされた GitLab インスタンス。テナントは GitLab Dedicated 顧客インスタンス_または_ Cell インスタンスのどちらかです。
  • Cell(セル): 複数の顧客が単一のテナントを通じてサービスを受ける GitLab.com の一部となるようにプロビジョニングされたテナント。
  • Legacy Cell(レガシーセル): 既存の GitLab.com デプロイメント。
  • Ring(リング): 単一のデプロイメントステージターゲットとしてグループ化された Cell の集合。例: リング 2 の Cell はリング 1 の Cell の後に変更をデプロイします。
  • Cluster(クラスター): Cell の集合と既存の GitLab.com インフラストラクチャ。例: クラスター内の Registry のバージョンを変更する必要があります。
  • Fleet(フリート): 本番環境を構成する、シングルテナントとマルチテナントの両方を含むすべての SaaS 環境の集合。 既存の GitLab.com インフラストラクチャ、Cell、および Dedicated が含まれます。

アーキテクチャ

以下は Cell アーキテクチャです。現在の GitLab.com アーキテクチャ(Cell 導入前)は https://handbook.gitlab.com/handbook/engineering/infrastructure-platforms/production/architecture/ で確認できます。

@startuml
!include <k8s/Common>
!include <k8s/Context>
!include <k8s/Simplified>
!include <k8s/OSS/all>
!include <gcp/GCPCommon>
!include <gcp/Compute/all>
!include <gcp/Databases/all>
!include <gcp/Security/all>
!include <gcp/Storage/all>

skinparam actorStyle awesome
skinparam frame {
  borderColor<<gcp_project>> #4285F4
}
skinparam frame {
  borderColor<<vpc>> #F4B400
}
skinparam frame {
  borderColor<<gcp>> #0F9D58
}
skinparam frame {
  borderColor<<cluster>> #DB4437
}
skinparam cloud {
  borderColor<<cloudflare>> #F48120
}

:User:
cloud gitlab.com <<cloudflare>> {
  [DoS Protection]-->[WAF]
  [WAF]-->[RoutingService]
}
cloud "cloud.gitlab.com" <<cloudflare>> {
  [Cloud Connector]-->[AI Gateway]
}
:User:->gitlab.com
:User:->cloud.gitlab.com

cloud "ClickHouse Cloud" {
  database "ClickHouse" as cell1Clickhouse
  database "ClickHouse" as cell2Clickhouse
}

frame "Google Cloud Platform" <<gcp>> {
  frame "topology-service" <<gcp_project>>{
    rectangle "TopologyService" as TopologyService
  }
  frame "Cell Cluster" <<cluster>> {
    frame "gitlab-production" <<gcp_project>>{
      frame "gprd (Shared VPC Network)" <<vpc>> as gprdVPC {
        rectangle "Frontend" as primaryFrontend {
          node "HAProxy"
        }

        rectangle "Compute" as primaryCompute {
          node zonal [
          <b> zonal cluster x3
          ===
          api
          ---
          web
          ---
          git
          ---
          gitlab-shell
          ---
          websockets
          ---
          registry
          ]

          node regional [
          <b>regional x1
          ===
          sidekiq
          ---
          kas
          ---
          zoekt
          ---
          cny
          ---
          pages
          ]
        }

        rectangle "Storage" as primaryStorage {
          database "patroni-main"
          database "patroni-ci"
          database "patroni-registry"
          database "redis (multiples)"
          file "object storage" as primaryObjectStorage
        }

        primaryFrontend <--> primaryCompute
        primaryCompute <--> primaryStorage
      }
    }

    frame "gitlab-ci" <<gcp_project>> {
      node "runner managers" as runnerManager

      runnerManager --> "HAProxy"
    }
    frame "gitlab-ci-*" <<gcp_project>> {
      node "ephemeral VMs"
    }
    runnerManager --> "gitlab-ci-*"

    frame "gitlab-gitaly-gprd-*" <<gcp_project>> {
      file "gitaly-[1,9]" as primaryGitaly
    }
    primaryCompute <--> primaryGitaly
    primaryGitaly .r[#F4B400].* gprdVPC

    frame "cell-01HV3FBWXHSYBAR2R2" as cell1 <<gcp_project>> {
      frame "cell-01HV3FBWXHSYBAR2R2 VPC" <<vpc>> as cell1VPC {
        Cluster_Boundary(cell1gke, "cell1gke") {
          Namespace_Boundary(cell1gitlab, "gitlab") {
            KubernetesPod(cell1web, "Web", "")
            KubernetesPod(cell1shell, "Shell", "")
            KubernetesPod(cell1registry, "Registry", "")
            KubernetesPod(cell1sidekiq, "Sidekiq", "")
          }
          Namespace_Boundary(cell1Observability, "monitoring") {
            KubernetesPod(cell1Prom, "Prometheus", "")
          }
        }

        storage "Storage" as cell1Storage {
          Cloud_SQL(cell1Postgres, "PostgreSQL", "")
          Cloud_Memorystore(cell1Redis, "Redis", "")
          Cloud_Storage(cell1ObjectStorage, "GCS", "")
          Key_Management_Service(cell1SecretStorage, "GKMS", "")
          Compute_Engine(cell1Gitaly, "Gitaly", "")
        }
        cell1gke <--> cell1Storage
        cell1gke <---> cell1Clickhouse
      }
    }

    frame "cell-01HV3FBYX37C18SW05" as cell2 <<gcp_project>> {
      frame "cell-01HV3FBYX37C18SW05 VPC" <<vpc>> as cell2VPC {
        Cluster_Boundary(cell2gke, "cell2gke") {
          Namespace_Boundary(cell2gitlab, "gitlab") {
            KubernetesPod(cell2web, "Web", "")
            KubernetesPod(cell2shell, "Shell", "")
            KubernetesPod(cell2registry, "Registry", "")
            KubernetesPod(cell2sidekiq, "Sidekiq", "")
          }
          Namespace_Boundary(cell2Observability, "monitoring") {
            KubernetesPod(cell2Prom, "Prometheus", "")
          }
        }

        storage "Storage" as cell2Storage {
          Cloud_SQL(cell2Postgres, "PostgreSQL", "")
          Cloud_Memorystore(cell2Redis, "Redis", "")
          Cloud_Storage(cell2ObjectStorage, "GCS", "")
          Key_Management_Service(cell2SecretStorage, "GKMS", "")
          Compute_Engine(cell2Gitaly, "Gitaly", "")
        }

        cell2gke <--> cell2Storage
        cell2gke <---> cell2Clickhouse
      }
    }

    cell1VPC <. gprdVPC : Private Service Connect
    cell2VPC <. gprdVPC : Private Service Connect
  }

  "Cell Cluster" -u-> cloud.gitlab.com
}
[RoutingService]-[thickness=1]->TopologyService
[cell1gke]-[thickness=1]->TopologyService
[cell2gke]-[thickness=1]->TopologyService
[primaryFrontend]-[thickness=1]->TopologyService
[RoutingService]-[thickness=3]->primaryFrontend
[RoutingService]-[thickness=3]->cell1gke
[RoutingService]-[thickness=3]->cell2gke
@enduml

KAS

@startuml

skinparam frame {
  borderColor<<customer>> #F4B400
}
skinparam frame {
  borderColor<<gcp>> #4285F4
}
skinparam cloud {
  borderColor<<cloudflare>> #F48120
}

together {
  frame "cluster 1" <<customer>> {
      component "agentk" as cluster1AgentK
  }

  frame "cluster 2" <<customer>> {
      component "agentk" as cluster2AgentK
  }

  frame "cluster 3" <<customer>> {
      component "agentk" as cluster3AgentK
  }

  frame "workstation" <<customer>> {
      component "kubectl"
  }
}


cloud wss://kas.gitlab.com <<cloudflare>> as kas.gitlab.com {
    component "routing service"
}

cluster1AgentK <..d..> kas.gitlab.com
cluster2AgentK <..d..> kas.gitlab.com
cluster3AgentK <--d--> kas.gitlab.com
kubectl <--d--> kas.gitlab.com

together {
  frame "gprd-gitlab-cell-1" <<gcp>> {
    component kas as kasCell1
    component webservice as webserviceCell1
    component redis as redisCell1
    collections "gitaly(s)" as gitalyCell1

    kasCell1 <-d-> webserviceCell1
    kasCell1 <-d-> redisCell1
    kasCell1 <-d-> gitalyCell1
  }

  frame "gprd-gitlab-cell-2" <<gcp>> {
    component kas as kasCell2
    component webservice as webserviceCell2
    component redis as redisCell2
    collections "gitaly(s)" as gitalyCell2

    kasCell2 <-d-> webserviceCell2
    kasCell2 <-d-> redisCell2
    kasCell2 <-d-> gitalyCell2
  }
}

"routing service" <--d--> kasCell1
"routing service" <--d--> kasCell1
"routing service" <..d..> kasCell2
"routing service" <..d..> kasCell2

@enduml

リング

リングは、プロビジョニングする Cell と既存のインフラストラクチャをどのようにグループ化するかというメンタルモデルの基礎となります。 リングの内部には X 個の Cell があり、後続のリングはより多くの Cell を含み、フリート全体を段階的にカバーします。 各リングは前のリングのスーパーセットになります。 例えばリングゼロにはリングゼロの Cell のみが含まれ、 リング 5 には リング 5 の Cell とその前のすべてのリングが含まれます。 変更は内側のリングから外側のリングへと段階的にカスケードします。 例えば変更が リング 5 に達した場合、リング 4、3、2、1 にも達しています。

どのタイプのロールアウトも リング 0 から始まり、変更が成功すれば後続のリングに移行します。 失敗した場合はロールアウトを停止でき、すべての顧客に影響を与えません。 このような段階的なロールアウトにより、以下のメリットが得られます:

  1. 変更の爆発半径が小さくなり、すべての顧客に一度に影響を与えません。
  2. 変更をロールアウトする方法に明確な境界があります。
  3. ステージングのような異なる環境を持つ必要がなくなり、すべての Cell が本番環境になります。
  4. 変更への信頼度が高まるほど、対象者が広がります。
@startuml

skinparam frame {
  borderColor<<Cells 1.0>> #0F9D58
}

skinparam frame {
  borderColor<<Cells 1.5+>> #F4B400
}

left to right direction

frame "Ring 3" <<cells 1.5+>> {
  component "01HWRY6Y73W6TW3BHC"
  component "01HWRY6Y740CZSBCGB"
  component "01HWRY6Y74AHZ0AFZ1"
  component "01HWRY6Y743018H2N7"

  frame "Ring 2" <<Cells 1.0>> {
    component "01HWRY6Y74HM0SKTZ9"
    component "01HWRY6Y74YZF5DX5C"
    component "01HWRY6Y74QYG7VV2Y"
    component "01HWRY6Y745BE459Y6"
    component "01HWRY6Y74915AAS8E"
    component "01HWRY6Y74EV3ZVXF5"
    component "01HWRY6Y74REVKJK3P"
    component "01HWRY6Y748ZBGR9G1"
    component "01HWRY6Y74AR5HHJ4H"
    component "01HWRY6Y743V5085XK"

    frame "Ring 1" <<Cells 1.0>> {
      frame "Ring 0" <<Cells 1.0>> {
        component "Canary stage" <<legacy>> as cny
        component "01HWRY6Y745RS405F6"
      }

      component "Main stage\nLegacy Cell" <<legacy>> as Legacy
    }
  }
}

@enduml

Cells 1.0 では、リング 2 内に最大 10 個の Cell を目標としています。 リング内の Cell 数は任意であり、そのサイズはまだ決定されていません。 公開リリース前に auto-deploy パッケージを適切にテストする必要性、 セキュリティ修正のための本番ロールアウトの速度、 そしてユーザーへの障害やバグからの保護を考慮します。

最終的にはリングを使って Cell 環境でのすべての変更の管理に使用します。

ステージング

リングには従来のステージング環境がありません。 なぜなら、最初のリングで変更をテストできるため、同じ結果が得られるからです。 これは既存のステージング環境をシャットダウンするという意味ではなく、 Cell 以外のインフラストラクチャには引き続き使用されます。

この設定により、現在ステージングで抱えているいくつかの問題を解消できます:

  1. ステージングは本番環境の真の表現ではありません。
  2. デプロイメントをブロックするため、ステージングを本番として扱っています。
  3. ステージングの設定が本番から逸脱する可能性があります。

大規模ドメイン

インフラストラクチャは多面的であり、すべてのチームが Cell インフラストラクチャの設定に役割を持っています。

信頼度 列は、特定のドメインとその Cell に向けた方向性についてどれだけ自信があるかを示しています。 ブループリントがマージされた場合、そのドメインに方向性を提供するブループリントがあるため、信頼度は 👍 に移行するのが理想的です。

ドメインオーナーブループリント信頼度
ルーティングgroup::tenant scaleブループリント👍
Cell コントロールプレーンgroup::Delivery/team::FoundationsTo-Do👎
Cell サイジングteam::Scalability-ObservabilityTo-Do👎
CI ランナーteam::Scalability-Practicesブループリント👎
データベースteam::Database Reliabilityブループリント👍
デプロイメントgroup::Deliveryブループリント👍
オブザーバビリティteam::Scalability-Observabilityブループリント👎
Cell アーキテクチャとツールteam::Foundationsブループリント👍
プロビジョニングteam::FoundationsTo-Do👎
設定管理/ロールアウトteam::FoundationsTo-Do👎
障害復旧team::Production Engineeringブループリント👎
@startuml
skinparam component {
    BackgroundColor White
    BorderColor Black
}

rectangle "Domains as Downstream Dependencies" #line.dashed {
    component "Control Plane"
    component "Cell Sizing"
    component "Databases"
    component "Routing"
    component "CI Runners"
    component "Cell Architecture and tooling"
}

component "Deployments"
component "Observability"
component "Provisioning"
component "Configuration Management"

"Deployments" -d-> "Control Plane" : Ring Definition
"Deployments" -d-> "Provisioning": Cell needs to exist to deploy
"Configuration Management" -d-> "Control Plane": Ring Definition
"Provisioning" -d-> "Cell Sizing": Size we are going to Provision
"Provisioning" -d-> "Databases": Database to provision
"Provisioning" -d-> "Observability": Observability infrastructure part of provisioning
"Provisioning" -d-> "CI Runners": How to provision CI Runners
"Provisioning" -d-> "Cell Architecture and tooling": What to provision
"Observability" -d-> "Provisioning": Cell needs to exist to observe
"Configuration Management" -d-> "Provisioning": Cell needs to exist to configure

@enduml

ステークホルダー

Cell の運用には複数のチームが参加しています。 最初の区別は、ツールを実装・保守するチームと、それらのツールを使用するチームの間です。

エリア機能オーナー
Dedicated ツールとの統合*
リリースマネージャーのワークフローとの統合team::Delivery-Deployments
InstrumentorAMP を使用したデプロイメントの仕組みteam::Foundations
Cell アプリケーションの参照アーキテクチャとオーバーレイteam::Ops
Cell のブートストラップ、ツール、および補助インフラストラクチャteam::Ops
Cell のデプロビジョニングteam::Ops
クラスター状態のコントロールプレーン**
GitOps モデルの調査team::Delivery-Deployments
CRD + オペレーターの調査team::Delivery-Deployments
リングベースのデプロイメント自動化
リング境界内での変更の伝播team::Delivery-Deployments
リング境界外での変更伝播のオーケストレーションteam::Foundations
緊急ブレーキ: パッケージロールアウトの停止team::Delivery-Deployments
ロールバック機能
ダウンタイムありのロールバック(リング 0 の QA Cell 向け)team::Delivery-Deployments
ロールバックサポートのための遅延ポストデプロイマイグレーションgroup::environment automation
オブザーバビリティ
Cell ヘルスメトリクスteam::Scalability-Observability
フリートヘルスメトリクスteam::Scalability-Observability
パッケージ状態team::Delivery-Deployments
インシデントライフサイクル管理
エンジニア・オン・コールへのページングteam::Ops
インシデントツールteam::Ops
ネットワークエッジ
Web アプリケーションファイアウォールteam::Foundations
CDNteam::Foundations
負荷分散とネットワーキングteam::Foundations
レート制限team::Foundations

* これらのアイテムは、SaaS プラットフォームとコアプラットフォームのさまざまなステークホルダーからの貢献が必要な場合があります。ステークホルダーはオーナーチームと顧客チームのニーズを満たすための適切なアライメントを確保するためにこの作業を緊密に連携すべきです。

** これらのアイテムは Cell 2.0 イテレーション後の検討事項です。

これらの機能のユーザーは、リリースマネージャー、エンジニア・オン・コール、および Team:Ops です。 以下のリストは、これらのグループが Cell クラスターで実行できるタスクを定義しています:

  1. リリースマネージャー
    • 境界内のデプロイメントの指揮
    • 「graduated」パッケージの宣言
    • 境界内のデプロイメントのロールバック
  2. エンジニア・オン・コール
    • 失敗したデプロイメントのアラート受信
    • パッケージロールアウトの一時停止(次のリングへの到達を阻止)
    • 失敗したデプロイメントの調査の推進
  3. Team::Ops
    • Cell のブートストラップ
      • プロビジョニング
      • デプロビジョニング
      • 再バランシング
      • Cell とリングの関連付け

Cell アーキテクチャとツール
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
Cells と Dedicated の違い
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
Cells におけるフィーチャーフラグの設定
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
Cells における変更の調整
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
Cells ネットワーキング
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
Cells: Runner
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
Cells: フリートにおける Cells の可観測性
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
Protocells 障害復旧
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
データベースプラットフォーム
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …
セルラーアーキテクチャを用いたアプリケーションデプロイメント
このページには今後予定されている製品・機能・機能性に関する情報が含まれています。ここに示す情報は参考目的のみです。購入・計画の決定にこの情報を使用しないでください。製品・機能・機能性の開発、リリー …