Kubernetesにおけるマルチクラスタ関連手法の分類
こんにちは。青山(amsy810)です。
Kubernetesには複数のクラスタを扱うための技術がいくつかあります。 今回は幾つかのパターンに分けて紹介していきたいと思います。 また、将来的にこうなったら面白いかもという話をするために、すぐにプロダクション利用できない話やWebサービスでは使わないような話も含まれています。
【目次】
- 複数クラスタを利用する理由
- 複数クラスタを管理するパターン
- GitOpsで複数クラスタを管理するパターン
- 複数のKubernetesクラスタをFederateするパターン
- Virtual kubeletパターン
- マルチクラスタ時のロードバランサの扱い
- LoadBalancer の機能を利用して分散する
- DNS を利用して分散する
- Multi Cluster にまたがる Service Mesh を利用して転送する
- マルチクラスタでPod Networkを繋ぐ
- ストレージの扱い
- マルチテナンシー関連の技術
- 超個体型データセンターへの応用
複数クラスタを利用する理由
複数クラスタで構成するには下記のような理由があるのではないでしょうか。 何がしたいかによっては、選択できる手法も限られてくるでしょう。
- 耐障害性、信頼性向上、ディザスタリカバリ
- マルチクラウド・ハイブリッドクラウド対応
- ジオロケーションによるパフォーマンス問題の解消
- 機密データのローカリティを確保する
- In-place クラスタアップグレードを避ける
- スケーラビリティの確保
- エッジ・フォグ環境に適用する
北山さんがマルチクラスタのメリット・デメリットでおすすめの記事をツイートしていたので、こちらもメモしておきます。
複数クラスタを管理するパターン
複数クラスタを管理する方法は主に3つあります。
1. GitOpsで複数クラスタを管理するパターン
GitOpsでは、Gitリポジトリに保存されたマニフェストファイルをKubernetesクラスタに対して同期することでKubernetesクラスタの管理を行います。 この時に、同じリポジトリを参照することで同等のクラスタを作成することができます。 また、ArgoCD では Kustomize や Helm と連携することができるため、レプリカ数や一部の設定を変更したり、一部のマイクロサービスだけデプロイするといった選択をすることも可能です。
現状プロダクションで利用するとなると、GitOpsで複数のクラスタに対してマニフェストを適用する方法を取ることが多いでしょう。
2. 複数のKubernetesクラスタをFederateするパターン
Kubernetesには、複数のクラスタを束ねて管理する Federation v2 の開発が SIG-MultiClsuter によって進められています。 Federation v2では、マネジメントクラスタが複数のターゲットクラスタを管理する形になります。 マネジメントクラスタに対して、FederatedDeploymentやFederatedServiceなどのリソースを作成すると、複数のターゲットクラスタにDeploymentやServiceが作成されるようになっています。 また、CustomResoruceなどもFederetadXXXとして扱うことができるようになっています。
Federationでも、FederatedDeploymentなどの定義時に特定のフィールドにパッチを当てることができます。 また、ClusterSelectorを使用して特定のクラスタのみにデプロイすることも可能です。
kind: FederatedDeployment spec: overrides: - clusterName: cluster1 clusterOverrides: - path: "/spec/replicas" value: 5 - clusterName: cluster2 clusterOverrides: - path: "/spec/template/spec/containers/0/image" value: "nginx:1.17.0-alpine"
他にも、複数のクラスタ横断でレプリカ数を維持するようなスケジューリングを行うReplicaSchedulingPreferenceなどの機能もあります。クラスタ横断でDeploymentを柔軟に展開したい場合には利用すると良いでしょう。
apiVersion: scheduling.kubefed.io/v1alpha1 kind: ReplicaSchedulingPreference metadata: name: test-deployment spec: targetKind: FederatedDeployment totalReplicas: 9 clusters: A: weight: 1 B: weight: 2
3. Virtual kubeletパターン
Virtual kubeletはKubernetesに仮想ノードを登録し、その仮想ノード上割り当てられたPodは「クラスタ外にあるコンピューティングプール」で起動する仕組みを提供します。 コンピューティングプールは、一般的にServerlessなCaaSサービスが多いですが、他にもエッジ環境におけるノードや別のコンピューティングクラスタのケースもあります。
Virtual kubeletで扱えるコンピューティングプールには、さまざまなプロバイダーが提供されています。 大きく分けると3種類でしょうか。
Serverless CaaSバックエンド向け
- Azure Container Instances
- AWS Fargate
別コンピューティングクラスタ向け
- Admiralty Multi-Cluster Scheduler
- HashiCorp Nomad
エッジ環境・単一ノード向け
Serverless CaaS バックエンド向けのプロバイダでは、無尽蔵なコンピューティングプール上に迅速にPodをオフロードして起動するような使い方ができたり、メインで使うことでKubernetesノードを管理する必要がなくなります。 なお、AWS Fargateプロバイダーは、EKS on Fargateでは使われていません。
別コンピューティングクラスタ向けのプロバイダでは、Serverless CaaSの代わりに、HashiCorp Nomadや別のKubernetesクラスタ(Admiraltyの場合)などのコンピューティングクラスタに対してPodをオフロードすることができます。 Admiralty Multi-clsuter scheduler はその名の通り、複数のKubernetesクラスタに対してスケジューリングする用途でも使うことができます。
エッジ環境や単一ノード向けのプロバイダでは、Virtual Nodeに割り当てられたPodはエッジ環境上のクラスタで起動します。 クラウド上に起動しているKubernetes Masterから、エッジ環境のノード郡を管理できるようになります。
これらのソリューションはいくつかしか試せていませんが、全てにおいて「通常Nodeで起動したPod」と「Virtual kubeletで起動したPod」の間のPod Networkが適切に接続されたままになるのかが気になるところです。
マルチクラスタ時のロードバランサの扱い
マルチクラスタ環境では、ロードバランサなどのサービスを提供するエンドポイントを払い出す方法が大きく分けて3種類あるでしょう。
1. LoadBalancer の機能を利用して分散する
Anthos の Multi Cluster Service / Ingress では、同一IPアドレスを利用して複数リージョンにまたがる複数のクラスタに対してリクエストを転送することができます。なので、米国と日本でマルチクラスタ構成を組み、リクエスト元の地理に応じて最適なクラスタに転送することができます。マルチリージョンでマルチクラスタ構成をするにあたって、この機能は便利だなという気持ちになります。
CyberAgent の AKE でも、単一のVIPを使って複数のクラスタ上に展開されるServiceやIngressに利用できるようになっています。主にクラスタ間移行をゼロダウンタイムで行えるようにすることが目的です。
2. DNS を利用して分散する
上記のような環境が利用できない場合は、DNS Round Robin で構成するのが一般的でしょう。 Federation v2の場合は ExternalDNSと連携するようになっており、作成されたLoadBalancer Service と Ingress リソースが払い出す複数のVIPを自動的にDNSに登録する、Multi-Cluster Service DNS と Multi-Cluster Ingress DNS の機能が提供されています。
3. Multi Cluster にまたがる Service Mesh を利用して転送する
クラスタ間の距離がある程度近い場合は、特定のクラスタでリクエストを受けて隣のクラスタにリクエストを転送するようにするのも良いでしょう。 Istio ではMulti Cluster Service Meshの機能が用意されており、複数のクラスタにまたがってリクエストを分散させることができます。
マルチクラスタでPod Networkを繋ぐ
マルチクラスタでPod Networkを構成するには、Submarinerを利用することができます。 Submarinerでは、相互接続するすべてのクラスタのノード1台以上のGateway用のAgent(Submariner Gateway Engine)を展開し、このGateway Agent間でIPSecトンネルが張られるようになっています。 また、すべてのノードにはRoute Agentが展開されており、これによりクラスタを跨いだPod間通信ができるようになっています。
またSubmarinerでは、複数のクラスタで利用されるクラスタ内DNSのSuffix(cluster.local)は異なるものを指定し、ClusterIPのCIDRも別のものを指定します。 そのため、特定のクラスタから別のクラスタのServiceに対してリクエストが送れるように、双方のDNSサーバに対してクエリをかけられるようにしておく必要があります。
ストレージの扱い
マルチクラスタ・マルチテナント環境におけるストレージの扱いですが、VolumeSnapshotの機能が導入されることである程度クラスタ間移行はしやすくなるかもしれません。 一方で、CSI Driver間でのマイグレーションなどは現状はスコープ外のため、同一CSI Driver、すなわち同一のストレージバックエンドに限れば、クラスタ間でPersistentVolumeの移行もしやすくなるかもしれません。 マルチクラスタの理由にもよりますが、同一クラウドでマルチクラスタ構成であれば、シームレスな移行も夢では無いかと思います。
マルチテナンシー関連の技術
マルチクラスターと類似したものとして、マルチテナンシーの考え方もあります。 Kubernetesコミュニティにも、SIG-MultiClsuter と Multi-Tenancy WG の 2 種類があります。
下記に Virtual Cluster や Hierarchical Namespace の incubating project のDesign Docsや実装が公開されています。 GitHub - kubernetes-sigs/multi-tenancy: A working place for multi-tenancy related proposals and prototypes.
また、Hierarchical Namespace Controller については、以前検証した結果をブログにまとめてあるのでご興味があれば参考にしてみてください。
また先週末の KubeFest でぞえとろさんがちらっと話題に出してた、kioskやloft あたりも気になっています。 この辺りも時間があれば調べて、マルチクラスタ編もまとめるかもしれません。
超個体型データセンターへの応用
客員研究員として参加しているさくらインターネット研究所では、ビジョンとして「超個体型データセンター」を掲げています。 私の理解でざっくりと説明すると、「中小規模のデータセンター」や「エッジ・フォグ環境」などが相互に有機的に接続され、自律分散的に協調動作するだろうというビジョンです。
今回は備忘録的にKubernetesにおけるマルチクラスタ周りの技術の分類や手法をまとめてみました。 ベースの技術としてKubernetesを使うべきというわけではありませんが、技術検証やPoCなどではKubernetesやCRD/Controllerによる拡張性を利用できると良いかと思っています。
今回紹介したマルチクラスタ関連の技術を組み合わせることで、少しそれらしいものはできるかもしれませんが、超個体的(相互に有機的に接続され、自立分散的に協調動作)というよりかは、中央集権的な手法が多いと感じています。
そのため理想としては、各Kubernetesクラスタを作成後にAgentを各クラスタにデプロイするだけで、Agentが相互に情報を交換しあうことで最適なワークロードの配置を行ってくれるような、超個体的なクラスタを作れると面白いのかなと思っています。 Kubernetesの場合には、このAgentの実装はCustom Controllerを実装すればよいので、あとはロジックをどうするかをもう少し明確に考える必要があると思っています。 ロジックやメトリクスがPlugableにできるように設計できれば、最初は局所解に陥るような単純なものでも良いのかもしれません。