IK.AM

@making's tech note


自宅で運用しているTanzu Kubernetes Grid及びTanzu Community Editionのk8sクラスタ on vSphereをvSANなしでホスト跨ぎで冗長化する方法

🗃 {Dev/CaaS/Kubernetes/TKG}
🏷 Kubernetes 🏷 vSphere 🏷 TKG 🏷 Tanzu 🏷 Cluster API 🏷 TCE 
🗓 Updated at 2021-12-14T10:29:51+09:00  🗓 Created at 2021-12-14T02:05:08+09:00 {✒️️ Edit  ⏰ History  🗑 Delete}

TUNA-JP Advent Calendar 2021 その1の14日目のエントリです。

本記事執筆時点で自宅のhome labはESXiをインストールした3台のNUC (NUC6i7KYK x 1, NUC10i7FNH x 2) で構成されています。 また Synology DiskStation DS718+ という少し古い安物のNASも使用しています。

ここにTanzu Kubernetes Gridをインストールしています。このブログもWorkloadクラスタの一つの上で動いています。

Tanzu Community Editionを使う場合でも同じなので、以下の内容はTKG -> TCEに置き換えても読めます。

共有データストアがないと冗長化できない問題

ESXi Host (NUC)が3台あるので、TKGのWorkload Clusterをスケールアウトして異なるホスト上に分散させたいです。1台のホストがダウンしてもk8sクラスタは稼働し続けるための当然の欲求です。

しかし、TKG及びTCEでクラスタを作成する場合、VSPHERE_DATASTOREに指定するデータストアは一つしか選べません。

VSPHERE_DATASTOREで指定したデータストアはNodeのVMのdiskのプロビジョニング先として使用されます。 したがって、この値にホストのローカルデータストアを選択すると次の図のように、対象のクラスタの全VMがそのローカルデータストアを持つホスト上に作成されてしまいます。 worker x 3なk8sクラスタを3つ作っても、3つのホストそれぞれに1クラスタ作ることしかできません。とても残念な構成です。

image

共有データストアを使用した場合は、次の図のような期待通りのホストを跨ったクラスタを作成することができます。

image

共有データストアの選択肢としては

  • 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の情報を追加設定できます。

具体的には次のような設定が可能です。

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

Node Poolが対応しているのはWorkerのみで、Controlplaneは最初のクラスタ作成時に指定したデータストアを使用しますが、 アプリケーションが乗るWorkerが複数ホストに分散できるのであれば、自宅環境の用途としては問題ありません。

ホストが3台あるので、最初に使用したデータストア以外の2つのデータストアを使用するNode Poolを作成するために、 次のようなyamlを作成します。クラスタ名はappleです。

# nodepool1.yaml
name: apple-md-1
replicas: 1
vsphere:
  datastore: /Datacenter/datastore/datastore01
# nodepool2.yaml
name: apple-md-2
replicas: 2
vsphere:
  datastore: /Datacenter/datastore/datastore02

指定しなかった設定項目は元のクラスタの設定が引き継がれます。

ちなみにtanzu cluster createコマンドで作成されるMachineDeployment名は<cluster name>-md-0なので、 Node Pool名は<cluster name>-md-1<cluster name>-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  <none>  
ℹ  

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

image

image

これで、期待した構成でクラスタを作ることができました。

この構成には一つ制約があります。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

複数のNUC + 安いNASで手軽に構成できます。

この構成にしてからまだTKGのアップデートが行われていないので、アップデートがどのような手順になるのか現時点で不明です。