OpenStack Provider で動作させた Workload Cluster を更新する

# 目的

以前の記事である [Cluster API の OpenStack Provider を利用する](https://qiita.com/yoshi_1010/items/7d8f2117e115423746e5) では Cluster API の OpenStack Provider を利用して Workload Cluster を動作させた。
今回の記事ではこの作成した Workload Cluster を更新する。

Cluster API ではマニフェストベースで Kubernetes Cluster を管理することができる。
Kubernetes Cluster の更新もまたマニフェストを編集し、apply することで実施できる。
今回は実際にマシンを動作させつつ、Workload Cluster の更新手順をまとめる。

# 構成

下記のマシンを 1 台準備する。
準備したマシンには Management Cluster 用に kind をインストールし、OpenStack 用に DevStack を動作させる。

- Disk: 200GB
- Cores: 8 core
- Memory: 24GB
- OS: Ubuntu 20.04

# 手順

ドキュメントに記載されている Workload Cluster を更新する手順は下記である。

1. 既存の MachineTemplate (openstackmachinetemplates) をコピー
2. インスタンスタイプやイメージ ID など、変更が必要な値を変更
3. Management Cluster で新しい MachineTemplate を作成
4. 既存の KubeadmControlPlane リソースを変更して、infrastructureRef フィールドで新しい MachineTemplate リソースを参照

上記の手順だけでは実際に更新する手順を理解することが難しいため、実際に動作させつつ、更新する。

現状の Workload Cluster 動作状況は下記のとおりである。

```
$ clusterctl describe cluster capi-quickstart-openstack
NAME                                                                          READY  SEVERITY  REASON  SINCE  MESSAGE
Cluster/capi-quickstart-openstack                                             True                     97m
├─ClusterInfrastructure - OpenStackCluster/capi-quickstart-openstack
├─ControlPlane - KubeadmControlPlane/capi-quickstart-openstack-control-plane  True                     97m
│ └─Machine/capi-quickstart-openstack-control-plane-hbtrl                     True                     98m
└─Workers
  └─MachineDeployment/capi-quickstart-openstack-md-0                          True                     18m
    └─Machine/capi-quickstart-openstack-md-0-xfz6x-k6gh4                      True                     96m

$ openstack server list
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
| ID                                   | Name                                          | Status | Networks                                                                       | Image                     | Flavor    |
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
| 738dd6b9-364c-4f40-b5f7-612218a07c22 | capi-quickstart-openstack-md-0-jswjh          | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.115            | ubuntu-2004-kube-v1.23.10 | m1.medium |
| 16807128-b637-48dc-9525-ad6ca2150282 | capi-quickstart-openstack-control-plane-tm72v | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.43, 172.24.4.2 | ubuntu-2004-kube-v1.23.10 | m1.medium |
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
```

## 既存の MachineTemplate (openstackmachinetemplates) をコピー

OpenStack Provider で Workload Cluster を更新する場合、MachineTemplate を更新する。
MachineTemplate は Workload Cluster 起動時に利用する Workload Cluster の構成要素を記載したリソースである。
このリソースで起動時に利用する flavor やイメージ等を管理する。

既存の環境では下記のような MachineTemplate を利用していた。

- capi-quickstart-openstack-control-plane: Master Node の MachineTemplate
- capi-quickstart-openstack-md-0: Worker Node の MachineTemplate

```
$ cat capi-quickstart-openstack.yaml
...
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha7
kind: OpenStackMachineTemplate
metadata:
  name: capi-quickstart-openstack-control-plane
  namespace: default
spec:
  template:
    spec:
      cloudName: demo
      flavor: m1.medium
      identityRef:
        kind: Secret
        name: capi-quickstart-openstack-cloud-config
      image: ubuntu-2004-kube-v1.23.10
      sshKeyName: keypair1
---
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha7
kind: OpenStackMachineTemplate
metadata:
  name: capi-quickstart-openstack-md-0
  namespace: default
spec:
  template:
    spec:
      cloudName: demo
      flavor: m1.medium
      identityRef:
        kind: Secret
        name: capi-quickstart-openstack-cloud-config
      image: ubuntu-2004-kube-v1.23.10
      sshKeyName: keypair1
...
```

## 変更が必要な値を変更

今回は OpenStack の flavor を変更する。
初期環境では Master/Worker Node ともに m1.medium で動作させているところを Worker Node のみ m1.large に変更する。

```
cat << _EOF_ > new_machinetemplate.yaml
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha7
kind: OpenStackMachineTemplate
metadata:
  name: capi-quickstart-openstack-md-1
  namespace: default
spec:
  template:
    spec:
      cloudName: demo
      flavor: m1.large
      identityRef:
        kind: Secret
        name: capi-quickstart-openstack-cloud-config
      image: ubuntu-2004-kube-v1.23.10
      sshKeyName: keypair1
_EOF_
```

既存の MachineTemplate との差分を取得すると下記のようになる。

```
# 既存の Worker Node MachineTemplate
$ cat << _EOF_ > old_machinetemplate.yaml
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha7
kind: OpenStackMachineTemplate
metadata:
  name: capi-quickstart-openstack-md-0
  namespace: default
spec:
  template:
    spec:
      cloudName: demo
      flavor: m1.medium
      identityRef:
        kind: Secret
        name: capi-quickstart-openstack-cloud-config
      image: ubuntu-2004-kube-v1.23.10
      sshKeyName: keypair1
_EOF_

# 差分を取得する
$ diff old_machinetemplate.yaml new_machinetemplate.yaml
4c4
<   name: capi-quickstart-openstack-md-0
---
>   name: capi-quickstart-openstack-md-1
10c10
<       flavor: m1.medium
---
>       flavor: m1.large
```

## Management Cluster で新しい MachineTemplate を作成

変更した MachineTemplate を apply する。

MachineTemplate は変更できない (immutable な) リソースであるため、必ず新規作成する。 

```
$ kubectl apply -f new_machinetemplate.yaml
openstackmachinetemplate.infrastructure.cluster.x-k8s.io/capi-quickstart-openstack-md-1 created
```

確認する。

```
$ kubectl get openstackmachinetemplates.infrastructure.cluster.x-k8s.io
NAME                                      AGE
capi-quickstart-openstack-control-plane   110m
capi-quickstart-openstack-md-0            110m
capi-quickstart-openstack-md-1            101s
```

## 既存の KubeadmControlPlane リソースの infrastructureRef フィールド修正

MachineDeployment リソースの infrastructureRef を修正する。

[Cluster API の OpenStack Provider を利用する](https://qiita.com/yoshi_1010/items/7d8f2117e115423746e5) の記事を参考に Cluster API を用いている場合、capi-quickstart-openstack.yaml というマニフェストファイルから Workload Cluster を作成しているはずである。
このファイルを確認すると、既存の MachineDeployment リソースは下記のように動作していることがわかる。

```
$ cat capi-quickstart-openstack.yaml
...
apiVersion: cluster.x-k8s.io/v1beta1
kind: MachineDeployment
metadata:
  name: capi-quickstart-openstack-md-0
  namespace: default
spec:
  clusterName: capi-quickstart-openstack
  replicas: 1
  selector:
    matchLabels: null
  template:
    spec:
      bootstrap:
        configRef:
          apiVersion: bootstrap.cluster.x-k8s.io/v1beta1
          kind: KubeadmConfigTemplate
          name: capi-quickstart-openstack-md-0
      clusterName: capi-quickstart-openstack
      failureDomain: nova
      infrastructureRef:
        apiVersion: infrastructure.cluster.x-k8s.io/v1alpha7
        kind: OpenStackMachineTemplate
        name: capi-quickstart-openstack-md-0
      version: v1.23.10
...
```

上記の `spec.template.spec.infrastructureRef.name` を修正する。

```
capi-quickstart-openstack.yaml のバックアップを取得する
$ cp -ai capi-quickstart-openstack.yaml capi-quickstart-openstack.yaml.default

$ vim capi-quickstart-openstack.yaml
spec.template.spec.infrastructureRef.name を修正

$ diff capi-quickstart-openstack.yaml.default capi-quickstart-openstack.yaml
70c70
<         name: capi-quickstart-openstack-md-0
---
>         name: capi-quickstart-openstack-md-1
```

capi-quickstart-openstack.yaml を apply する。

```
kubectl apply -f capi-quickstart-openstack.yaml
```

apply 時に `clusterctl describe cluster capi-quickstart-openstack` を watch コマンド等を利用して確認すると変更の流れがわかる。

実行中の `openstack server list` を確認すると、一時的にインスタンスが 1 台増加していることがわかる。

```
$ openstack server list
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
| ID                                   | Name                                          | Status | Networks                                                                       | Image                     | Flavor    |
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
| 677a784c-aefd-4ff6-9ea5-bef1711d1af1 | capi-quickstart-openstack-md-1-wvkhv          | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.106            | ubuntu-2004-kube-v1.23.10 | m1.large  |
| 738dd6b9-364c-4f40-b5f7-612218a07c22 | capi-quickstart-openstack-md-0-jswjh          | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.115            | ubuntu-2004-kube-v1.23.10 | m1.medium |
| 16807128-b637-48dc-9525-ad6ca2150282 | capi-quickstart-openstack-control-plane-tm72v | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.43, 172.24.4.2 | ubuntu-2004-kube-v1.23.10 | m1.medium |
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
```

新規インスタンスが動作した後は既存のインスタンスが停止する。
最終的には下記のように m1.medium で動作していたインスタンスが m1.large で動作するようになった。

```
$ clusterctl describe cluster capi-quickstart-openstack
NAME                                                                          READY  SEVERITY  REASON  SINCE  MESSAGE
Cluster/capi-quickstart-openstack                                             True                     133m
├─ClusterInfrastructure - OpenStackCluster/capi-quickstart-openstack
├─ControlPlane - KubeadmControlPlane/capi-quickstart-openstack-control-plane  True                     133m
│ └─Machine/capi-quickstart-openstack-control-plane-hbtrl                     True                     135m
└─Workers
  └─MachineDeployment/capi-quickstart-openstack-md-0                          True                     55m
    └─Machine/capi-quickstart-openstack-md-0-ms6mp-2ck42                      True                     5m16s

$ openstack server list
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
| ID                                   | Name                                          | Status | Networks                                                                       | Image                     | Flavor    |
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
| 677a784c-aefd-4ff6-9ea5-bef1711d1af1 | capi-quickstart-openstack-md-1-wvkhv          | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.106            | ubuntu-2004-kube-v1.23.10 | m1.large  |
| 16807128-b637-48dc-9525-ad6ca2150282 | capi-quickstart-openstack-control-plane-tm72v | ACTIVE | k8s-clusterapi-cluster-default-capi-quickstart-openstack=10.6.0.43, 172.24.4.2 | ubuntu-2004-kube-v1.23.10 | m1.medium |
+--------------------------------------+-----------------------------------------------+--------+--------------------------------------------------------------------------------+---------------------------+-----------+
```

## 補足: MachineTemplate について

MachineTemplate 自体は複数の Workload Cluster から同時利用が可能である。
そのため、複数の Machine リソースが同じ MachineTemplate を使用した際、他のクラスタを削除するとどうなるか調査する。
この調査では 2 つの Workload Cluster を同じ MachineTemplate を利用して起動する。
結果は下記のとおりとなった。


- 1 つ目のクラスタ (最初から起動) 削除 -> MachineTemplate は削除されない
- 2 つ目のクラスタ (後から起動) 削除 -> MachineTemplate は削除されない
- 2 つのクラスタ両方とも削除 -> MachineTemplate は削除される
- 交互にクラスタを削除する -> どちらかのクラスタが動作している限り MachineTemplate は削除されない

下記のように MachineTemplate の describe を確認すると Owner References で参照されているリソースが確認できた。
以上の実験より、この参照がなくなった時点で MachineTemplate が削除されると考える。

```
$ kubectl describe openstackmachinetemplates.infrastructure.cluster.x-k8s.io capi-quickstart-md-0
  ...
  Owner References:
    API Version:     cluster.x-k8s.io/v1beta1
    Kind:            Cluster
    Name:            capi-quickstart-v2
    UID:             10e514a3-35ae-418c-804c-bf30e7f66302
    API Version:     cluster.x-k8s.io/v1beta1
    Kind:            Cluster
    Name:            capi-quickstart
    UID:             77b08830-af05-40d3-91eb-0178fe801aad
```

Machine Template の参照を切り替えた場合、該当クラスタが以前まで使用していた Machine Template の Owner References に Workload Cluster の情報が残った。

```
$ kubectl get openstackmachinetemplates.infrastructure.cluster.x-k8s.io
NAME                            AGE
capi-quickstart-control-plane   116m
capi-quickstart-md-0            116m
capi-quickstart-md-1            18m
capi-quickstart-md-2            6m19s

$ kubectl describe openstackmachinetemplates.infrastructure.cluster.x-k8s.io capi-quickstart-md-0
  Owner References:
    API Version:     cluster.x-k8s.io/v1beta1
    Kind:            Cluster
    Name:            capi-quickstart
    UID:             77b08830-af05-40d3-91eb-0178fe801aad

$ kubectl describe openstackmachinetemplates.infrastructure.cluster.x-k8s.io capi-quickstart-md-1
  Owner References:
    API Version:     cluster.x-k8s.io/v1beta1
    Kind:            Cluster
    Name:            capi-quickstart
    UID:             77b08830-af05-40d3-91eb-0178fe801aad

$ kubectl describe openstackmachinetemplates.infrastructure.cluster.x-k8s.io capi-quickstart-md-2
  Owner References:
    API Version:     cluster.x-k8s.io/v1beta1
    Kind:            Cluster
    Name:            capi-quickstart
    UID:             77b08830-af05-40d3-91eb-0178fe801aad

$ kubectl delete cluster capi-quickstart
cluster.cluster.x-k8s.io "capi-quickstart" deleted

$ kubectl get openstackmachinetemplates.infrastructure.cluster.x-k8s.io
No resources found in default namespace.
```

また、クラスタが起動した後に MachineTemplate を削除したとしても、起動が完了したクラスタに影響が出ないこともわかった。

```
$ kubectl get machine -w
NAME                                   CLUSTER           NODENAME                              PROVIDERID                                          PHASE     AGE     VERSION
capi-quickstart-control-plane-fbjj7    capi-quickstart   capi-quickstart-control-plane-22rnb   openstack:///4e9615e5-8a0a-4e50-b60d-f475488ee0c9   Running   4m49s   v1.23.10
capi-quickstart-md-0-88cdd4c56-2n5wj   capi-quickstart   capi-quickstart-md-0-68bg9            openstack:///95a4f167-4c3c-46fb-b6fb-ddc2467cbfb7   Running   5m3s    v1.23.10

$ kubectl get openstackmachinetemplates.infrastructure.cluster.x-k8s.io
NAME                            AGE
capi-quickstart-control-plane   5m58s
capi-quickstart-md-0            5m58s

$ kubectl delete openstackmachinetemplates.infrastructure.cluster.x-k8s.io capi-quickstart-md-0
openstackmachinetemplate.infrastructure.cluster.x-k8s.io "capi-quickstart-md-0" deleted

$ kubectl delete openstackmachinetemplates.infrastructure.cluster.x-k8s.io capi-quickstart-control-plane
openstackmachinetemplate.infrastructure.cluster.x-k8s.io "capi-quickstart-control-plane" deleted

$ kubectl get machine
NAME                                   CLUSTER           NODENAME                              PROVIDERID                                          PHASE     AGE     VERSION
capi-quickstart-control-plane-fbjj7    capi-quickstart   capi-quickstart-control-plane-22rnb   openstack:///4e9615e5-8a0a-4e50-b60d-f475488ee0c9   Running   7m38s   v1.23.10
capi-quickstart-md-0-88cdd4c56-2n5wj   capi-quickstart   capi-quickstart-md-0-68bg9            openstack:///95a4f167-4c3c-46fb-b6fb-ddc2467cbfb7   Running   7m52s   v1.23.10

$ kubectl --kubeconfig=capi-quickstart.kubeconfig get node
NAME                                  STATUS     ROLES                  AGE     VERSION
capi-quickstart-control-plane-22rnb   NotReady   control-plane,master   6m11s   v1.23.10
capi-quickstart-md-0-68bg9            NotReady   <none>                 3m40s   v1.23.10
```

# まとめ

今回は OpenStack Provider で動作させた Workload Cluster の更新をした。
また、更新時に使用する MachineTemplate リソースについて調査しまとめた。

Cluster API を用いることでマニフェストベースで Kubernetes Cluster を管理できる。
Kubernetes Cluster を運用しているとクラスタの更新は必要な作業として浮上する。
Cluster API では Kubernetes Cluster そのものをマニフェストファイルとして管理でき、そのマニフェストファイルを正しく記述することで基盤を意識することなく Kubernetes Cluster を管理できる。
また、マニフェストファイルを Git 等のバージョン管理ツールで管理することでファイル自体の差分管理もでき、以前の環境と現環境の比較も容易になる。