Container Engine for Kubernetes (OKE)の新しいバージョンアップ手順（on-demand node cycling）を確認する

# はじめに
Container Engine for Kubernetes (OKE)のバージョンアップ手順として新しくon-demand node cycling機能が実装されました。これはWorker Nodeのアップグレード手順を簡素化してくれる機能です。

https://docs.oracle.com/en-us/iaas/releasenotes/changes/f018e024-65d0-4f87-a1e0-dc1ba0d30e48/

https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengupgradingimageworkernode_topic-Performing_an_InPlace_Worker_Node_Update_By_Cycling_an_Existing_Node_Pool.htm

https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengupgradingk8sworkernode_topic-Performing_an_InPlace_Worker_Node_Upgrade_by_Cycling_an_Existing_Node_Pool.htm

実際のところどうなのか確認してみます。

なお、この機能を使うためには「拡張クラスタ」である必要があります。
拡張クラスタは2023年3月にGAになった機能で、それ以前のクラスタは「基本クラスタ」と呼ばれています。
拡張クラスタと基本クラスタの違いはこちらをご参照ください。

https://docs.oracle.com/ja-jp/iaas/Content/ContEng/Tasks/contengcomparingenhancedwithbasicclusters_topic.htm

# 環境の確認
今回は2ノードのクラスタを用意しました。

```
$ k get node
NAME          STATUS   ROLES   AGE    VERSION
10.0.10.13    Ready    node    4h8m   v1.25.4
10.0.10.218   Ready    node    4h8m   v1.25.4
```

Kubernetesのバージョンはv1.25.4で、これをv1.26.2に上げます。

OCIのコンソール上でバージョンアップができると表示されています。

![スクリーンショット 2023-05-09 13.36.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/c66994af-3aa1-7b28-197c-29eca2577e22.png)

ちなみに、基本クラスタから拡張クラスタにアップグレードすることもできますので、基本クラスタを使っているけど、この機能を試してみたい場合には、コンソールから`拡張クラスタへのアップグレード`をクリックすると、拡張クラスタに変えることができます。（拡張クラスタから基本クラスタに変更することはできません）
なお、拡張クラスタは基本クラスタと違って、クラスタそのものが課金対象となりますのでご注意ください。

動作確認用にDeploymentで2つのPodを作成しています。

```
$ k get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP             NODE          NOMINATED NODE   READINESS GATES
nginx-76d6c9b8c-9vdft   1/1     Running   0          49m   10.244.0.4     10.0.10.13    <none>           <none>
nginx-76d6c9b8c-nc92w   1/1     Running   0          49m   10.244.0.131   10.0.10.218   <none>           <none>
```

# バージョンアップ
コントロールプレーン -> Worker Nodeの順にバージョンアップします。

## コントロールプレーン
OCIのコンソールから`Kubernetesの新バージョンを使用できます`をクリックします。

以下の画面でバージョンを選択して、`アップグレード`をクリックします。
![スクリーンショット 2023-05-09 13.38.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/d5083abb-a019-2b96-561a-bbeb4d1ddb24.png)

この画面になります。
![スクリーンショット 2023-05-09 13.38.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/bcfa7259-c581-ad74-070b-67c85d9d5156.png)

少し待つとアイコンがグリーンに変わって、v1.26.2にバージョンアップできたことが確認できます。
![スクリーンショット 2023-05-09 13.51.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/bc1993a4-09bd-ac41-1a62-e658ef01821f.png)

## Worker Node
OKEのWorker Nodeはノードプールという単位でプロビジョニングされています。
クラスタのコンソールから、ノードプールの詳細画面に行きます。

現状では、ノードプールのバージョンはv1.25.4のままです。
この画面で`編集`をクリックします。

![スクリーンショット 2023-05-09 16.14.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/e3fe1aca-b5d6-cb57-f03b-ba61b8921cbc.png)

この画面のバージョンでv1.26.2を選択して、`変更の保存`をクリックします。

![スクリーンショット 2023-05-09 16.20.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/35d193ce-9a65-ab52-9910-52cc92e74f28.png)

ノードプールのバージョンがv1.26.2に変わりました。

![スクリーンショット 2023-05-09 16.22.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/1b47431c-870e-4062-72d3-7e91a1a801a2.png)

ここまでは基本クラスタでも同じで、ここからがon-demand node cyclingの手順になります。

OCIのコンソールで`サイクル・ノード`をクリックします。
この画面で最大サージと最大使用不可の数値を設定します。

![スクリーンショット 2023-05-09 16.15.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/39653fca-b969-a26d-f16e-4a20636b85bd.png)

- 最大サージ
    - バージョンアップ時に一度に追加するノード数の上限
- 最大使用不可
    - バージョンアップ時に使用できないようにするノード数の上限

バージョンアップはそのノードのKubernetesのバージョンを上げるのではなく、新しいバージョンのノードを追加して、古いバージョンのノードを削除する動作になります。
そのため、バージョンアップ時に性能を落としたくない場合は、最大サージ数を1以上にして、最大使用不可を0にします。この場合は一時的にノード数が増えますので、その分コストがかかることになります。
逆に、バージョンアップ時にコストを増やしたくないのであれば、最大サージ数を0にして、最大使用不可を1以上にします。この場合は一時的にノード数が減りますので、性能（Podが起動できないなど）に影響が出る可能性があります。

今回はそれぞれ1ずつにしてみました。

コンソール上では以下のように新しいノードが追加されています。

![スクリーンショット 2023-05-09 16.27.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/458a1664-5042-11d2-bf78-d9d9b88c1d10.png)

ノードのバージョンアップ（入れ替え）が終わると以下のようになります。

![スクリーンショット 2023-05-09 16.33.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492530/785379ce-be3b-9d27-cc9b-356979cb8bfa.png)

ノードの動きをkubectlコマンドでも確認しました。

```
$ k get node -w
NAME          STATUS   ROLES   AGE     VERSION
10.0.10.13    Ready    node    6h58m   v1.25.4
10.0.10.218   Ready    node    6h58m   v1.25.4
10.0.10.218   Ready,SchedulingDisabled   node    6h58m   v1.25.4
10.0.10.218   NotReady,SchedulingDisabled   node    6h59m   v1.25.4
10.0.10.91    NotReady                      <none>   0s      v1.26.2
10.0.10.91    NotReady                      <none>   51s     v1.26.2
10.0.10.91    Ready                         <none>   54s     v1.26.2
10.0.10.91    Ready                         node     73s     v1.26.2
10.0.10.13    Ready,SchedulingDisabled      node     7h1m    v1.25.4
10.0.10.199   NotReady                      <none>   0s      v1.26.2
10.0.10.199   NotReady                      <none>   20s     v1.26.2
10.0.10.13    NotReady,SchedulingDisabled   node     7h2m    v1.25.4
10.0.10.199   NotReady                      <none>   62s     v1.26.2
10.0.10.199   Ready                         <none>   66s     v1.26.2
10.0.10.199   Ready                         <none>   68s     v1.26.2
10.0.10.199   Ready                         node     90s     v1.26.2
10.0.10.199   Ready                         node     2m35s   v1.26.2
10.0.10.91    Ready                         node     4m14s   v1.26.2
```

削除されてから追加しているような動きですね。
最終的にはこうなりました。

```
$ k get node
NAME          STATUS   ROLES   AGE     VERSION
10.0.10.199   Ready    node    96s     v1.26.2
10.0.10.91    Ready    node    3m15s   v1.26.2
```

Podの動きも確認しました。

```
$ k get pod -o wide -w
NAME                    READY   STATUS    RESTARTS   AGE     IP           NODE         NOMINATED NODE   READINESS GATES
nginx-76d6c9b8c-9vdft   1/1     Running   0          3h40m   10.244.0.4   10.0.10.13   <none>           <none>
nginx-76d6c9b8c-f744z   1/1     Running   0          2m12s   10.244.0.5   10.0.10.13   <none>           <none>
nginx-76d6c9b8c-9vdft   1/1     Running   0          3h41m   10.244.0.4   10.0.10.13   <none>           <none>
nginx-76d6c9b8c-9vdft   1/1     Terminating   0          3h41m   10.244.0.4   10.0.10.13   <none>           <none>
nginx-76d6c9b8c-f744z   1/1     Running       0          3m9s    10.244.0.5   10.0.10.13   <none>           <none>
nginx-76d6c9b8c-f744z   1/1     Terminating   0          3m9s    10.244.0.5   10.0.10.13   <none>           <none>
nginx-76d6c9b8c-tcbdd   0/1     Pending       0          0s      <none>       <none>       <none>           <none>
nginx-76d6c9b8c-tcbdd   0/1     Pending       0          0s      <none>       10.0.10.91   <none>           <none>
nginx-76d6c9b8c-tcbdd   0/1     ContainerCreating   0          0s      <none>       10.0.10.91   <none>           <none>
nginx-76d6c9b8c-44qhc   0/1     ContainerCreating   0          0s      <none>       10.0.10.91   <none>           <none>
nginx-76d6c9b8c-f744z   0/1     Terminating         0          3m10s   10.244.0.5   10.0.10.13   <none>           <none>
nginx-76d6c9b8c-9vdft   0/1     Terminating         0          3h41m   10.244.0.4   10.0.10.13   <none>           <none>
nginx-76d6c9b8c-44qhc   1/1     Running             0          35s     10.244.0.131   10.0.10.91   <none>           <none>
nginx-76d6c9b8c-tcbdd   1/1     Running             0          35s     10.244.0.132   10.0.10.91   <none>           <none>
```

最終的にはこうなりました。

```
$ k get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE     IP             NODE         NOMINATED NODE   READINESS GATES
nginx-76d6c9b8c-44qhc   1/1     Running   0          4m29s   10.244.0.131   10.0.10.91   <none>           <none>
nginx-76d6c9b8c-tcbdd   1/1     Running   0          4m29s   10.244.0.132   10.0.10.91   <none>           <none>
```

ノードが減ってから増える動作でしたので、最終的は２つのPodが一つのノードに寄せられた形になりました。
今回は２ノードのクラスタでしたのでこのようになりました。通常は3ノード以上だと思いますが、3ノード以上の場合には、最後に追加されたノードに（Daemonsetを除き）Podがない状態になると思います。
これを防ぎたいのであれば、追加してから削除する動作（「最大使用不可」を0）にする必要がありますね。

# まとめ
今回確認したon-demand node cyclingを使わない場合は、ノードプールのバージョンを上げた後に以下の手順を手動で実施する必要があります。

- ノードの追加（スケール）
- kubectl drain
- ノードの削除

これをやらないで良いので、バージョンアップが楽になったと感じました。