エンタープライズ マルチテナンシーのベスト プラクティス


Google Kubernetes Engine(GKE)のマルチテナンシーは、テナント間で共有される 1 つ以上のクラスタです。Kubernetes では、テナントは次のいずれかになります。

  • 1 つ以上のワークロードの開発と運用を担当するチーム。
  • 関連する一連のワークロード(1 つ以上のチームが運営している場合も含む)。
  • 単一のワークロード(Deployment など)。

多くの場合、クラスタ マルチテナントは、コストの削減や、テナント間で一貫して管理ポリシーを適用することを目的に実装されます。ただし、GKE クラスタや関連する GKE リソースを正しく構成しないと、コストの削減や一貫したポリシーの適用という目的が達成できないだけでなく、別のテナントのワークロードに悪影響を及ぼす場合もあります。

このガイドでは、企業組織に複数のマルチテナント クラスタを安全かつ効率的に設定するためのベスト プラクティスについて説明します。

前提条件と要件

このガイドで説明するベスト プラクティスは、企業環境のマルチテナントのユースケースに基づいています。次の前提条件と要件があります。

  • 組織とは、Kubernetes を使用し、コンピューティング リソースと管理リソースを共有する可能性がある複数のテナント(2 つ以上のアプリケーション チームまたはサービスチーム)を所有している 1 つの企業です。
  • 各テナントは、単一のワークロードを作成する 1 つのチームです。
  • アプリケーション チームやサービスチーム以外にも、プラットフォーム チームメンバー、クラスタ管理者、監査者など、クラスタを利用して管理するチームもあります。
  • プラットフォーム チームはクラスタを所有し、各テナントチームが使用できるリソースの量を定義します。それぞれのテナントはリソースの増加をリクエストできます。
  • 各テナントチームは Kubernetes API を使用してアプリケーションをデプロイできます。このデプロイをプラットフォーム チームに連絡する必要はありません。
  • API 呼び出し、共有データソースなど、設計上の明示的な決定を除き、共有クラスタ内の他のテナントに影響が及ぶことはありません。

この設定は、マルチテナントのベスト プラクティスを説明するモデルとなります。この設定では、すべての企業組織を網羅する説明はできませんが、同様のシナリオには簡単に応用できます。

フォルダ、プロジェクト、クラスタの設定

企業組織が GKE にマルチテナント クラスタをデプロイする場合、1 つのアプリケーションと 1 つのチームしか存在しない単純な Kubernetes 環境と比べると、環境の管理が複雑になります。こうした複雑さを管理するために、他の Google Cloud システムで追加の構成が必要になります。たとえば、管理上の問題を分離するようにプロジェクトを構成するだけでなく、組織構造をクラウドの ID とアカウントにマッピングし、Google Cloud リソース(データベース、ロギング、モニタリング、ストレージ、ネットワークなど)を管理するように構成する必要があります。

フォルダとプロジェクトの階層を設定する

組織が Google Cloud のリソースをどのように管理しているのかを確認し、問題を分離するには、フォルダプロジェクトを使用します。プロジェクトを使用して環境(本番環境とステージングなど)とチームを分離し、フォルダを使用して、複数のプロジェクト間で適用されるポリシーの設定を異なるチームに許可できます。たとえば、大半の組織の場合、ネットワーク インフラストラクチャを管理するチームと、クラスタを管理するチームが存在します。それぞれの技術は、独自の専門知識、トラブルシューティング、アクセスを必要とする個別のスタックとみなされます。

親フォルダには最大 300 個までのフォルダを作成できます。また、フォルダは最大で 10 レベルまでネストできます。300 以上のテナントがある場合は、制限内に収まるようにテナントを階層構造に編成できます。フォルダの詳細については、フォルダの作成と管理をご覧ください。

IAM を使用してロールを割り当てる

Google Cloud リソースへのアクセスは、IAM ポリシーで制御できます。まず、組織に必要なグループとそのオペレーションのスコープを特定し、適切な IAM ロールをグループに割り当てます。

Google グループを使用すると、ユーザーの IAM を効率的に割り当て、管理できます。

ネットワーク制御を一元管理する

サブネット、ルート、ファイアウォールなどのネットワーク リソースを一元管理するため、共有 VPC ネットワークを使用します。共有 VPC 内のリソースは、内部 IP を使用することで、プロジェクトの境界を越えて安全で、効率的に通信を行うことができます。共有 VPC ネットワークは、一元管理されたホスト プロジェクトによって定義され、所有されています。このネットワークは、1 つ以上のサービス プロジェクトで使用できます。

共有 VPC と IAM を使用すると、ネットワーク管理とプロジェクト管理の分離が可能になります。これにより、最小権限の原則を実装しやすくなります。たとえば、一元管理されたネットワークのチームは、参加しているプロジェクトに対する権限がなくてもネットワークを管理できます。同様に、プロジェクト管理者は、共有ネットワークの操作権限なしでプロジェクトのリソースを管理できます。

共有 VPC を設定する場合は、VPC でサブネットとセカンダリ IP 範囲を構成する必要があります。サブネット サイズを決める場合は、予想されるテナントの数、実行予定の Pod と Service の数、最大 Pod サイズと平均 Pod サイズを確認する必要があります。必要なクラスタの合計容量を計算すると、目的のインスタンス サイズを把握できます。また、これにより、ノードの合計数がわかります。ノードの合計数から、消費される IP 空間の合計量を計算し、必要なサブネット サイズを決めることができます。

ネットワークを設定する際に考慮すべき要素は次のとおりです。

  • ホスト プロジェクトに接続できるサービス プロジェクトの最大数は 1,000 個です。1 つの組織で使用できる共有 VPC ホスト プロジェクトの最大数は 100 個です。
  • ノード、Pod、Service の IP 範囲はすべて一意にする必要があります。プライマリ IP アドレスとセカンダリ IP アドレスの範囲が重複するサブネットは作成できません。
  • 特定の GKE クラスタの Pod と Service の最大数は、クラスタのセカンダリ範囲のサイズによって制限されます。
  • クラスタの最大ノード数は、クラスタのサブネットのプライマリ IP アドレス範囲とクラスタの Pod アドレス範囲のサイズによって制限されます。
  • IP アドレスをより柔軟に管理をするため、ノードで実行可能なノードの最大数を構成します。ノードあたりの Pod 数を減らすと、ノードあたりの CIDR 範囲が小さくなり、必要な IP アドレスも少なくなります。

クラスタのサブネットを計算する際に、オープンソースの GKE IPAM 計算ツールを使用できます。IP アドレス管理(IPAM)を使用すると、IP 空間やサブネットを効率的に使用し、範囲の重複を回避できます。将来的に接続オプションは不要になるかもしれません。VPC クラスタのネットワーク範囲の詳細については、VPC ネイティブ クラスタの作成をご覧ください。

共有クラスタ外で実行されるリソース(専用の Compute Engine VM など)の分離が必要なテナントでは、独自の VPC を使用する場合があります。この VPC は、ネットワーク チームが運用する共有 VPC にピアリングされます。この場合、セキュリティは強化されますが、煩雑さが増し、さまざまな制限が発生します。ピアリングの詳細については、VPC ネットワーク ピアリングの使用をご覧ください。以下の例では、すべてのテナントが 1 つの(環境ごとの)テナントの VPC 共有を選択しています。

信頼性と可用性の高いクラスタを作成する

高可用性と信頼性を兼ね備えたクラスタ アーキテクチャを設計するには、次の推奨事項を実施します。

  • クラスタごとに 1 つのクラスタ管理プロジェクトを作成して、プロジェクト レベルの構成(IAM バインディングなど)が多数のクラスタに悪影響を及ぼすリスクを軽減するとともに、割り当てと課金が分離されるようにします。クラスタ管理プロジェクトは、テナント プロジェクトとは別のものです。テナント プロジェクトは、個々のテナントが、たとえば Google Cloud リソースを管理するために使用します。
  • 本番環境のクラスタを限定公開にし、ノードへのアクセスを無効にして、コントロール プレーンへのアクセスを管理します。また、開発環境とステージング環境にも限定公開クラスタの使用をおすすめします。
  • マルチテナンシーの高可用性を実現するには、クラスタのコントロール プレーンがリージョンである必要があります。コントロール プレーンに対する影響はテナントにも及びます。実行中のリージョン クラスタにはコストがかかりますAutopilot クラスタは、リージョン クラスタとしてあらかじめ構成されています。
  • ゾーンの信頼性を維持するには、クラスタ内のノードが 3 つ以上のゾーンにまたがっている必要があります。同じリージョンのゾーン間の下り(外向き)コストについては、ネットワーク料金をご覧ください。
3 つのゾーンで実行されるリージョン コントロール プレーンが存在する限定公開リージョン クラスタ
図 3: 3 つのゾーンで動作するリージョン コントロール プレーンを持つ限定公開リージョン クラスタ。

クラスタノードとリソースの自動スケーリング

テナントの要求に応えるため、自動スケーリングを有効にして、クラスタ内のノードを自動的にスケーリングします。

自動スケーリングを行うと、Namespace 内のさまざまなテナントが負荷の高いワークロードをデプロイしたときや、ゾーンが停止したときに、システムの応答性と健全性を高めることができます。

Autopilot クラスタでは、ワークロードの要件を満たすようにノードプールが自動的にスケーリングされます。

自動スケーリングを有効にする場合、予想されるワークロードのサイズに基づいてクラスタ内のノードの最小数と最大数を指定します。ノードの最大数を指定すると、実行する Namespace に関係なく、クラスタ内のすべての Pod に十分な領域を確保できます。クラスタの自動スケーリングは、最小または最大の境界に基づいてノードプールを再スケーリングします。これにより、システムの負荷が低下した場合は運用コストを抑え、十分なクラスタ リソースを使用できない場合は Pod が保留状態にならないように調整できます。ノードの最大数を決める場合は、各テナントが必要とする CPU とメモリの最大量を特定し、それらの値を合計して合計容量を計算します。これは、すべてのテナントが上限に達したときにクラスタが処理できる容量になります。ノードの最大数を使用すると、クラスタで使用可能な IP サブネット空間を考慮して、インスタンスのサイズと数を選択できます。

Pod 自動スケーリングを使用して、リソースの需要に基づいて Pod を自動的にスケーリングします。水平 Pod オートスケーラー(HPA)は、CPU / メモリの使用量またはカスタム指標に基づいて、Pod のレプリカの数をスケーリングします。垂直 Pod 自動スケーリング(VPA)を使用して、Pod リソースの需要に基づいて自動的にスケーリングできます。2 つのオートスケーラーが相互に競合する可能性があるため、カスタム指標を利用できない場合は、HPA で使用しないでください。このため、HPA で開始して、必要な場合にのみ VPA を使用します。

クラスタのサイズを確認する

クラスタのサイズを決める場合は、考慮すべき重要な要素があります。次の点に注意してください。

  • クラスタのサイズは、実行するワークロードのタイプによって異なります。ワークロードの密度が高い場合、コスト効率は高くなりますが、リソース競合の可能性も大きくなります。
  • クラスタの最小サイズは、クラスタがまたがるゾーンの数によって決まります。ゾーンクラスタの場合は 1 つのノード、リージョン クラスタの場合は 3 つのノードで定義されます。
  • 1 つのプロジェクトで、ゾーンあたり最大クラスタ数は 50、リージョンあたりのリージョン クラスタ数は 50 になります。
  • 1 つのクラスタで、クラスタあたりの最大ノード数は 15,000(GKE バージョン 1.17 以前では 5,000)、ノードプールあたりのノード数は 1,000、クラスタあたりのノード数は 1,000(GKE Ingress コントローラを使用する場合)、ノードあたりの Pod 数は 256(1.23.5-gke.1300 より前のバージョンの GKE では 110)、クラスタあたりの Pod 数は 150,000、クラスタあたりのコンテナ数は 300,000 になります。詳細については、割り当てと上限のページをご覧ください。

メンテナンスの時間枠を設定する

クラスタやノードのアップグレードとメンテナンス時のダウンタイムを減らすには、メンテナンスの時間枠をオフピーク時間に設定します。アップグレードで、ノードを再作成するためにワークロードを移動するときに、一時的な中断が発生することがあります。このような中断の影響を最小限に抑えるために、オフピーク時にアップグレードを行うようにスケジュールを設定し、部分的な中断を可能な限りシームレスに処理できるようにアプリケーションのデプロイを設計します。

Ingress を使用して外部アプリケーション ロードバランサを設定する

テナントに公開されている Service や、これらの Service への受信トラフィックを管理するため、クラスタごとに 1 つの内向き(上り)トラフィックを許可する HTTP(S) ロードバランサを作成します。ここでは、各テナントの Service がクラスタの Ingress リソースに登録されます。HTTP(S) ロードバランサを作成して構成するには、Kubernetes Ingress リソースを作成します。これにより、トラフィックが Service に到達する方法とトラフィックがテナントのアプリケーションに転送される方法を定義します。Ingress リソースに Service を登録することで、Service の命名規則が統一され、tenanta.example.comtenantb.example.com などのように 1 つの Ingress を表すようになります。

マルチテナンシー対応のクラスタをセキュリティで保護する

ネットワーク ポリシーで Pod 通信を制御する

クラスタの Namespace 内の Pod 間で行われるネットワーク通信を制御するため、テナントの要件に基づいてネットワーク ポリシーを作成します。まず、異なるテナントのアプリケーションをホストする Namespace の間で発生するトラフィックをブロックする必要があります。クラスタ管理者は、Pod が 1 つの Namespace から他の Namespace の Service またはデータベースに誤ってトラフィックを送信しないようにするため、deny-all ネットワーク ポリシーを適用して、すべての上り(内向き)トラフィックを拒否できます。

たとえば、他のすべての Namespace から tenant-a Namespace への上り(内向き)トラフィックを制限するネットワーク ポリシーは次のようになります。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: tenant-a
spec:
  podSelector:
    matchLabels:

  ingress:
  - from:
    - podSelector: {}

GKE Sandbox でワークロードを実行する

信頼できないワークロードを実行するクラスタは、他のクラスタよりも攻撃を受ける可能性が高くなります。GKE Sandbox を使用すると、マルチテナント環境でワークロード間の分離境界を強化できます。セキュリティ管理のため、まず GKE Sandbox を使用し、その後でポリシーベースのアドミッション制御を使用してギャップを埋めることをおすすめします。

GKE Sandbox は、オープンソースのコンテナ サンドボックス プロジェクトの gVisor をベースにしています。コンテナとホスト OS の間にレイヤを追加し、マルチテナント ワークロードの分離を強化します。ノード上でコンテナ ランタイムは特権ユーザーとして実行され、ホストカーネルのほとんどのシステムコールにアクセスできます。マルチテナント クラスタでは、1 つの悪意のあるテナントがホストカーネルや他のテナントのデータにアクセスする可能性があります。GKE Sandbox は、コンテナとホスト間の通信の必要性を減らすことで、こうした脅威を回避します。これにより、ホストで攻撃される領域が限定され、攻撃者の動きが制限されます。

GKE Sandbox は、コンテナとホスト OS の間に 2 つの分離境界を提供します。

  • ユーザー空間カーネル。このカーネルは Go で記述されています。システムコールを処理し、ホストカーネルとの通信を制限します。Pod ごとに独立したユーザー空間カーネルがあります。
  • ユーザー空間カーネルは、Namespace 内と seccomp フィルタリング システムコール内でも実行されます。

ポリシーベースのアドミッション制御を設定する

セキュリティ境界に違反する Pod がクラスタ内で実行されないようにするには、アドミッション コントローラを使用します。アドミッション コントローラを使用すると、定義したポリシーと照らし合わせて Pod の仕様を確認し、それらのポリシーに違反している Pod がクラスタで実行されるのを防ぐことができます。

GKE では、次のタイプのアドミッション制御がサポートされています。

GKE 用 Workload Identity 連携を使用して Google Cloud サービスへのアクセスを許可する

ワークロードに Google Cloud サービスへのアクセス権を安全に付与するには、クラスタで GKE 用 Workload Identity 連携を有効にします。GKE の Workload Identity 連携により、管理者は、Kubernetes ワークロードが Google Cloud サービスへのアクセスに使用する Kubernetes サービス アカウントを管理できます。GKE 用 Workload Identity 連携を有効にしてクラスタを作成すると、クラスタが格納されているプロジェクトに ID の Namespace が確立されます。ID の Namespace により、クラスタは Kubernetes サービス アカウント名を仮想の Google サービス アカウント ハンドルにマッピングし、GKE アプリケーションに対するサービス アカウントの認証を自動的に行います。これは、テナントの Kubernetes サービス アカウントに IAM を割り当てる場合に使用されます。

コントロール プレーンへのネットワーク アクセスを制限する

コントロール プレーンを保護するには、承認済みネットワークへのアクセスを制限します。GKE で承認済みネットワークを有効にすると、最大 50 個の CIDR 範囲を承認し、その範囲内の IP アドレスにのみコントロール プレーンへのアクセスを許可できます。GKE では、Transport Layer Security(TLS)と認証を使用して、公共のインターネットからコントロール プレーン エンドポイントへのアクセスを保護しています。承認済みネットワークを使用することで、特定の IP アドレスセットに対するアクセスをさらに制限できます。

テナント プロビジョニング

テナント プロジェクトを作成する

テナントの非クラスタ リソースをホストするには、テナントごとにサービス プロジェクトを作成します。これらのサービス プロジェクトには、テナント アプリケーション固有の論理リソース(ログ、モニタリング、ストレージ バケット、サービス アカウントなど)が含まれます。テナントのサービス プロジェクトはすべてテナントのホスト プロジェクトの共有 VPC に接続します。

RBAC を使用してテナントへのアクセスを限定する

Kubernetes RBAC を使用して、テナントのクラスタ リソースへのアクセス権をきめ細かく定義します。IAM でテナント グループに最初に付与される読み取り専用アクセス権のほかに、各テナント グループに Namespace 全体の Kubernetes RBAC ロールとバインディングを定義します。

テナント管理者とテナント デベロッパーという 2 つのテナント グループがあります。このグループに対して、次の RBAC ロールとアクセス権を定義します。

グループ Kubernetes
RBAC ロール
説明
テナント管理者 Namespace 管理者

Namespace 内の Deployment の一覧取得と監視を許可します。

テナント グループに対するユーザーの追加または削除を許可します。

テナント デベロッパー Namespace 編集者、
Namespace 閲覧者
Namespace 内の Pod、Deployment、Service、ConfigMap の作成、編集、削除を許可します。

Namespace 内に Google Workspace または Cloud Identity グループのさまざまな権限を割り当てる RBAC のロールとバインディングを作成するだけでなく、テナント管理者が各グループのユーザーを管理するために権限を必要とすることが少なくありません。組織の要件に応じて、Google Workspace または Cloud Identity の権限をテナント管理者に委任し、グループ メンバーを管理できるようにするか、Google Workspace または Cloud Identity の権限を持つ組織のチームとテナント管理者が一緒に変更を処理するようにします。

IAM と RBAC の権限を Namespace と併用すると、Google Cloud コンソールのクラスタ リソースに対するユーザー操作を制限できます。詳細については、アクセスを有効にしてクラスタ リソースを名前空間ごとに表示するをご覧ください。

Google グループを使用して権限をバインドする

クラスタ内でテナントの権限を効率的に管理するには、RBAC 権限を Google グループにバインドします。これらのグループのメンバーは、Google Workspace 管理者によって管理されています。このため、クラスタ管理者にはユーザーに関する詳細情報が必要になりません。

たとえば、tenant-admins@mydomain.com という Google グループがあり、admin1@mydomain.com という名前のユーザーがそのグループのメンバーとします。次のバインディングにより、このユーザーには tenant-a 名前空間に対する管理者権限が付与されます。

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  namespace: tenant-a
  name: tenant-admin-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: tenant-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
  kind: Group
  name: "tenant-admins@mydomain.com"

Namespace を作成する

同じクラスタにあるテナント間を論理的に分離するには、Namespace を実装します。Kubernetes RBAC のプロセスで、クラスタ管理者はテナント グループごとに Namespace を作成します。テナント管理者は、テナント Namespace 内のユーザー(テナント デベロッパー)を管理します。テナント デベロッパーは、アプリケーションをデプロイするため、クラスタとテナント固有のリソースを使用できます。

Namespace の上限到達を回避する

理論上、クラスタ内の Namespace の最大数は 10,000 ですが、いくつかの要因のため、実際にこの上限に達することはありません。たとえば、Namespace の最大数に達する前に、クラスタ全体の最大 Pod 数(150,000)とノード数(5,000)に達することがあります。また、他の要因(例: Secrets 数など)により、有効な上限がさらに下がることもあります。結果として最初の段階では、うまく機能しないことが証明されない限り、1 回に 1 つの制約について理論上の制限値に近づけ、他の制限から 1 桁近く離しておくのが最もよい方法です。1 つのクラスタでサポートできるリソースよりも多くのリソースが必要な場合は、さらにクラスタを作成する必要があります。Kubernetes のスケーラビリティの詳細については、Kubernetes スケーラビリティのしきい値をご覧ください。

Namespace の命名規則を標準化する

異なるクラスタにホストされている複数の環境で簡単にデプロイできるように、Namespace に使用する命名規則を標準化します。たとえば、Namespace の名前に環境名(開発、ステージング、本番環境)を結び付けるのではなく、環境全体で同じ名前を使用します。同じ名前を使用することで、別の環境に移行したときに構成ファイルを変更する必要がなくなります。

テナント ワークロードにサービス アカウントを作成する

テナントの Namespace に存在するワークロードごとに、テナント固有の Google サービス アカウントを作成します。これにより、セキュリティを強化できます。テナントが各自の Namespace で所有またはデプロイするワークロードのサービス アカウントを管理できるようになります。それぞれの Namespace の Kubernetes サービス アカウントは、GKE 用 Workload Identity 連携を使用して 1 つの Google サービス アカウントにマッピングされます。

リソースの割り当てを適用する

クラスタを共有するすべてのテナントがクラスタ リソースに公平にアクセスできるように、リソース割り当てを適用します。各テナントでデプロイされる Pod の数と、各 Pod で必要なメモリと CPU の量に基づいて、Namespace ごとにリソースの割り当てを作成します。

次の例では、tenant-a Namespace の Pod が最大 16 個の CPU と 64 GB のメモリをリクエストするリソース割り当てを定義しています。最大 CPU は 32、最大メモリが 72 GB になっています。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-a
spec:
  hard: "1"
    requests.cpu: "16"
    requests.memory: 64Gi
    limits.cpu: "32"
    limits.memory: 72Gi

モニタリング、ロギング、使用状況

使用状況の指標を追跡する

クラスタの個々の Namespace とラベルで費用の内訳を確認するには、GKE の費用の割り当てを有効にします。GKE の費用の割り当てでは、リソース リクエストやクラスタ ワークロードのリソース使用状況が追跡されます。これは、さらに Namespace やラベルで分類できます。GKE の費用の割り当てを使用すると、クラスタを共有している部門やチームの費用の内訳を計算し、個々のアプリケーションの使用パターン(単一アプリケーションのコンポーネントも含む)を把握できます。これにより、クラスタ管理者は優先度に基づいて使用量の急増に対応し、より適切な容量計画と予算配分を行うことができます。

GKE の費用の割り当てを有効にすると、GKE ワークロードのクラスタ名と Namespace が、BigQuery への課金データのエクスポートのフィールドに表示されます。

テナント固有のログを提供する

プロジェクト ワークロードに固有のログデータをテナントに提供するには、Cloud Logging のログルーターを使用します。テナント固有のログを作成する場合、クラスタ管理者はシンクを作成し、テナントの Google Cloud プロジェクトで作成されたログバケットにログエントリをエクスポートします。

このようなタイプのログを構成する方法については、GKE でのマルチテナント ロギングをご覧ください。

チェックリストの概要

次の表に、企業組織内でマルチテナント クラスタを作成する場合の推奨タスクを示します。

地域 タスク
組織の設定
Identity and Access Management
ネットワーキング
高可用性と信頼性
セキュリティ
ロギングとモニタリング

次のステップ