--- title: 自宅で運用しているTanzu Kubernetes Grid及びTanzu Community Editionのk8sクラスタ on vSphereをvSANなしでホスト跨ぎで冗長化する方法 tags: ["Kubernetes", "vSphere", "TKG", "Tanzu", "Cluster API", "TCE"] categories: ["Dev", "CaaS", "Kubernetes", "TKG"] date: 2021-12-13T17:05:08Z updated: 2021-12-14T01:29:51Z --- > [TUNA-JP Advent Calendar 2021](https://qiita.com/advent-calendar/2021/tuna-jp) その1の14日目のエントリです。 本記事執筆時点で自宅のhome labはESXiをインストールした3台のNUC (NUC6i7KYK x 1, NUC10i7FNH x 2) で構成されています。 また [Synology DiskStation DS718+](https://www.amazon.co.jp/exec/obidos/ASIN/B074BYFKZ2/ikam-22/ref=nosim/) という少し古い安物のNASも使用しています。 ここにTanzu Kubernetes Gridをインストールしています。このブログもWorkloadクラスタの一つの上で動いています。 Tanzu Community Editionを使う場合でも同じなので、以下の内容はTKG -> TCEに置き換えても読めます。 ### 共有データストアがないと冗長化できない問題 ESXi Host (NUC)が3台あるので、TKGのWorkload Clusterをスケールアウトして異なるホスト上に分散させたいです。1台のホストがダウンしてもk8sクラスタは稼働し続けるための当然の欲求です。 しかし、TKG及びTCEでクラスタを作成する場合、`VSPHERE_DATASTORE`に指定するデータストアは一つしか選べません。 * TKGのクラスタ作成時のパラメータ https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/1.4/vmware-tanzu-kubernetes-grid-14/GUID-tanzu-k8s-clusters-vsphere.html * TCEのクラスタ作成時のパラメータ https://tanzucommunityedition.io/docs/latest/vsphere-wl-template/ `VSPHERE_DATASTORE`で指定したデータストアはNodeのVMのdiskのプロビジョニング先として使用されます。 したがって、この値にホストのローカルデータストアを選択すると次の図のように、**対象のクラスタの全VMがそのローカルデータストアを持つホスト上に作成されてしまいます**。 worker x 3なk8sクラスタを3つ作っても、3つのホストそれぞれに1クラスタ作ることしかできません。とても残念な構成です。 ![image](https://user-images.githubusercontent.com/106908/145721750-5cb24f6b-27e3-4af3-adc2-42459b271e61.png) 共有データストアを使用した場合は、次の図のような期待通りのホストを跨ったクラスタを作成することができます。 ![image](https://user-images.githubusercontent.com/106908/145721878-038e8896-9b80-4e2c-a0b3-62707d1513c8.png) 共有データストアの選択肢としては * vSANを構築する * NASをiSCSIまたはNFSでデータストアとして使う が考えられます。 vSANはハードウェア的 (NICの数, 通信速度) にもリソース消費量(CPU, Memory)的にも現有戦力では難しいです。 > なお、vSANを構築したいって方は本記事の内容は不要です。 > https://qiita.com/hirosat/items/537f3b75160e2a9f4a21 > を参考にしてください。 NASとして使用しているSynology DiskstationはiSCSIに対応しているので、これをデータストアに使うことができます。 しかし、NASもNUCもNICが1GbEにしか対応していません。まともに使うには最低でも2.5GbEは欲しいところです。 実際にiSCSIのデータストアを`VSPHERE_DATASTORE`に設定して、クラスタを作成した時はControlplaneのDisk IOの負荷が大きく、ロードアベレージが高くなり、 API Serverへのアクセスのレスポンスタイムが遅くなり、kube-vipがクラッシュし、ControlplaneのVIPが消えては復活し、というのを繰り返す不安定な状態になっていました。 SSDのローカルデータストアを使う場合はこのようなことは起きません。
(もしかしたらこれはIOが多いkapp controllerがControlplaneに配置されていたからかもしれません。kapp controllerをWorkerに再配置したら改善していたかもしれないので、興味のある方は試してみてください。) したがって、自宅環境では、`VSPHERE_DATASTORE`にローカルデータストアを指定し、NodeのDiskにはローカルSSDを使うのが前提条件となりました。 このままではホストを跨った冗長なk8sクラスタを作ることができません... ### 救世主Node Pool 仕方なくk8sクラスタが同一ホスト上に全て乗ってしまう状態で運用していたのですが、TKG 1.4で朗報がありました。 Node Poolのサポートです。TCEでは最初から使えます。 https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/1.4/vmware-tanzu-kubernetes-grid-14/GUID-tanzu-k8s-clusters-node-pool.html Node Poolは異なるタイプのWorkerをサポートするための機能です。例えば特定のWorker NodeのみをCI専用にしてCPUのコア数を増やしたい場合に利用できます。 Cluster APIの用語で言うと、Clusterに対してMachineDeploymentリソースを増やす形になります。MachineDeploymentにはvSphere上のVMのSpecを決めるVSphereMachineTemplateリソースが紐づきます。 TKG/TCEのNode PoolではこのVSphereMachineTemplateの情報を追加設定できます。 具体的には次のような設定が可能です。 ```yaml name: tkg-wc-oidc-md-1 replicas: 4 labels: key1: value1 key2: value2 vsphere: memoryMiB: 8192 diskGiB: 64 numCPUs: 4 datacenter: dc0 datastore: iscsi-ds-0 storagePolicyName: name folder: vmFolder resourcePool: rp-1 vcIP: 10.0.0.1 template: templateName cloneMode: clone-mode network: network-name ``` 見ての通り、`vsphere.datastore`にデータストアを定義できます。 つまり、新しく作るNode Pool (WorkerのMachineDeployment)を別のデータストアに紐づくホスト上に作成できます。 これにより、1つのクラスタに複数のデータストアを持つMachineDeploymentを結びつけられ、結果的にホストを跨ったWorker VMを持つk8sクラスタを作成できます。 次の図のような構成になります。 ![image](https://user-images.githubusercontent.com/106908/145833616-66b52d50-32b4-4266-a338-528444cb9d4c.png) Node Poolが対応しているのはWorkerのみで、Controlplaneは最初のクラスタ作成時に指定したデータストアを使用しますが、 アプリケーションが乗るWorkerが複数ホストに分散できるのであれば、自宅環境の用途としては問題ありません。 ホストが3台あるので、最初に使用したデータストア以外の2つのデータストアを使用するNode Poolを作成するために、 次のようなyamlを作成します。クラスタ名は`apple`です。 ```yaml # nodepool1.yaml name: apple-md-1 replicas: 1 vsphere: datastore: /Datacenter/datastore/datastore01 ``` ```yaml # nodepool2.yaml name: apple-md-2 replicas: 2 vsphere: datastore: /Datacenter/datastore/datastore02 ``` 指定しなかった設定項目は元のクラスタの設定が引き継がれます。 ちなみに`tanzu cluster create`コマンドで作成されるMachineDeployment名は`-md-0`なので、 Node Pool名は`-md-1`と`-md-2`にしました。 次のコマンドで`apple`クラスタに対して、Node Poolを追加できます。 ``` tanzu cluster node-pool set apple -f nodepool1.yaml tanzu cluster node-pool set apple -f nodepool2.yaml ``` Node Pool及び、クラスタの状態を確認します。 ``` $ tanzu cluster node-pool list apple NAME NAMESPACE PHASE REPLICAS READY UPDATED UNAVAILABLE apple-md-0 default Running 2 2 2 0 apple-md-1 default Running 1 1 1 0 apple-md-2 default Running 2 2 2 0 $ tanzu cluster get apple --show-group-members NAME NAMESPACE STATUS CONTROLPLANE WORKERS KUBERNETES ROLES apple default running 1/1 5/5 v1.21.2+vmware.1 ℹ Details: NAME READY SEVERITY REASON SINCE MESSAGE /apple True 69d ├─ClusterInfrastructure - VSphereCluster/apple True 93d ├─ControlPlane - KubeadmControlPlane/apple-control-plane True 69d │ └─Machine/apple-control-plane-6g89p True 70d └─Workers ├─MachineDeployment/apple-md-0 │ ├─Machine/apple-md-0-5c747f779f-twdgg True 84d │ └─Machine/apple-md-0-5c747f779f-x9bjv True 63d ├─MachineDeployment/apple-md-1 │ └─Machine/apple-md-1-89bf4f8c4-l28tm True 81d └─MachineDeployment/apple-md-2 ├─Machine/apple-md-2-97546f689-clgjh True 82d └─Machine/apple-md-2-97546f689-ndcvh True 63d ``` MachineDeploymentが合計3つ作られているのがわかります。 `kubectl`のcontextをManagement Clusterに切り替えて、Cluster APIのリソースを確認します。 Node Poolに相当するMachineDeploymentが作成されていることがわかります。 ``` $ kubectl get machinedeployment -l cluster.x-k8s.io/cluster-name=apple NAME PHASE REPLICAS READY UPDATED UNAVAILABLE apple-md-0 Running 2 2 2 apple-md-1 Running 1 1 1 apple-md-2 Running 2 2 2 ``` また、MachineDeploymentに対応してVSphereMachineTemplateが作成されています。 ``` $ kubectl get vspheremachinetemplate NAME AGE apple-control-plane 93d apple-md-1-mt 93d apple-md-2-mt 93d apple-worker 93d ``` Node Poolに対して指定したデータストアが使用されていることも確認できます。 ``` $ kubectl get vspheremachinetemplate apple-md-2-mt -oyaml | kubectl neat apiVersion: infrastructure.cluster.x-k8s.io/v1alpha3 kind: VSphereMachineTemplate metadata: name: apple-md-2-mt namespace: default spec: template: spec: cloneMode: fullClone datacenter: /Datacenter datastore: /Datacenter/datastore/datastore02 diskGiB: 20 folder: /Datacenter/vm/tkg memoryMiB: 8192 network: devices: - dhcp4: true nameservers: - 8.8.8.8 networkName: VM Network numCPUs: 2 resourcePool: /Datacenter/host/Cluster/Resources/tkg server: vcenter.example.com template: /Datacenter/vm/tkg/photon-3-kube-v1.21.2 ``` vCenterを見ても、3つのホストにWorkerが分散していることがわかります。 ![image](https://user-images.githubusercontent.com/106908/145850372-8193d3fd-9810-44da-a614-ca290e96c01e.png) ![image](https://user-images.githubusercontent.com/106908/145850412-ac400986-cbf9-4c6e-b86f-5733d971e3fc.png) ![image](https://user-images.githubusercontent.com/106908/145850527-6c28c0ee-d1dd-4dcb-944e-fdb4d844042b.png) これで、期待した構成でクラスタを作ることができました。 この構成には一つ制約があります。**k8sのPersistent Volumeをローカルデータストア(SSD)上に作成することができません**。 考えてみれば当たり前で、ローカルにPVができるとそのPVを使っているコンテナが移動できないからです。 Node Poolを使用して異なるデータストア上にWorkerを作った場合は、vCenterに共有データストアが存在しないとPersistent Volumeが作成できず、Pending状態になります。 storagePolicyを指定している場合は、指定したstoragePolicyに共有データストアが存在しないといけません。 自宅の環境ではiSCSI接続のNASをk8sのPersistent Volume用途に使用しています。こちらは自宅用途では許容範囲です。 PVはvSphere CSI Driver経由で作成されるため、k8s側でNASを使うための設定は特に要りません。 --- まとめると、vSANがない自宅環境でTKG/TCEを使ったホスト跨ぎな冗長k8sクラスタを作りたい場合、 * Node VMはローカルデータストアを使う * Node Poolを追加することで異なるデータストアを使うWorker Nodeを増やす * Persistent VolumeにはiSCSI接続のNASを使う でうまく行きました。次の図のような構成です。 ![image](https://user-images.githubusercontent.com/106908/145857790-6ed2a923-5264-42c3-b7e9-a47154058f0d.png) 複数のNUC + 安いNASで手軽に構成できます。 この構成にしてからまだTKGのアップデートが行われていないので、アップデートがどのような手順になるのか現時点で不明です。