Amazon Web Services ブログ
Amazon EKS クラスター向けのマルチテナント設計時の考慮事項
この投稿は、AWS ソリューションアーキテクトの Roberto Migli による寄稿です。
Amazon Elastic Kubernetes Service (Amazon EKS) は、今日、コンテナアプリケーションを大規模に実行するために、数千の顧客が使用しています。よくある質問の中でも、マルチテナントの Amazon EKS クラスターをチームに提供することについてよく耳にします。 1 つまたは多くのクラスターを実行する必要がありますか? チームごと、環境ごと、アカウントごとに 1 つのクラスターを使用する必要がありますか? 正解や不正解はありません。この投稿では、正しい判断を下すためにいくつかの側面を検討していきます。
問題
マルチテナンシーでは、異なるワークロードまたはチームが同じクラスターを共有し、それらをある程度、論理的または物理的に分離する必要があります。さまざまな理由から分離が必要になる場合があります。たとえば、セキュリティは、各チームが意図したワークロードでのみ動作し、他のチームのワークロードでは動作できないようにするか、アプリケーション間でネットワークを分離 (デフォルトでは、すべての名前空間内のすべてのポッドが相互通信できる) します。もう 1 つの理由は、同じインフラストラクチャを共有するさまざまなワークロード全体でリソース (CPU、メモリ、ネットワークなど) を公平に配分するためです。顧客ごとにソリューションをデプロイするサービスのソフトウェア企業は、同じクラスター上で複数のテナントを実行することでインフラストラクチャの利用率を高めることができますが、各テナント間をさらに高度に分離する必要があります。
マルチテナンシーのための Kubernetes ネイティブソリューション
Kubernetes は、1 つのクラスター内でマルチテナンシー設計に役立つネイティブの Kubernetes API と構造をいくつか提供します。コンピューティング、ネットワーキング、ストレージの主な構成要素を以下に示します。
分離を計算する
Kubernetes のドキュメントは、名前空間を「複数のユーザー間でクラスターリソースを分割する方法」と定義しているため、マルチテナンシーの基礎となります。Kubernetes オブジェクトのほとんどは名前空間に属しています。下の図には 2 つの名前空間があり、それぞれが互いに実質的に分離されたオブジェクトのセットを実行しています。
名前空間はワークロードやユーザーの分離を提供しませんが、次のコンポーネントを理解するための核心です。1 つ目はロールベースのアクセスコントロール (RBAC) です。Kubernetes API で誰が何を実行できるかを定義する方法を提供します。承認は ClusterRole を介してクラスターに適用することも、Role を介して 1 つの名前空間にバインドすることもできます。たとえば、namespace1 と呼ばれる 1 つの名前空間への管理者アクセスを提供するために使用される namespace1-admin ロールを定義し、次のコードで admin-ns1 という名前のグループに関連付けることができます。
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: namespace1-admin
namespace: namespace1
rules:
- apiGroups: ["", "extensions", "apps"]
resources: ["*"]
verbs: ["*"]
- apiGroups: ["batch"]
resources:
- jobs
- cronjobs
verbs: ["*"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: admins-ns1-rb
namespace: namespace1
subjects:
- kind: Group
name: admins-ns1
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: namespace1-admin
apiGroup: rbac.authorization.k8s.io
Amazon EKS は、Kubernetes 用の AWS IAM 認証システムを介して RBAC と IAM を統合し、IAM ユーザーとロールを RBAC グループにマッピングできるようにします。RBAC は、他の分離レイヤーを制御するためにも使用できる中心コンポーネントです。以下ではそれについて語ります。
Kubernetes では、ポッドの CPU とメモリのリクエストと制限を定義できます。ノード上のリソースの競合を防ぎ、スケジューラによるインテリジェントなリソース割り当てを改善するために、開発者はそれらを常に設定する必要があります。リソースクォータを使用すると、ユーザーは 1 つの名前空間内で消費できるリソースまたは Kubernetes オブジェクトの量を制限できます。コンピューティングの観点から、リソースクォータにより、ユーザーは CPU とメモリの制限をネイティブで定義できます。次に例を示します。
apiVersion: v1
kind: ResourceQuota
metadata:
name: mem-cpu-demo
namespace: namespace1
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
リソースクォータを使用すると、ワークロードに限られた範囲のリソースを割り当てて、テナントが互いに干渉するのを防ぐことができます。制限範囲を使用することが可能です。これにより、ユーザーはデフォルト、最小リクエスト、最大リクエストを定義し、ポッドまたはコンテナごとに制限することができます。
テナントは、基盤となるノードインスタンスへのアクセスからも分離する必要があります。Kubernetes ポッドセキュリティポリシー (PSP) では、ユーザーが分離を行うことができます。PSP で制御できる機能は多数ありますが、マルチテナントクラスターを構築するチームは、ポッド内のコンテナが権限モードを有効にできるかどうかを判断する Privileged、およびポッドがノード接続にアクセスできず、近所のネットワークアクティビティをスヌープする可能性を防ぐ HostNetwork を確認する必要があります。Amazon EKS は v1.13 以降の PSP をサポートしています。詳細については、AWS オープンソースブログをご覧ください。
Kubernetes には、他のポッドまたはノードに対して、ポッドをスケジュールできる場所を指定するソリューションもあります。たとえば、ポッドアンチアフィニティを使用すると、次のような構成を使用して、特定のラベルが付いたポッドを同じノードでスケジュールできないようにユーザーが定義できます。
apiVersion: v1
kind: Pod
metadata:
namespace: namespace1
name: workload-1
labels:
team: "team-1"
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: "kubernetes.io/hostname"
namespaces:
- shared-services
labelSelector:
matchExpressions:
- key: "type"
operator: In
values: ["monitoring"]
ここでは、namespace1 でチーム (team-1) というラベル付きのポッドは、同じ名前のノードでスケジュールされません。ビジネスアプリケーションとモニタリングアプリケーション間の干渉を防ぐために、名前空間共有サービスでラベルタイプ (モニタリング) を持つ他のポッドがすでにスケジュールされています。ここでいくつかご注意ください。まず、この機能を使用するには、適切なラベルをワークロードに適用する必要があります。次に、ハード要件を尊重するためにチームが最終的にノードを使用できなくなる可能性があるため、この設定を大規模に維持することが難しくなる可能性があります。最後に、ポッド間アフィニティと非アフィニティを使用するには、コントロールプレーンに高いワークロードが必要であり、数百以上のノードを持つクラスターでは推奨されません。同様に、nodeSelectors および nodeAffinity を使用して、特定のノードにポッドを割り当てることができます。
別途指定されていない限り、通常はポッドのスケジュールから除外されるノードを使用したい場合はどうなりますか? 汚染と寛容の出番です。クラスター管理者は、上記の例を使用して、次のようなノードグループ設定ファイルを使用して、モニタリングおよび管理ワークロードに使用する必要がある専用のワーカーグループを EKS に作成することを好む場合があります。
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: dev-cluster
region: eu-west-1
nodeGroups:
- name: ng-monitoring
instanceType: c5.8xlarge
desiredCapacity: 2
taints:
monitoring: "true:NoSchedule"
この汚染により、汚染に耐えられないノードは、このノードグループでスケジュールされません。
別の可能性は、EKS で AWS Fargate を使用することです。Fargate は、他のポッドとリソースを共有せずに VM 分離環境で各ポッドを実行し、ノードとして EC2 インスタンスを作成または管理する必要性を取り除きます。
ネットワークの分離
デフォルトでは、ポッドは同じクラスター上のネットワークを介して、異なる名前空間にまたがって通信できます。Kubernetes は、ユーザーがポッド間通信をきめ細かく制御できるようにするネットワークポリシーを提供します。ネットワークポリシーの実装は、実際、ネットワークプラグインに委任されます。デフォルトの EKS クラスターでは、ポッド間ネットワーキングは、Calico をサポートして Kubernetes ネットワークポリシーを実施する Amazon VPC CNI プラグインに委任されます。テナントを名前空間で分離すると仮定すると、次のネットワークポリシーを使用して、名前空間 namespace1 内でのみネットワーク通信を許可できます (つまり、この名前空間から同じクラスター上の他の名前空間への通信、およびその逆は拒否されます)。
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-np-ns1
namespace: namespace1
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
nsname: namespace1
egress:
- to:
- namespaceSelector:
matchLabels:
nsname: namespace1
マルチテナントクラスターでの通信を制限するために使用できるネットワークポリシーにはより高度な設定があり、Amazon EKS ドキュメントには、環境のセットアップ方法に関するクイックスタートと入門書が用意されています。
サービスメッシュでは、単一の EKS クラスターの外部にまで及ぶ可能性のある追加保護モデルを定義することもできます。Istio は非常に人気のあるオープンソースのサービスメッシュであり、トラフィック管理、セキュリティ、および可観測性などの機能を提供します。Istio チームはブログ投稿を通じて、マルチテナントクラスターに Istio をデプロイする方法について詳しく説明しました。EKS ワークショップには、EKS で Istio を設定する方法に関するクイックスタートもあります。さまざまな機能の中で Istio を使用すると、ユーザーはさまざまなネットワークレイヤーで機能する認証および承認ポリシーを定義できます。たとえば、L3 と L4 でのネットワークフローを制御するネットワークポリシーと、JWT を使用した L7 でのトークンベース認証の組み合わせを使用して、異なるテナントのサービスが通信する方法 (または通信しない方法) をより適切に制御できます。
AWS App Mesh は、アプリケーション内のすべてのサービスに対して一貫した可視性とネットワークトラフィック制御を提供する、マネージド型のサービスメッシュです。AWS App Mesh は Envoy に基づいており、サービスメッシュのコントロールプレーンの完全マネージド型の体験を提供します。テストのために、ドキュメントに Amazon EKS のクイックスタートが用意されています。
ストレージの分離
共有クラスターを使用するテナントでは、さまざまなタイプのストレージタイプが必要になる場合があります。Kubernetes は、ストレージを管理するためのさまざまなツールセットを提供しています。主なものはボリュームであり、永続ストレージの形式をポッドに接続し、そのライフサイクルを管理する方法を提供します。ここでは、上記の計算セクションで説明したように、ノードから直接マウントされたボリュームについては説明しません (PSP を使用したマルチテナント設計では、すべてのローカルボリュームアクセスを無効にする必要がある場合があります)。代わりに、PersistentVolume (PV) サブシステムのいくつかの主要機能と、PersistentVolumeClaim (PVC) との関係について説明します。
PV はクラスターレベルで宣言され、StorageClass も宣言されます。クラスター管理者は実際に、可能なドライバー、設定、および操作を集中的に定義します。Amazon EKS を使用すると、Amazon EBS (ツリー内プラグインと CSI プラグインの両方)、Amazon EFS、FSx for Lustre など、さまざまなストレージクラスがすぐに利用できます。PVC を使用すると、ユーザーはストレージクラスで定義されたポッドのボリュームをリクエストできます。PVC は名前空間リソースとして定義されているため、ストレージへのテナンシーアクセスを制御する方法を提供できます。管理者は、ストレージリソースクォータを使用して、特定の名前空間に属するストレージクラスを定義できます。たとえば、名前空間 namespace1 からストレージクラス storagens2 の使用を無効にするには、次のような ResourceQuota を使用できます。
apiVersion: v1
kind: ResourceQuota
metadata:
name: storage-ns1
namespace: namespace1
spec:
hard:
storagens2.storageclass.storage.k8s.io/requests.storage: 0
複数のクラスターによる分離
可能な代替手段は、複数の単一テナントの Amazon EKS クラスターを使用することです。この戦略により、各テナントは、共有 AWS アカウント内で、または大企業の組織専用アカウントを使用して、独自の Kubernetes クラスターを使用する可能性があります。
クラスターは、自己プロビジョニングすることも、標準化された設定が既にデプロイされている中央チームから提供してもらうこともできます。後者では、中央チームにとって重要な 2 つのフェーズがあります。クラスターのプロビジョニングと複数クラスターのモニタリングです。
Amazon EKS はコントロールプレーンを完全に管理しますが、お客様は新しく作成されたクラスターに標準設定セットを提供する必要があります。Terraform は、このような状況で Kubernetes プロバイダーを使用できます。Kubernetes プロバイダーは、上記の PSP またはネットワークポリシーを自動化された方法でデプロイできます。EKS には、リージョンごとに、アカウントごとに 100 EKS クラスターのサービスクォータがあり、リクエストに応じて変更できます。
クラスターがデプロイされたら、デプロイされたすべてのクラスターの概要を確認して各テナントをモニタリングし、最新バージョンの EKS コントロールプレーンを実行して大規模に運用していることを確認します。Rancher は、複数の Kubernetes クラスターの管理に使用される人気のあるオープンソースツールです。デプロイ方法と使用方法の詳細については、オープンソースブログのこの記事を確認してください。
まとめ
この投稿では、コンピューティング、ネットワーキング、ストレージの観点から、AWS 上の Amazon EKS のマルチテナント設計を実現するためのいくつかの考慮事項について説明しました。前述の戦略を採用する場合、実装のコストと複雑さに対して重み付けする必要があることにご注意ください。そのため、テナントごとに単一の Amazon EKS クラスターを使用するアプローチは魅力的ですが、複数のクラスターをデプロイして管理する機能が必要となります。チームは、Amazon ECS を使用して、テナントごとのクラスターを迅速にプロビジョニングすることについても検討する必要があります。最後に、AWS は AWS SaaS Factory を介してマルチテナントアプリケーションを構築するパートナーと ISV にヘルプを提供します。
参考文献
- AWS re:Invent 2019: Amazon EKS を使用したマルチテナント PaaS サービスの設計
- AWS パートナーネットワークのブログ投稿: テナントあたりの SaaS コストの計算 – AWS Kubernetes 環境での PoC 実装
- Pivotal ブログ: Kubernetes: 1 つのクラスターが必要ですか、それとも複数のクラスターが必要ですか?