1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Knative Operator における KnativeServing CR が複数の Knative Serving インスタンスをインストールできる設計上の理由と技術的な背景について

Posted at

設計上の理由 (Design Reasons for Multiple Instances)

● マルチテナンシーの要請: Knative Operatorの設計では、1つのクラスター内に複数のKnative Servingインスタンス(制御プレーン)をデプロイできる柔軟性があります。これはマルチテナンシーを念頭に置いたものです。たとえば企業環境では、アプリケーションチームごとに独立したKnative Serving制御プレーンが必要になる場合があります (Multi-Tenant Control Plane · Issue #4959 · knative/serving · GitHub)。各チームがクラスター全体の権限を持たなくても、自分の名前空間内でKnativeを運用できるようにするためです (Multi-Tenant Control Plane · Issue #4959 · knative/serving · GitHub) (Consider allowing serving controllers to be run for a single namespace)。このようにRBAC権限を名前空間レベルに抑えることで、チームごとに安全にKnativeサービスを提供できるようになります (Consider allowing serving controllers to be run for a single namespace)。

● チームごとの分離と設定の違い: 複数インスタンスを許容することで、異なる設定要件に対応できます。あるチームは特定の自動スケーリング設定やネットワーキング設定を望み、別のチームは別の設定を望むことがあります。KnativeServingカスタムリソース(CR)ごとに独自のConfigMapやIngress設定を持てるため、1つのクラスター内で異なるKnative Servingインスタンスがそれぞれ別個の設定で動作できます (Multi-Tenant Control Plane · Issue #4959 · knative/serving · GitHub)。この分離により、あるテナントの設定変更や不具合が他のテナントに影響を与えないという運用上のメリットがあります。

● スケーラビリティと負荷分散: 制御プレーンを複数走らせることで、負荷の分散やスケーラビリティの向上も期待できます。単一のKnative Servingインスタンスで非常に多数のサービスやリソースを管理すると負荷が集中しますが、インスタンスを分ければコントローラーの負荷を分散できます。例えば、名前空間ごとに異なるKnative Serving制御プレーンを担当させれば、各コントローラーは自分の担当範囲内のリソースだけ監視・管理するため、一箇所に集中するより効率的です(※ただし現状、明示的に担当範囲を分ける機構は後述のとおり制限があります)。このような**シャーディング(分割)**により大規模クラスターでのKnative運用を支える設計とも言えます。

● アップグレード戦略と環境分離: 複数のKnative Servingインスタンスを許容する設計は、アップグレードやテストの容易さにもつながります。たとえば現在稼働中のKnative Serving(あるバージョン)とは別に、新しいバージョンのKnative Servingを別インスタンスとして並行でインストールし、動作検証や段階的な移行を行うことができます (Run 2 Knative serving versions in parallel · Issue #14439 · knative/serving · GitHub)。実際、Knativeのユーザーからは「v1.10とv1.11を並行稼働させたい」といった要望もあり、別々のknative-serving名前空間にインストールする方法が議論されています (Run 2 Knative serving versions in parallel · Issue #14439 · knative/serving · GitHub)。このようにBlue/Greenデプロイ的に新旧バージョンを同時稼働させ、トラフィックを分割したり順次切り替えたりできるのは、複数インスタンスを許す設計のおかげです。加えて、本番環境とステージング環境を同一クラスター内で論理的に分離したい場合にも、インスタンスごとにNamespaceを分けることで実現できます。

● 運用上のメリットと考慮点: 複数のKnative Servingインスタンスを運用するメリットとしては上記のような強い分離性柔軟性が挙げられます。それぞれ独立した制御プレーンがあることで、問題発生時の影響範囲が限定され、異なる要件にも対応しやすくなります。一方で、運用上の考慮点としてリソースオーバーヘッドが増えることがあります。各インスタンスごとにコントローラーやウェブフック、ネットワークコンポーネント(例:Ingressコントローラー)が重複して動作するため、クラスター資源(CPUやメモリ)の消費は単一インスタンス運用時より大きくなります。また運用の複雑さも増すため、どのサービス(Knative Service)がどの制御プレーンに属するかを明確に分けて管理するルール作りが必要です。例えば、名前空間A内のアプリはKnativeServingインスタンスAで管理し、名前空間B内のアプリはインスタンスBで管理するといったポリシーを設ける必要があります。

以上のように、KnativeServing CRで複数インスタンスを管理可能にしているのは、マルチテナント環境や大規模環境での柔軟な運用を可能にするための設計上の判断と言えます。その結果、必要に応じて“Knativeをサービス(Knative as a Service)”のように提供し、単一クラスター上で複数の独立したKnative環境を展開できるのです (Multi-Tenant Control Plane · Issue #4959 · knative/serving · GitHub)。

技術的な背景 (Technical Background of KnativeServing CR and Multi-Instance Support)

● KnativeServing CRの仕様と構造: Knative Operatorは、KnativeServingというカスタムリソース(CR)を通じてKnative Servingのインストールと構成を管理します。このKnativeServing CRD(Custom Resource Definition)はスコープがNamespaced(名前空間スコープ)として定義されており (serving-operator/config/300-serving-v1alpha1-knativeserving-crd.yaml at master · knative/serving-operator · GitHub)、特定のNamespaceに属するリソースです。したがって、クラスター内の異なる名前空間に複数のKnativeServingオブジェクトを作成できます(例: knative-serving名前空間に1つ、knative-serving-prod名前空間にもう1つ、等)。各KnativeServingオブジェクトのspecフィールドには、そのKnative Servingインスタンス用の設定を記述できます。例えば、spec.configの下に各種ConfigMapのキーを指定して、デフォルトの設定値を上書きできます (serving-operator/config/300-serving-v1alpha1-knativeserving-crd.yaml at master · knative/serving-operator · GitHub)。config-networkconfig-autoscalerといった複数のConfigMapに対して値を設定可能で、さらにIngressに使用するGatewayのオーバーライド設定(spec.ingress関連)や、使用するコンテナイメージの参照先上書き(spec.registry関連)、HA構成(spec.highAvailability)などKnative制御プレーンの様々な構成要素をCR一つで定義します (serving-operator/config/300-serving-v1alpha1-knativeserving-crd.yaml at master · knative/serving-operator · GitHub) (serving-operator/config/300-serving-v1alpha1-knativeserving-crd.yaml at master · knative/serving-operator · GitHub)。要するに、KnativeServing CRは「ある名前空間にKnative Servingをこのような設定でインストールしてほしい」というインスタンスごとの望ましい状態を表現するオブジェクトです。

● Kubernetes OperatorにおけるCRD設計原則との関連: KubernetesにおけるOperatorパターンでは、CRDを名前空間スコープにするかクラスタースコープにするかは重要な設計判断です。一般に、特定のアプリケーション(例えばデータベースやウェブサービス)をOperatorで管理する場合、複数インスタンスをデプロイする可能性があるならCRDはNamespacedにします。一方、クラスター全体で一意であるべき設定(例: クラスター構成そのもの)を表すCRDはClusterスコープにします (Namespaced scope CRDs created at cluster level : r/kubernetes)。Knative Operatorは前者のアプローチを採用しており、KnativeServing CRDは名前空間スコープです。これにより、「同じOperatorで管理されるKnative Servingをクラスター内に複数展開する」というシナリオが排除されていません。むしろOperatorの多重インスタンス対応はKubernetesにおけるマルチテナンシー実現の一つの方法であり、Knative Operatorもそれに沿った実装になっていると言えます (Operators in multitenant clusters - Understanding Operators | Operators | OpenShift Container Platform 4.13)。例えばOpenShiftなどの環境では、単一クラスター上にOperatorを複数インスタンス(テナントごとに別々に)インストールすることでマルチテナントを実現するベストプラクティスがあります (Operators in multitenant clusters - Understanding Operators | Operators | OpenShift Container Platform 4.13)。Knative Operatorの場合は、1つのOperator(コントローラー)が複数のKnativeServing CRを見ることで、1対多のインスタンス管理を行います。

なお、Knative OperatorはオープンソースのKnativeコミュニティの思想に沿っており、必要以上に制限を加えない柔軟な設計になっています。単一クラスター=1インスタンスに固定せず、利用者の判断で複数デプロイも選択肢に入れられるようにしている点は、拡張性と柔軟性を重視するKubernetesらしい設計と言えるでしょう。

● Knative Operator内部での複数インスタンス管理: 複数のKnativeServing CRを作成した場合、Knative Operator内部では各CRごとに独立した調停(リコンシリエーション)プロセスが走ります。Operatorは各KnativeServingオブジェクトの望む状態を読み取り、それに合わせてKnative Servingのリソースをデプロイ・設定します。具体的には、各KnativeServing CRの属するNamespaceに、Knative Servingのコアコンポーネント(コントローラー、ウェブフック、アクティベーター、オートスケーラー、ネットワークコンポーネントなど)のDeploymentやService、関連するConfigMap類を配置します (Configuring Knative using the Operator - Knative)。例えばknative-servingという名前空間でCRを作成した場合、そのNamespace内にactivatorautoscaler等のDeployment、およびconfig-xxxというConfigMap群が作成されます (Configuring Knative using the Operator - Knative)。別のNamespaceで別のCRを作れば、同様のリソースがそのNamespace内に作成されます。このとき、OperatorはCRのspecに記載された設定を各インスタンスのConfigMapデータに反映します (Configuring Knative using the Operator - Knative)。たとえばspec.config.domainにドメインのオーバーライドを指定すれば、そのインスタンス用のconfig-domain ConfigMapの内容が書き換わります (Configuring Knative using the Operator - Knative)(他のインスタンスには影響しません)。このようにOperatorはCRの内容を各種マニフェストに反映させて適用し、各Knative Servingインスタンスが独立した挙動を取れるようにしています。

また、Operatorはインスタンスごとにデプロイしたリソースに対してオーナー参照(OwnerReference)を付与し、CRが削除された際にはそれに属するDeploymentやService等を自動クリーンアップできるように管理しています(一般的なOperatorの挙動です)。複数のKnativeServing CRが存在する場合、Operatorはそれぞれについてこの処理を繰り返します。一方で、Knative ServingのCRDそのもの(例: services.serving.knative.devrevisions.serving.knative.dev などのCRD)やClusterRoleなど、クラスター全域に影響するリソースについては、最初のインスタンス作成時に適用され、以降のインスタンス作成時には既に存在するためスキップされるか共用されます。例えば、KnativeServing CRを作成するときOperatorはまずKnativeの標準リソース定義を適用しますが、CRDはクラスター全体で一度作成すればよいため、2つ目以降のインスタンスでは重複作成されません。ただし、Operatorの実装上は「既存のリソースに対しても常に適用を試み、存在すれば更新(内容が同じなら実質的に変化なし)」というアプローチかもしれません。この辺りは実装詳細ですが、ポイントはクラスタースコープのリソースは共有し、名前空間スコープのリソースはインスタンスごとに分離して管理、という形になっていることです。

● 複数インスタンス管理における既存の制約や注意点: 設計上は柔軟性が確保されているものの、実際に複数のKnative Servingを同時運用する場合にはいくつかの制約や注意点があります:

  • ① グローバルなCRDとAPIリソースの共有: 上述のとおり、Knative Servingが提供するCRD(例えばKnative ServiceやRouteなどのカスタムリソース定義)はクラスター全体で共有されます (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub)。つまり、ユーザーが作成するService.serving.knative.dev等のオブジェクトは、クラスター内どのKnativeServingインスタンスから見ても同じリソース空間に存在します。現状、Knative Servingのコントローラーは「自分の管轄のNamespaceだけを見る」という動作にはなっておらず、基本的に全Namespaceの対象リソースを監視・調停します。そのため、複数のKnative Serving制御プレーンを立ち上げても、全てのコントローラーが全体のサービスに反応してしまう可能性があります (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub)。例えば、ユーザーがデプロイしたKnative Serviceリソース1つに対して、2つの異なるKnative Servingコントローラーがそれぞれ反応し、競合する更新を行うリスクがあります。同様に、各インスタンスのAutoscalerやActivatorが同じ対象に対して動作を試みるなど、競合状態が起こり得ます。この点はコミュニティでも認識されており、「Knative Servingのコントローラーを単一Namespaceに限定して動かせるようにしよう」という提案 (Multi-Tenant Control Plane · Issue #4959 · knative/serving · GitHub)や、「複数制御プレーンを同居させるには何が課題か」という議論 (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub)がなされています。しかし(執筆時点では)完全な分離機構は導入されていません。したがって、実質的に複数インスタンスを独立稼働させるためには、運用上で対象リソースを明確に分ける必要があります。例として、「Namespace Aに属するアプリはKnativeServingインスタンスAで扱い、Namespace BのアプリはインスタンスBで扱う」というように人為的に分離し、それぞれのKnativeServingインスタンスの設定で自分の担当外を無視するようなカスタマイズ(もし可能であれば)を検討する必要があります。ただ、Knative Servingに標準でそうした「担当Namespaceのフィルタ設定」があるわけではないため、この点は技術的な制約といえます (Multi-Tenant Control Plane · Issue #4959 · knative/serving · GitHub)。

  • ② Admission Webhookの競合: Knative Servingのインストール時には、リソース作成時の初期化やバリデーションのためにAdmission Webhook(MutatingWebhookやValidatingWebhook)がクラスターに登録されます。デフォルトではこれらのWebhook設定(MutatingWebhookConfiguration等)はknative-servingといった名称で一意に存在し、全ての対象リソース(Knative ServiceやRevision等)に対して動作します。複数のKnative Servingインスタンスをインストールすると、複数のWebhook設定が存在することになり、どちらのWebhookも同じリソースに対して呼び出される可能性があります (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub)。場合によっては、後からインストールしたインスタンスのWebhook設定が先のものを上書きする、あるいはWebhookが二重に適用されて予期せぬ挙動になる、といった問題が発生し得ます。Webhookはクラスター全体で作用するため、この競合は複数インスタンス運用時の大きな技術的課題です (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub)。対策としては、インスタンスごとにWebhookの対象や名前を変える高度な設定が必要ですが、Knative Operatorの標準機能ではそこまで細かい制御は exposed されていません。従って、Webhook競合を回避する明確な方法が用意されていない点に注意が必要です。

  • ③ ネットワーキングとIngressの考慮: Knative ServingはIngress(ネットワーク入口)の実装をプラグイン的に扱えます(IstioやKourier、Contourなど) (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub)。標準ではknative-serving NamespaceにIngress用のコンポーネント(例えばKourierのコントローラーやGatewayリソース)がデプロイされます。複数インスタンスを動かす際、それぞれが同じホスト名のドメインを扱おうとすると競合する可能性があります。例として、両方のKnative Servingインスタンスがexample.comドメインをデフォルトで使用しようとすると、DNSやルーティング上で競合が起こるでしょう。このため、ドメインの設定はインスタンスごとに分ける必要があります(config-domain ConfigMapで別々のドメインを設定)。加えて、もし両インスタンスが同じIngress実装(例: Kourier)を使う場合でも、それぞれが独立したGateway(ロードバランサーServiceなど)を持つよう構成しなければなりません。KnativeServing CRのspec.ingressspec.config.networkでGateway名やselectorをオーバーライドできるので、例えば一方のインスタンスはknative-ingress-gatewayとは別名のIngress Gatewayを使うように設定するといった対応が考えられます (serving-operator/config/300-serving-v1alpha1-knativeserving-crd.yaml at master · knative/serving-operator · GitHub)。このようにネットワーク面でも衝突を避ける細かな調整が必要です。

  • ④ リソースの重複消費: 既に述べたように、制御プレーンを複数立ち上げるとDeploymentやPodが重複します。特にメモリやCPUを消費するコントローラ群(autoscalerやnetworkingコントローラ等)や、イベントを待ち受けるactivator等がインスタンスごとに動くため、クラスター全体で見れば消費資源量が増大します。Knative自体は軽量なコンポーネントですが、HA構成にしている場合は各Deploymentを複数レプリカ動かすことになりますし、インスタンス数が増えればその分直線的にリソース消費も増える点に注意が必要です (serving-operator/config/300-serving-v1alpha1-knativeserving-crd.yaml at master · knative/serving-operator · GitHub)。

  • ⑤ バージョン互換性: 複数のKnative Servingを同一クラスターで動かす際に見落とせないのがバージョンや互換性の問題です。CRDが共通である以上、原則として単一のバージョン系列のKnative Servingを同時運用すべきです。例えば、あるインスタンスがKnative Serving v1.0で、別のインスタンスがv1.5といったように世代の離れたバージョンを同居させると、CRDスキーマの差異やコントローラー間の認識ズレで不整合が起こる可能性があります。Knative Operatorでは、サポートするKnative Servingのバージョン組み合わせを管理していますが (Install by using the Knative Operator - Knative)、基本的には一つのOperatorインストールにつき統一されたバージョンのKnativeを展開する想定です(異なるバージョン同時稼働はアップグレードの一時的な手段としては考慮されますが、長期運用想定ではありません)。したがって、複数CRを使う場合でもバージョンを合わせるか、アップグレード時は短期的な並行運用に留める方が安全です。

  • ⑥ Operatorおよび周辺ツールの制限: Upstream(コミュニティ版)のKnative Operator自体は複数KnativeServing CRの作成を明確に禁止していませんが、それを利用するプラットフォーム次第では制限を設けている場合があります。一例として、Red Hat OpenShiftの「Serverless Operator」では、過去のバージョンで複数のKnativeServing CRを作成できてしまうと不具合の元になるため、バージョン1.6.0以降でそれを明示的にエラーとする制御を入れています (Chapter 1. OpenShift Serverless Release Notes | Red Hat Product ...)。実際に「2つ以上のKnativeServing CRを作成しようとするとエラーになる」旨がリリースノートに記載されています (Chapter 1. OpenShift Serverless Release Notes | Red Hat Product ...)。このように、実運用環境ではベンダーが安定性のため1クラスター1インスタンスに制限しているケースもあります(OpenShiftの場合、Serverless Operatorがknative-servingという1つのネームスペースにのみインストールする前提になっています (How do I configure multi-tenant Kafka-backed Knative channels in an Openshift? - Stack Overflow))。従って、利用するプラットフォームのドキュメントやベストプラクティスに従い、複数インスタンス運用がサポートされているか確認する必要があります。

以上の制約から、Knative Operatorは設計上は複数インスタンスを許容していますが、実際にマルチインスタンスをフル活用するには慎重な計画と追加の設定が必要であることが分かります。コミュニティでも「複数の制御プレーンをどう実現するか」「コントローラーをNamespace単位に絞るにはどうするか」といった議論や研究が進められており (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub) (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub)、将来的にはより明確なマルチテナントサポートがKnative Serving/Eventingに組み込まれる可能性があります。

● まとめ: Knative OperatorのKnativeServingカスタムリソースは、Kubernetesの設計思想(拡張性とマルチテナンシー)に沿って複数のKnative制御プレーンを管理可能なように作られています。これは、利用者にとってスケーラビリティと柔軟な運用を可能にするメリットがあります (Multi-Tenant Control Plane · Issue #4959 · knative/serving · GitHub)。一方で、技術的には未解決の課題(コントローラーの競合やグローバルリソースの共有)があり、複数インスタンス運用は高度なシナリオです。そのため公式ドキュメントでも、通常は単一のKnative Servingインストールで十分であり、複数必要な場合は上述のような点に注意するよう示唆されています。また、OpenShiftのように実装上の都合で単一インスタンスに制限している例もあります (How do I configure multi-tenant Kafka-backed Knative channels in an Openshift? - Stack Overflow)。

Knativeコミュニティの設計思想としては、「Knative自体はデータプレーン(ユーザーのサービス実行部分)はマルチテナント対応」であり、単一のKnative Servingでも複数のNamespaceのアプリケーションを扱えるようになっています。ただし「制御プレーン自体をもマルチテナント化(分離)したい」というニーズにも応えられる可能性を残すため、Knative OperatorはCRD設計を柔軟にし、Namespacedスコープで複数配置を可能にしています。利用者は自分のユースケースに応じて、それを一つの強力なKnative環境として使うか、複数の隔離されたKnative環境として使うか選択できるわけです。

最後に、もし複数のKnative Servingインスタンスを運用する場合は、以下のポイントに留意してください:

  • 各インスタンスの役割や対象とするNamespaceを明確化し、可能な限りお互いの管轄が重ならないようにする。
  • ドメインやIngress経路の設定を分離し、ルーティングの競合を防ぐ(例: インスタンスAは*.example.com、インスタンスBは*.example.orgを使用)。
  • 全インスタンスでKnativeのバージョン互換性を保つ。理想的には同一バージョン、少なくともCRDに互換性のあるバージョンを使用する。
  • 公式ドキュメントやベストプラクティスを参照し、必要ならコミュニティの知見を取り入れる。KnativeのドキュメントにはOperator経由でConfigMapを上書きする方法 (Configuring Knative using the Operator - Knative)や、高可用性構成の方法、Ingressプラグインの設定などが記載されています。それらを駆使してインスタンス間干渉を最小限に抑える設定を行うことが重要です。

以上、KnativeServing CRが複数のKnative Servingインスタンスをインストール・管理可能となっている背景には、マルチテナント性の向上と運用の柔軟性という設計上の理由があり、それを支える技術的実装としてNamespacedなCRD設計Operatorによるリソース分離管理があります。ただし同時に、現在の実装上はグローバルリソース共有による制約もあるため、実運用ではそれらを踏まえた計画が必要です。公式ドキュメントやKnativeコミュニティの議論 (Multi-Tenant Control Plane · Issue #4959 · knative/serving · GitHub) (Multiple Knative Eventing control planes · Issue #6601 · knative/eventing · GitHub)を参考に、安全で効果的なマルチインスタンス運用を検討してください。

References:

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?