minikubeでnodeSelectorやnodeAffinityを試してみる


minikubeはマルチノードにも対応してるというので試してみたいと思います。

## 前提

* mac
* minikubeがインストールされている（DriverはDocker）


## 標準状態（シングルノード）での動作確認

まずはシングルノードでの動作（挙動）を確認してみます。

```bash
kubectl get nodes

NAME       STATUS   ROLES           AGE     VERSION
minikube   Ready    control-plane   5m21s   v1.25.3
```

minikubeというノードが１つ動いている。Roleがcontrol-planeになっているがワーカーノードも兼務？してるみたい。
というのは、下記のようにnginxを普通にデプロイしてみて、

```bash
kubectl create deployment my-www --image=nginx
kubectl expose deployment my-www --type=NodePort --port=80
minikube service my-www
```

podの名前を確認し、

```bash
kubectl get pods
my-www-567df47dd7-b4jbh   1/1     Running   0          10m
```

詳細を確認してみると、nodeとしてはcontrol-planeと同じminikubeで動いている（特にnodeとかかが追加されない）。

```bash
kubectl describe pod my-www-567df47dd7-b4jbh

ame:             my-www-567df47dd7-b4jbh
Namespace:        default
Priority:         0
Service Account:  default
Node:             minikube/192.168.49.2
Start Time:       Fri, 11 Nov 2022 06:13:47 +0900
Labels:           app=my-www
                  pod-template-hash=567df47dd7
Annotations:      <none>
Status:           Running
（以下、省略）
```

そこで、

```bash
kubectl describe node minikube
```

としてみると、下記のような感じでNamespaceで区別され実行されているみたいです。

```bash
（抜粋）

Non-terminated Pods:          (8 in total)
  Namespace                   Name                                
  ---------                   ----                                
  default                     my-www-567df47dd7-b4jbh             
  kube-system                 coredns-565d847f94-7rb2x            
  kube-system                 etcd-minikube                       
  kube-system                 kube-apiserver-minikube             
  kube-system                 kube-controller-manager-minikube    
  kube-system                 kube-proxy-7blwf                   
  kube-system                 kube-scheduler-minikube             
  kube-system                 storage-provisioner
  
（抜粋）            
```

## マルチノード化


標準ではシングルノードで動いているのをマルチノード化するためには以下の２つの方法があるようです。

### start時に--nodes 3とかする

start時に以下のようにすることも可能ですが、既にクラスタが生成されている場合はaddしろ！と怒られるようです。

>minikube deleteしてから再度minikube startすればOKです。

```bash
minikube start --nodes 2
```

### node add --workerとかする

既にクラスタがある場合とかはaddも利用できるようです。

>但し、私の環境では追加したnodeでCNIか有効化できず、nodeへの通信ができませんでした（調査中）。

```bash
minikube node add --worker
```

### マルチノード化（今回）

今回はminikube start時にnode数を指定する方法でマルチノード化しました。

```bash
minikube delete #必要なら
minikube start --nodes 2
```

### 動作確認

minikube-m02というのが追加されています。

```bash
kubectl get nodes

minikube       Ready    control-plane   26m   v1.25.3
minikube-m02   Ready    <none>          21s   v1.25.3
```

### ラベルの確認

nodeSelectorやAffinityはラベル情報を利用するので、確認します。

```bash
kubectl get nodes --show-labels
```

ラベルは、以下のようにして追加できるようです。

```bash
kubectl label node minikube-m02 disktype=ssd
```

>ラベルの削除はkubectl label node minikube-m02 disktype- とするみたい。

## nodeSelector, Affinityの確認（Podを指定のNodeで動かす）

### 準備（掃除）

```bash
kubectl delete service my-www
kubectl delete deployment my-www
```

### nodeSelector

Affinityで代用できるので最近はあまり使わないのかな？

#### Yamlの記述

以下のようにYamlを記述しました。

```yaml:my-www-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-www
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-www
  template:
    metadata:
      labels:
        app: my-www
    spec:
      containers:
      - name: my-www
        image: nginx
        ports:
        - containerPort: 80
      nodeSelector:
        kubernetes.io/hostname: minikube-m02
```

#### Yamlの適用

```bash
kubectl apply -f my-www-deployment.yaml
```

#### どこのnodeで動いてるか確認

describeで確認します。minikube-m02で動いているようです。

```bash
kubectl describe pod my-www-deployment-68696dc6b7-7g9lr

Name:             my-www-deployment-68696dc6b7-7g9lr
Namespace:        default
Priority:         0
Service Account:  default
Node:             minikube-m02/192.168.49.3
Start Time:       Fri, 11 Nov 2022 07:00:41 +0900
Labels:           app=my-www
                  pod-template-hash=68696dc6b7
Annotations:      <none>
Status:           Running
IP:               172.17.0.2
（以下省略）
```

以下のコマンドでもOK

```bash
kubectl get pods -A -o wide
```

#### 動作確認


Podの配置が目的なので動作確認は不要ですが、一応。
DeploymentをYamlで設定したので、ServiceもYamlで書いてみます。


```yaml:my-www-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-www
spec:
  ports:
  - port: 80
  selector:
    app: my-www
  type: NodePort
```

適用と動作確認。

```bash
kubectl apply -f my-www-service.yaml
minikube service my-www
```

### nodeAffinity

#### Yamlの編集


```yaml:my-www-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-www
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-www
  template:
    metadata:
      labels:
        app: my-www
    spec:
      containers:
      - name: my-www
        image: nginx
        ports:
        - containerPort: 80
      # nodeSelector:
      #   kubernetes.io/hostname: minikube-m02
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/hostname
                operator: In
                values:
                - "minikube-m02"
```

#### Yamlの適用

```bash
kubectl apply -f my-www-deployment.yaml
```

#### 動作確認

nodeSelectorと同じなので割愛。

#### 解説（最低限）

nodeAffinityには以下の２種類がある。

* requiredDuringSchedulingIgnoredDuringExecution
* preferredDuringSchedulingIgnoredDuringExecution

前者は指定したnodeで動かす（nodeSelectorと同じようなもの）。後者は指定したnode優先だが、NGなら他のnodeでもよい。

条件指定には、以下がある。

* matchExpressions
* matchFields

前者はLabelに対する条件指定で、後者はオブジェクトフィールドに対する条件指定らしい。

operatorにはIn Not Inとかもあるし、Anti AffinityとかTaintsとかいろいろあるけど、あまり使わないのでとりあえずこの記事ではここまで。[詳細は本家のドキュメント](https://kubernetes.io/ja/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/)などを参照。

## 参考

ありがとうございます。

* https://qiita.com/PoodleMaster/items/9fd00de31f037acb7b76
* https://kubernetes.io/ja/docs/tasks/configure-pod-container/assign-pods-nodes-using-node-affinity/
* https://cstoku.dev/posts/2018/k8sdojo-18/