KubernetesのCordon/Drainの動きをkindで検証

## はじめに

k8sにはNodeのメンテナンスなどの制御でCordon/Drainというものがあるらしい(勉強中)。しかしローカル検証環境であるminikubeは1Nodeなのでうまい検証ができない。これをクラスター環境を作れるkindで検証してみたい。（追記:minikubeも対応していた…)

何がしたいかというと、「Kubernetes道場」のこちらの記事をminikubeでなくkindでやってみたいということ。

https://cstoku.dev/posts/2018/k8sdojo-21/

### 追記

後日調べていたら・勉強していたら、既に2020年の時点でminikubeはマルチノードに対応してたことを知った…

https://minikube.sigs.k8s.io/docs/tutorials/multi_node/

次の方法で…

```sh
$ minikube start --nodes 3
```
```sh
$ kubectl get node        
NAME           STATUS   ROLES           AGE   VERSION
minikube       Ready    control-plane   73s   v1.32.0
minikube-m02   Ready    <none>          58s   v1.32.0
minikube-m03   Ready    <none>          44s   v1.32.0
```


## kindによるクラスター環境の準備

### インストール

https://qiita.com/tomoyafujita/items/5a3c06705f62c5732bc5

私はmacOSなので、

```sh
brew install kind
```

### クラスターの作成

とりあえず2Nodeとして次のファイルを作成し、

```yaml:kind-example-config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
```

クラスターを作成

```sh
kind create cluster --config kind-example-config.yaml
```

Node確認

```sh
$ kubectl get node
NAME                 STATUS   ROLES           AGE   VERSION
kind-control-plane   Ready    control-plane   62s   v1.32.0
kind-worker          Ready    <none>          53s   v1.32.0
kind-worker2         Ready    <none>          53s   v1.32.0
```

これでテストできる環境ができた。

## 検証

まずはnginxを動かしてみる

```sh
$ kubectl create deploy nginx --image nginx:alpine
deployment.apps/nginx created
```

NginxがどのNodeで動いているか確認すると、この時はkind-workerで動いている様子。

```sh
$ kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP           NODE          NOMINATED NODE   READINESS GATES
nginx-6b66fbbd46-gbb4v   1/1     Running   0          42s   10.244.1.2   kind-worker   <none>           <none>
```

### Drain

Nodeをメンテナンスする等を想定してこのkind-worker NodeをDrainする。

```sh
$ kubectl drain kind-worker --ignore-daemonsets 
node/kind-worker cordoned
Warning: ignoring DaemonSet-managed Pods: kube-system/kindnet-pc2m7, kube-system/kube-proxy-gvxlr
evicting pod default/nginx-6b66fbbd46-gbb4v
pod/nginx-6b66fbbd46-gbb4v evicted
node/kind-worker drained
```

すると、別Nodeであるkind-worker2に移動しRunning状態になっていることがわかる。

```sh
$ kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE   IP           NODE           NOMINATED NODE   READINESS GATES
nginx-6b66fbbd46-c842z   1/1     Running   0          24s   10.244.2.2   kind-worker2   <none>           <none>
```

また、kind-workerがSchedulingDisabledになっている

```sh
$ kubectl get nodes 
NAME                 STATUS                     ROLES           AGE     VERSION
kind-control-plane   Ready                      control-plane   3m31s   v1.32.0
kind-worker          Ready,SchedulingDisabled   <none>          3m21s   v1.32.0
kind-worker2         Ready                      <none>          3m21s   v1.32.0
```

次のコマンドで状態・イベントをみてみると該当NodeがTaintedになっていること、該当Podが別のNodeで起動したことがわかる。

```sh
$ kubectl describe nodes
略
$ kubectl describe pods
略
```

### Uncordon

メンテナンス等が終わったものとしてUncordonさせる

```sh
$ kubectl uncordon kind-worker
node/kind-worker uncordoned
```

```sh
$ kubectl describe node/kind-worker
〜〜〜
Taints:             <none>
Unschedulable:      false
〜〜〜
```

Taintsが消えて、Readyになっている

```sh
$ kubectl get nodes
NAME                 STATUS   ROLES           AGE     VERSION
kind-control-plane   Ready    control-plane   8m33s   v1.32.0
kind-worker          Ready    <none>          8m23s   v1.32.0
kind-worker2         Ready    <none>          8m23s   v1.32.0
```

### Cordon

今度はkind-worker,kind-worker2ともにCordonさせる。

```sh
$ kubectl cordon kind-worker  
node/kind-worker cordoned
$ kubectl cordon kind-worker2   
node/kind-worker2 cordoned
```

両方のWorker NodeともにSchedulingDisabledになっているが、

```sh
$ kubectl get nodes
NAME                 STATUS                     ROLES           AGE     VERSION
kind-control-plane   Ready                      control-plane   9m20s   v1.32.0
kind-worker          Ready,SchedulingDisabled   <none>          9m10s   v1.32.0
kind-worker2         Ready,SchedulingDisabled   <none>          9m10s   v1.32.0
```

すでに実行済みのPodはRunningのままになっている。

```sh
$ kubectl get pods -o wide 
NAME                     READY   STATUS    RESTARTS   AGE     IP           NODE           NOMINATED NODE   READINESS GATES
nginx-6b66fbbd46-c842z   1/1     Running   0          7m31s   10.244.2.2   kind-worker2   <none>           <none>
```

この状態で新規にhttpdを起動させてみようとすると

```sh
$ kubectl create deploy httpd --image httpd:alpine
deployment.apps/httpd created
```

どちらのWorker NodeもCordonで起動中のものは動き続けるが新規のスケジュールは受け付けないのでPendingとなる。

```sh
$ kubectl get pods -o wide 
NAME                     READY   STATUS    RESTARTS   AGE     IP           NODE           NOMINATED NODE   READINESS GATES
httpd-798d447958-ftwsf   0/1     Pending   0          18s     <none>       <none>         <none>           <none>
nginx-6b66fbbd46-c842z   1/1     Running   0          8m30s   10.244.2.2   kind-worker2   <none>           <none>
```

### Uncordon

この状態でkind-worker NodeをUncordonさせるとPodが実行できる様になるので

```
$ kubectl uncordon kind-worker
node/kind-worker uncordoned
```

PendingになっていたものがRunning状態になる。

```sh
$ kubectl get pods -o wide
NAME                     READY   STATUS    RESTARTS   AGE    IP           NODE           NOMINATED NODE   READINESS GATES
httpd-798d447958-ftwsf   1/1     Running   0          2m1s   10.244.1.3   kind-worker    <none>           <none>
nginx-6b66fbbd46-c842z   1/1     Running   0          10m    10.244.2.2   kind-worker2   <none>           <none>
```

kind-worker2もUncordenすると

```sh
$ kubectl uncordon kind-worker2
node/kind-worker2 uncordoned
```

どちらのNodeもReadyになり今後動くPodはどちらのNodeでも実行可能になる。

```sh
$ kubectl get nodes
NAME                 STATUS   ROLES           AGE   VERSION
kind-control-plane   Ready    control-plane   15m   v1.32.0
kind-worker          Ready    <none>          15m   v1.32.0
kind-worker2         Ready    <none>          15m   v1.32.0
```