TKG 2.1 で Kube-Vip をワークロード用 LB として使ってみる

Kube-Vip は、ベアメタルから VM、Edge など、あらゆる環境の Kubernetes クラスタにおいて、仮想 IP (VIP) および、L4 の Load Balancer 機能を提供するソフトウェアです。
外部のソフトウェアやハードウェアに依存しないよう、自己完結型のコンテナとして実装されています。
元々は、Kubernetes のコントロールプレーン (kube-apiserver) の可用性向上のための HA 機能として開発されていたようですが、進化を続け、Kubernetes の Service (type=LoadBalancer) も提供できるようになっています。

https://kube-vip.io/

Tanzu Kubernetes Grid (TKG) 2.1 では、NSX Advanced Load Balancer (NSX ALB) が、推奨の LB 製品ではありますが、NSX ALB が無い場合には、Kubernetes クラスタのコントロールプレーン用の LB として、Kube-Vip が利用できます。
ただし、デフォルト設定では Kube-Vip は、コントロールプレーン (kube-apiserver) 用のみの LB として構成されるため、ユーザーワークロード、例えば、ユーザーが展開したアプリ用の Service (type=LoadBalancer) には利用できません。そのため、Kube-Vip の構成で、Management Cluster をデプロイした際には、ユーザーワークロード用の LB は、別途用意する必要があります。

:::note info
**補足**
Tanzu Kubernetes Grid (および、そのファミリー) の名前については、歴史的な変遷があるため、なかなかややこしいですが、この記事において、単に TKG と言った場合には、旧称 Tanzu Kubernetes Grid multicloud (TKGm) を意図しており、vSphere with Tanzu とは区別しています。
この記事においては、[TKG 2.1 の公式ドキュメント](https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/2.1/tkg-deploy-mc-21/mgmt-index.html)と、↓こんな感じの対応になっていますので、参考にしていただければと思います。

* 単に Tanzu Kubernetes Grid (TKG) と表記した場合
    * 公式ドキュメントの Standalone Management Cluster をデプロイするパターン。
    * vSphere とは、疎結合なアーキテクチャーで、AWS や Azure 上などにも展開が可能。
* vSphere with Tanzu と表記した場合
    * 公式ドキュメントの Supervisor Cluster をデプロイするパターン。
    * vSphere と高度にインテグレーションされており、より付加価値のある機能が利用できる。
:::

しかし、TKG 2.1 においては、Technical Preview ではありますが、ユーザーワークロード向けの LB として、Kube-Vip を利用できます。
もちろん、Technical Preview なので、公式なサポートは提供されない機能ですが、今回は、この実験的な機能で、遊んでみたいと思います。


# 前提

* Tanzu Kubernetes Grid 2.1.1
* kubectl v1.24.10+vmware.1
* Management Cluster はデプロイ済み

また、公式ドキュメントにも記載がありますが、Management Cluster を Kube-Vip の構成でデプロイしておく必要があります。そのため、NSX ALB を使って構成している場合には、注意してください。

https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/2.1/tkg-deploy-mc-21/mgmt-reqs-network-kube-vip.html


# 手順

基本的には、公式ドキュメントの記載に従って、構成して行く...んですが、Workload Cluster を展開する際に指定するオプションの解説があるのみで、具体的なステップの解説はされていません。

https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/2.1/tkg-deploy-mc-21/mgmt-reqs-network-kube-vip.html

とは言え、実際のステップ自体は、通常の Workload Cluster の展開手順と同じ、指定するパラメータだけ、注意すれば良いので、これを保管する形で記載していきます。


## Cluster Config ファイルの作成

公式ドキュメントに記載されているスペックに従って、Workload Cluster を展開する際の構成ファイルを作成します。

https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/2.1/using-tkg-21/workload-clusters-configure-vsphere.html

ただ、ゼロから書いていると大変なので、私は、Management Cluster をデプロイする際に使用されていた Cluster Config ファイルをコピーし、必要な箇所を変更する形で、作成しています。

まず、Management Cluster をデプロイする際に使用されていた Cluster Config ファイルの場所ですが、↓こちらになります。

```sh
$ ls -1 ~/.config/tanzu/tkg/clusterconfigs/
7t40uj4cm1.yaml    # `(Legacy) Plan-Based`
management.yaml    # `Class-Based`
...
```

「なにこれ？」かも知れませんが、`<ランダム文字列>.yaml` と、`<Management Cluster 名>.yaml` というファイルが見つかるかと思います。
ランダム文字列のファイルが複数ある場合、Management Cluster 名のファイルとタイムスタンプが最も近しいものが、おそらく Management Cluster を作成する際に利用されたファイルだろうとあたりをつけてみてください。

で、それぞれ、「なにものか？」と言うと...

- `<ランダム文字列>.yaml`
    - TKG 1.x 時代に利用されていた形式で書かれたファイル。
    - TKG 2.1 では `(Legacy) Plan-Based` 形式と呼ばれている。
- `<Management Cluster 名>.yaml`
    - TKG 2.x から導入された新しい形式で書かれたファイル。
    - `Class-Based` 形式と呼ばれており、TKG 2.1 では、こちらの形式が推奨。

どちらの形式でも、Workload Cluster を作成できるのですが、TKG 2.1 のデフォルト動作では、`(Legacy) Plan-Based` 形式で進めようとすると、自動で `Class-Based` 形式にファイルが変換され、「変換済みのファイルを生成したから、そっちを指定してもう一回コマンドを実行してね」と案内されます。

もちろん、新しい形式である `Class-Based` 形式で進める方が、将来的にも良いことですが、今回の Kube-Vip の機能を有効化するには、`(Legacy) Plan-Based` 形式の方が分かりやすいので、こちらをコピーして作業を進めることにします。

```sh
cp ~/.config/tanzu/tkg/clusterconfigs/7t40uj4cm1.yaml cluster-config.yaml
```

このファイルの中身を修正していきます。

```sh
vi cluster-config.yaml
```

それぞれチェックべき箇所は、↓こんな感じです。

```yaml: cluster-config.yaml
# 公式ドキュメントには、必要な設定として記載あり。
# ただ、Kube-Vip で Management Cluster をデプロイしていれば、既に設定されているはず。
AVI_CONTROL_PLANE_HA_PROVIDER: "false"

# ...(略)...

# これから展開する Workload Cluster 名を指定。
CLUSTER_NAME: tkc01

# Control Plane VM を 3台構成にする場合には、"prod"、1台構成にする場合には "dev" を指定。
CLUSTER_PLAN: dev

# ...(略)...

# これから展開する Workload Cluster のコントロールプレーン (kube-apiserver) の VIP を指定。
VSPHERE_CONTROL_PLANE_ENDPOINT: 172.19.31.193

# その他、知っていると便利なパラメータは、↓この辺。
# VSPHERE_CONTROL_PLANE_DISK_GIB
# VSPHERE_CONTROL_PLANE_MEM_MIB
# VSPHERE_CONTROL_PLANE_NUM_CPUS
# VSPHERE_WORKER_DISK_GIB
# VSPHERE_WORKER_MEM_MIB
# VSPHERE_WORKER_NUM_CPUS
# WORKER_MACHINE_COUNT

# ...(略)...

# !!! 下記を追記 !!!
KUBEVIP_LOADBALANCER_ENABLE: "true"
KUBEVIP_LOADBALANCER_IP_RANGES: "172.19.31.1-172.19.31.31"
# IP アドレスの範囲を CIDR で指定する場合は下記を利用。
#KUBEVIP_LOADBALANCER_CIDRS: "172.19.31.0/24"
```

公式ドキュメントにおいて、追記が必要と解説されていたオプションだけ解説すると、↓こんな感じです。

* `KUBEVIP_LOADBALANCER_ENABLE`
    * ユーザーワークロード用として Kube-Vip を利用する機能を有効化。
* `KUBEVIP_LOADBALANCER_IP_RANGES`
    * ワークロード用 Kube-Vip が、実際に Service (type=LoadBalancer) を作成する使える IP アドレスの範囲を指定。
    * カンマ区切りで、複数指定できる。
    * Node 用 IP アドレスの範囲 (DHCP で配布しているはず) と被らないように注意。
* `KUBEVIP_LOADBALANCER_CIDRS`
    * ワークロード用 Kube-Vip が使える IP アドレスが所属するネットワークの CIDR を指定。
    * カンマ区切りで、複数指定できる。
    * ネットワークの重複が無いように注意。

:::note info
**2023/08/11 更新**
`KUBEVIP_LOADBALANCER_IP_RANGES` と両方指定した場合、`KUBEVIP_LOADBALANCER_CIDRS` 設定が優先されます。
そのため、「CIDR 指定した IP アドレス範囲の全体」ではなく、「特定の IP アドレスの範囲のみ」を指定したい場合には、`KUBEVIP_LOADBALANCER_IP_RANGES` を利用してください。
:::


## Workload Cluster のデプロイ

構成ファイルが作成できたら、実際に、ワークロード用 Kube-Vip が有効化された Workload Cluster をデプロイして行きます。

まず、前述の通り、TKG 2.1 では、`Class-Based` 形式が推奨であり、デフォルトでは、`(Legacy) Plan-Based` 形式のファイルは、新しい形式への変換が求められます。
とは言っても、変換は非常に簡単で、↓こんな感じで `--dry-run` オプションを指定して、その結果をファイルに保存すれば OK です。

```sh
tanzu cluster create --dry-run -f cluster-config.yaml > tkc01.yaml
```

変換されたファイルを指定して、Workload Cluster を作成します。

```sh
tanzu cluster create -f tkc01.yaml
```

↓こんな感じで、作成完了を待ちます。
...が、Nested 環境とかでやっていると、ストレージ性能の関係で、これが長い...

```textValidating configuration...
Warning: Pinniped configuration not found; Authentication via Pinniped will not be set up in this cluster. If you wish to set up Pinniped after the cluster is created, please refer to the documentation.
creating workload cluster 'tkc01'...
waiting for cluster to be initialized...
[zero or multiple KCP objects found for the given cluster, 0 tkc01 default, no MachineDeployment objects found for the given cluster]
cluster control plane is still being initialized: ScalingUp
cluster control plane is still being initialized: WaitingForIPAllocation @ Machine/tkc01-tpqsl-7525z
waiting for cluster nodes to be available...
unable to get the autoscaler deployment, maybe it is not exist
waiting for addons core packages installation...

Workload cluster 'tkc01' created
```

完了したら、作成した Workload Cluster の Context を取得しましょう。
↓こんな感じのコマンドで、kubeconfig を取得できます。

```sh
tanzu cluster kubeconfig get tkc01 --admin
```

取得できたら、その Context に切り替えておきます。

```text
$ kubectl config get-contexts
CURRENT   NAME                          CLUSTER      AUTHINFO           NAMESPACE
*         management-admin@management   management   management-admin
          tkc01-admin@tkc01             tkc01        tkc01-admin

$ kubectl config use-context tkc01-admin@tkc01
Switched to context "tkc01-admin@tkc01".
```

各ノードも Ready 状態になっていれば、OK です。

```text
$ kubectl get nodes
NAME                               STATUS   ROLES           AGE     VERSION
tkc01-lsglm-5hbf8                  Ready    control-plane   13m     v1.24.10+vmware.1
tkc01-md-0-bng8f-978fd44c4-j9wds   Ready    <none>          6m38s   v1.24.10+vmware.1
```


## 動作確認

今回は、動作確認として、nginx を動かし、そこにアクセスするための Service (type=LoadBalancer) を作成してみます。
そのために、↓こんな感じのマニフェストを用意してみました。

```yaml:nginx.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
```

このマニフェストを適用します。

```sh
kubectl apply -f nginx.yaml
```

作成した内容を確認します。

```sh
$ kubectl get -f nginx.yaml
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/nginx   LoadBalancer   100.71.81.242   172.19.31.1   80:31467/TCP   57s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx   1/1     1            1           56s
```

問題無さそうですね。
実際に `172.19.31.1` にブラウザからアクセスしてみて、いつもの `Welcome to nginx!` の画面が表示されれば、OK です。


# 最後に

前述の通り、TKG 2.1 では、NSX ALB が、推奨の LB 製品になりますし、Kube-Vip をユーザーワークロード用として使うのは、あくまで実験的な機能になります。
しかし、Kube-Vip は、非常に簡単に使えて、かつ省リソースなので、ラボ環境で使うには、面白い選択肢になるかなと思います。
ご興味あれば、お試しいただけると楽しいと思います！