スケジューリングの検証 - NodeSelector

# これは何

NodeSelectorの動きの検証

# 検証リストと結果

* NodeSelectorでPodを特定のNodeに配置した後でNodeのラベルを消す
    * ⇒何も起こらない
* NodeSelectorでPodを特定のNodeに配置した後でPodのNodeSelectorを更新する
    * ⇒Podが再作成されて反映される
* NodeSelectorで同時に満たすことが可能な複数のラベルを設定する
    * ⇒ちゃんと複数のラベルの条件にマッチしたNodeにスケジューリングされる
* NodeSelectorで同時に満たすことが不可能な複数のラベルを設定する
    * ⇒条件にマッチするNodeが無いとしてPendingになる

# tl;dr

* Node側のラベルについては、恐らくkube-shcedulerはスケジューリング時にしか見ていない
    * そのため、スケジューリング後にNodeのラベルを変更しても何も起こらない
    * 他のNodeにラベルを貼っても、そっちに移動したりはしない
        * この問題の解決はdeschedulerが必要

* DeploymentやPod側のラベルが更新されれば、即時反映される
    * これは恐らく、厳密にはPodが再作成されるので再度スケジューリングのプロセスを通過するため

# 以下、具体的な検証内容

## NodeSelectorでPodを特定のNodeに配置してからNodeのラベルを消す

普通にNodeSelectorでNodeを指定するようにして配置する。

```
PS C:\dev\temp\20191209> kubectl get node
NAME                                        STATUS   ROLES    AGE   VERSION
ip-10-0-1-174.us-east-2.compute.internal    Ready    <none>   31h   v1.14.7-eks-1861c5
ip-10-0-54-134.us-east-2.compute.internal   Ready    <none>   31h   v1.14.7-eks-1861c5
ip-10-0-91-149.us-east-2.compute.internal   Ready    <none>   31h   v1.14.7-eks-1861c5
PS C:\dev\temp\20191209> kubectl get node -l NoScheduleTest
NAME                                       STATUS   ROLES    AGE   VERSION
ip-10-0-1-174.us-east-2.compute.internal   Ready    <none>   31h   v1.14.7-eks-1861c5
```

```
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  strategy: {}
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - image: nginx
        name: nginx
      nodeSelector:
        NoScheduleTest: "True"
```

```
PS C:\dev\temp\20191209> kubectl apply -f .\test.yaml
deployment.apps/test created
PS C:\dev\temp\20191209> kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE                                       NOMINATED NODE   READINESS GATES
test-84c94bbd8f-s5zbh   1/1     Running   0          20s   10.0.16.103   ip-10-0-1-174.us-east-2.compute.internal   <none>           <none>
```

ここで、Podが配置された後にNodeのラベルを剥がしても何も起こらない。

```
PS C:\dev\temp\20191209> kubectl label node ip-10-0-1-174.us-east-2.compute.internal NoScheduleTest-
node/ip-10-0-1-174.us-east-2.compute.internal labeled
PS C:\dev\temp\20191209> kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE    IP            NODE                                       NOMINATED NODE   READINESS GATES
test-84c94bbd8f-s5zbh   1/1     Running   0          3m7s   10.0.16.103   ip-10-0-1-174.us-east-2.compute.internal   <none>           <none>
```

ついでに、他のNodeに該当のラベルを貼ってみても何も起こらない。

```
PS C:\dev\temp\20191209> kubectl label node ip-10-0-91-149.us-east-2.compute.internal NoScheduleTest=True
node/ip-10-0-91-149.us-east-2.compute.internal labeled
PS C:\dev\temp\20191209> kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE     IP            NODE                                       NOMINATED NODE   READINESS GATES
test-84c94bbd8f-s5zbh   1/1     Running   0          4m35s   10.0.16.103   ip-10-0-1-174.us-east-2.compute.internal   <none>           <none>
```

## NodeSelectorでPodを特定のNodeに配置した後でPodのNodeSelectorを更新する

普通にNodeSelectorでNodeを指定するようにして配置する。

```
PS C:\dev\temp\20191209> kubectl get node -l Test=True
NAME                                        STATUS   ROLES    AGE    VERSION
ip-10-0-91-149.us-east-2.compute.internal   Ready    <none>   3d5h   v1.14.7-eks-1861c5
PS C:\dev\temp\20191209> kubectl get node -l Test=False
NAME                                       STATUS   ROLES    AGE    VERSION
ip-10-0-1-174.us-east-2.compute.internal   Ready    <none>   3d6h   v1.14.7-eks-1861c5
```

```
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  strategy: {}
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - image: nginx
        name: nginx
      nodeSelector:
        Test: "True"
```

```
PS C:\dev\temp\20191209> kubectl apply -f .\test.yaml
deployment.apps/test created
PS C:\dev\temp\20191209> kubectl get pod -o wide
NAME                   READY   STATUS    RESTARTS   AGE   IP            NODE                                        NOMINATED NODE   READINESS GATES
test-5b89bbf9f-g4wbq   1/1     Running   0          11s   10.0.95.169   ip-10-0-91-149.us-east-2.compute.internal   <none>           <none>
PS C:\dev\temp\20191209>
```

NodeSelectorの値を`True`から`False`に変えてDeploymentをデプロイ。

```
      nodeSelector:
        Test: "False"
```

```
PS C:\dev\temp\20191209> kubectl apply -f .\test.yaml
deployment.apps/test configured
```


ちゃんとPodが再作成され、NodeSelectorで指定した条件を満たすNodeに配置された。

```
PS C:\dev\temp\20191209> kubectl get pod -o wide
NAME                   READY   STATUS    RESTARTS   AGE   IP            NODE                                       NOMINATED NODE   READINESS GATES
test-cf8d65d84-rb9ct   1/1     Running   0          14s   10.0.16.103   ip-10-0-1-174.us-east-2.compute.internal   <none>           <none>
```

## NodeSelectorで同時に満たすことが不可能な複数のラベルを設定する

`False`だけのNodeと、`False`と`True`が両方貼ってあるNodeの2つを用意する。

```
C:\dev\temp\20191209> kubectl get node -L NodeAffinityTest -L NodeSelectorTest
NAME                                        STATUS   ROLES    AGE   VERSION              NODEAFFINITYTEST   NODESELECTORTEST
ip-10-0-1-174.us-east-2.compute.internal    Ready    <none>   4d    v1.14.7-eks-1861c5   False              true
ip-10-0-54-134.us-east-2.compute.internal   Ready    <none>   4d    v1.14.7-eks-1861c5   False
ip-10-0-91-149.us-east-2.compute.internal   Ready    <none>   4d    v1.14.7-eks-1861c5
PS C:\dev\temp\20191209>
```

NodeSelectorに2つを指定してデプロイ。

```
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  strategy: {}
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - image: nginx
        name: nginx
      nodeSelector:
        NodeAffinityTest: "False"
        NodeSelectorTest: "true"
```

```
PS C:\dev\temp\20191209> kubectl apply -f .\test.yaml
deployment.apps/test created
PS C:\dev\temp\20191209> kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE                                       NOMINATED NODE   READINESS GATES
test-64cc7fddf7-46ln8   1/1     Running   0          9s    10.0.19.186   ip-10-0-1-174.us-east-2.compute.internal   <none>           <none>
```

ちゃんと、両方を満たすNodeにスケジューリングされた。

## NodeSelectorで同時に満たせない複数のラベルを設定。

`False`、`True`のNodeをそれぞれ1つずつ用意する。
両方が貼られているNodeは存在しない状態。

```
PS C:\dev\temp\20191209> kubectl get node -L NodeAffinityTest
NAME                                        STATUS   ROLES    AGE   VERSION              NODEAFFINITYTEST
ip-10-0-1-174.us-east-2.compute.internal    Ready    <none>   4d    v1.14.7-eks-1861c5
ip-10-0-54-134.us-east-2.compute.internal   Ready    <none>   4d    v1.14.7-eks-1861c5   False
ip-10-0-91-149.us-east-2.compute.internal   Ready    <none>   4d    v1.14.7-eks-1861c5
PS C:\dev\temp\20191209> kubectl get node -L NodeSelectorTest
NAME                                        STATUS   ROLES    AGE   VERSION              NODESELECTORTEST
ip-10-0-1-174.us-east-2.compute.internal    Ready    <none>   4d    v1.14.7-eks-1861c5   true
ip-10-0-54-134.us-east-2.compute.internal   Ready    <none>   4d    v1.14.7-eks-1861c5
ip-10-0-91-149.us-east-2.compute.internal   Ready    <none>   4d    v1.14.7-eks-1861c5
PS C:\dev\temp\20191209>
```

先ほど同様、両方を指定するDeploymentをデプロイ。

```
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: test
  name: test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test
  strategy: {}
  template:
    metadata:
      labels:
        app: test
    spec:
      containers:
      - image: nginx
        name: nginx
      nodeSelector:
        NodeAffinityTest: "False"
        NodeSelectorTest: "true"
```

`Pending`になる。

```
PS C:\dev\temp\20191209> kubectl get pod -o wide
NAME                    READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
test-64cc7fddf7-ksx8q   0/1     Pending   0          9s    <none>   <none>   <none>           <none>
```

`kubectl describe pod`してみると、条件にマッチするNodeが無いと出力されている。

```
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  21s (x2 over 21s)  default-scheduler  0/3 nodes are available: 3 node(s) didn't match node selector.
```

NodeSelectorは強制力があるが同時に満たせないので、やっぱりスケジューリングできない。

同じような動きだが、**条件にマッチするNodeが無かったら妥協して別のNodeにスケジューリングする**という動きは`NodeAffinity`であれば可能(`preferredDuringSchedulingIgnoredDuringExecution`)のようだ。