TKG を DHCP 無しでデプロイしてみる

# はじめに

先日、2023年8月1日に TKG 2.3.0 がリリースされ、VMware Explore 2023 Las Vegas でも、いくつかのセッションでも、その更新内容が紹介されていました。

https://docs.vmware.com/jp/VMware-Tanzu-Kubernetes-Grid/2.3/tkg-deploy-mc/mgmt-release-notes.html

詳細はぜひ、リリースノートを参照いただければと思いますが、個人的にすごく良いと思ったアップデートが下記の部分です。

> * (vSphere) クラスタ内 IP アドレス管理 (IPAM) 機能が拡張されました。「[ノード IP アドレス管理](https://docs.vmware.com/jp/VMware-Tanzu-Kubernetes-Grid/2.3/using-tkg/workload-clusters-node-networking.html#ipam)」を参照してください。
>   * クラスベースのワークロード クラスタに加えて、スタンドアローン管理クラスタの IP アドレス管理。
>   * IPv6 のサポート。
>   * 異なる管理名前空間内のワークロード クラスタは、同じグローバル IP アドレス プールから IP アドレスを割り当てることができます。
>   * IP アドレス プールには、連続しない IP アドレス範囲を含めることができます。
>   * IP アドレス プール クエリ `kubectl get inclusterippool` は、`FREE` および `USED` アドレス数を出力します。
>   * 「構成ファイル変数リファレンス」の「[ノード IP アドレス管理](https://docs.vmware.com/jp/VMware-Tanzu-Kubernetes-Grid/2.3/tkg-deploy-mc/mgmt-deploy-config-ref.html)」で説明されているクラスタ構成変数。
>   * `InClusterIPPool` オブジェクト構造は、以前の TKG バージョンとは異なります。クラスタを v2.3 にアップグレードすると、IP アドレス プールが新しい構造に変換されます。

その他の拡張も含まれていますが、以前は TKG のデプロイに、DHCP が必要だったところ、IPAM 機能の導入により、DHCP 無しでデプロイできるようになっています！

確かに、ラボ環境であれば、DHCP サーバーも Ubuntu や VyOS を使って簡単に建てられます。

https://qiita.com/iwaseyusuke/items/0ac51439f476a36fb3ff

しかし、商用環境となると、「その DHCP サーバーの可用性はどうするんだ？」「いちいち用意するのか？」となるので、絶妙に痒いポイントでした。

TKG 2.3.0 からは、IPAM 機能の実装により、DHCP サーバー不要でデプロイできるようになっているので、今回は IPAM 機能を使って、TKG の Management Cluster と Workload Cluster をデプロイしてみたいと思います。


# 手順

基本的には、公式ドキュメントに記載の手順に従って、デプロイを実行して行きます。

https://docs.vmware.com/jp/VMware-Tanzu-Kubernetes-Grid/2.3/tkg-deploy-mc/mgmt-deploy-index.html

:::note warn
**注意**
TKG 2.3.0 時点では、IPAM 機能を利用する場合、`tanzu mc create --ui` で実行されるインストーラ インターフェイスから、直接 Management Cluster をデプロイすることができません。
とは言え、1から構成ファイルを書くのは大変なので、一旦、インストーラ インターフェイスを進めて、デプロイを実行する直前で、[構成の確認 (Review Configuration)] > [構成のエクスポート (Export Configuration)] を実行し、構成ファイルを途中まで生成してから、利用することをオススメします。
:::

また、手順で紹介で紹介しているパラメータの定義は、公式のリファレンスです。
[vSphere] > [ノード IP アドレス管理] のセクションを参照ください。

https://docs.vmware.com/jp/VMware-Tanzu-Kubernetes-Grid/2.3/tkg-deploy-mc/mgmt-deploy-config-ref.html


## Management Cluster のデプロイ

### 構成ファイルの作成

前述の通り、インストーラ インタフェースからは、直接はデプロイできないため、構成ファイルに下記を追記して、Tanzu CLI からデプロイを実行します。

追記する設定は、下記のようなイメージです。

```yaml: cluster-config.yaml 設定例
# ...(略)...

# 下記を追記
MANAGEMENT_NODE_IPAM_IP_POOL_GATEWAY: "10.10.10.1"
MANAGEMENT_NODE_IPAM_IP_POOL_ADDRESSES: "10.10.10.2-10.10.10.100,10.10.10.105"
MANAGEMENT_NODE_IPAM_IP_POOL_SUBNET_PREFIX: "24"
CONTROL_PLANE_NODE_NAMESERVERS: "10.10.10.10,10.10.10.11"
WORKER_NODE_NAMESERVERS: "10.10.10.10,10.10.10.11"
```

それぞれ分かりやすい命名になっているので、そこまで説明は要らないと思いますが、簡単に紹介すると下記の通りです。

* `MANAGEMENT_NODE_IPAM_IP_POOL_GATEWAY`
    * 各ノードにとってのデフォルト ゲートウェイを設定します。
* `MANAGEMENT_NODE_IPAM_IP_POOL_ADDRESSES`
    * 各ノードに割り当てる IP アドレス帯を設定します。
    * カンマ区切りにより、複数のアドレス帯を設定できます。
* `MANAGEMENT_NODE_IPAM_IP_POOL_SUBNET_PREFIX`
    * 各ノードに割り当てるネットワークのプレフィックス長を設定します。
* `CONTROL_PLANE_NODE_NAMESERVERS`
    * コントロール プレーン ノードにとっての DNS サーバーを設定します。
    * カンマ区切りにより、複数の DNS サーバーを設定できます。
    * その際、最初に記載された DNS サーバーが優先になります。
* `WORKER_NODE_NAMESERVERS`
    * ワーカー ノードにとっての DNS サーバーを設定します。
    * カンマ区切りにより、複数の DNS サーバーを設定できます。
    * その際、最初に記載された DNS サーバーが優先になります。


### デプロイの実行

構成ファイルが作成できたら、Tanzu CLI から Maangement Cluster をデプロイします。

```text: 実行例
tanzu mc create -f cluster-config.yaml
```


## Workload Cluster のデプロイ

### 構成ファイルの作成

公式ドキュメントでは、Cluster Class ベースの新しい記法で紹介されていますが、ここでは横着して、Plan ベースの古い記法で構成ファイルを作成し、それを Tanzu CLI で変換して利用することにします。
設定手順としては、Management Cluster の場合と異なり、まず、IP アドレスのプール、`InClusterIPPool` または `GlobalInClusterIPPool` を作成し、作成した IP プール名を構成ファイル内で指定することになります。

まず、IP アドレスのプールを作成しますが、前述の通り、2種類あります。

* `InClusterIPPool`
    * Management Cluster 内の特定の Namespace (例えば `default`) 内でのみ、共有できる IP プール。
    * Workload Cluster の構成ファイルでは、こちらがデフォルト。
* `GlobalInClusterIPPool`
    * 特定の Namespace に限らず、複数の Namespace 間で共有できる IP プール。

ここでは、`InClusterIPPool` を `default` の名前空間に作成して行きます。

```yaml: in-cluster-ip-pool.yaml の設定例
apiVersion: ipam.cluster.x-k8s.io/v1alpha2
kind: InClusterIPPool
metadata:
  name: in-cluster-ip-pool
  namespace: default
spec:
  gateway: 10.10.10.1
  addresses:
  - 10.10.10.2-10.10.10.100
  - 10.10.10.102
  - 10.10.10.104
  prefix: 24
```

`.spec` 内の記述は、Management Cluster のデプロイで利用した変数とほぼ同じです。

これを `kubectl` コマンドで適用し、IP プールを作成します。

```text: 実行例
kubectl apply -f in-cluster-ip-pool.yaml
```

では、作成した IP プールを使って、Workload Cluster のデプロイのための構成ファイルを作成していきます。

しかし、1から作成するは大変なので、またまた横着して、Management Cluster をデプロイする際に利用した `cluster-config.yaml` をコピーし、最低限、下記の辺りを修正して利用します。

```yaml: cluster-config 設定例
# ...(略)...

# クラスタ名なので、被らないように修正。
CLUSTER_NAME: tkc01
# "prod" だとコントロール プレーン ノードが 3台で冗長化され、"dev" だと 1台構成になります。
CLUSTER_PLAN: dev

# ...(略)...

# kube-apiserver の待ち受け IP アドレスになるので、被らないように修正。
VSPHERE_CONTROL_PLANE_ENDPOINT: 10.10.10.200

# ...(略)...

# その他、知っていると便利なパラメータは、↓この辺。
# 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

# ...(略)...

# Management Cluster の作成時に指定した MANAGEMENT_* の代わりに、下記を追記。
# NODE_IPAM_IP_POOL_KIND: "InClusterIPPool"
NODE_IPAM_IP_POOL_NAME: "in-cluster-ip-pool"
CONTROL_PLANE_NODE_NAMESERVERS: "10.10.10.10,10.10.10.11"
WORKER_NODE_NAMESERVERS: "10.10.10.10,10.10.10.11"
```

こちらも Management Cluster の時と、分かりやすい命名になっていますが、簡単に紹介すると下記の通りです。

* `NODE_IPAM_IP_POOL_KIND`
    * 先に作成した IP プールの種類、"InClusterIPPool" または "GlobalInClusterIPPool" を指定します。
    * デフォルトは "InClusterIPPool" なので、上記の例ではコメントアウトしています。
* `NODE_IPAM_IP_POOL_NAME`
    * 先に作成した IP プールの名前を指定します。
* `CONTROL_PLANE_NODE_NAMESERVERS`
    * コントロール プレーン ノードにとっての DNS サーバーを設定します。
    * カンマ区切りにより、複数の DNS サーバーを設定できます。
    * その際、最初に記載された DNS サーバーが優先になります。
* `WORKER_NODE_NAMESERVERS`
    * ワーカー ノードにとっての DNS サーバーを設定します。
    * カンマ区切りにより、複数の DNS サーバーを設定できます。
    * その際、最初に記載された DNS サーバーが優先になります。


### デプロイの実行

構成ファイルが作成できたら、前述の通り、古い記法で構成ファイルを作成しているので、これを Tanzu CLI で変換します。

```text: 実行例
tanzu cluster create --dry-run -f cluster-config.yaml > tkc01.yaml
```

コマンドの中でバリデーションが行われ、特に問題なければ、`tkc01.yaml` として Cluster Class ベースの構成ファイルが作成されるので、これを指定して、Workload Cluster を作成します。

```text: 実行例
tanzu cluster create -f tkc01.yaml
```

完了したら、作成した Workload Cluster の Context を取得します。

```text: 実行例
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-jn7hn-zjgxv                         Ready    control-plane   4m5s    v1.26.5+vmware.2
tkc01-md-0-zcslg-6bbcbdcb9bx5kd4c-mb2fp   Ready    <none>          3m20s   v1.26.5+vmware.2
tkc01-md-0-zcslg-6bbcbdcb9bx5kd4c-ntzhx   Ready    <none>          3m34s   v1.26.5+vmware.2
```


# まとめ

今回は、ある程度、デプロイ経験のある方向けに、DHCP 無しでデプロイする方法を紹介しました。

「DHCP が不要になった」と言うだけだと、地味ではるあるかと思いますが、いずれにしても必須要件が減って、柔軟性が増しているので、他の機能強化含めて、ぜひお試しいただければと思います。