【KubernetesのAffinity】その２ - Pod Affinity / Pod Anti-Affinityの使い方

## Affinityとは
Affinityとは、Podをスケジューリングの条件を設定する機能である。
以下の3種類があるが、このページではPod Affinity、Pod Anti-Affinityの２つを説明する。

- Node Affinity
- **Pod Affinity**
- **Pod Anti-Affinity**

Node Affinityについては以下を参照。
[【KubernetesのAffinity】その１ - Node Affinityの使い方](https://qiita.com/Esfahan/items/aeddf89428441ec3437c)

## 目次
- [Kubernetesハンズオン目次](https://qiita.com/Esfahan/items/4fcf51622fed20dffb88)

## Pod Affinity
これは、特定のPodが存在するNodeへ、該当のPodをスケジューリングする方法である。

以下で、pod-aが存在するNodeへ、pod-bをスケジューリングする例をやってみる。

### pod-aを作成

```yaml:pod-a.yml
apiVersion: v1
kind: Pod
metadata:
  name: memcached
  labels:
    app: memcached
spec:
  containers:
  - name: memcached
    image: memcached:alpine
```

作成

```shell-session
$ sudo kubectl apply -f pod-a.yml
pod/memcached created
```

確認

```shell-session
$ sudo kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
memcached   1/1     Running   0          21s
```

### pod-bを作成
`topologyKey`というフィールドがあるが、これはNodeのLabelを使った範囲指定をするためのもの。
以下の`kubernetes.io/hostname`というのは、同じホスト(=ノード)内という意味になる。
podAffinityを利用する場合、このフィールドは必須である。

参考：[topology-key](https://cstoku.dev/posts/2018/k8sdojo-18/#topology-key)

```yaml:pod-b.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-affinity
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
              # metadata.labels.appがmemcachedという名前のPodが存在しているNodeにスケジューリングする
              - memcached
        # 同じホスト(=ノード)内のNodeにスケジューリングする
        topologyKey: kubernetes.io/hostname
  containers:
    - name: nginx
      image: nginx:alpine
```

作成

```shell-session
$ sudo kubectl apply -f pod-b.yml
pod/memcached created
```

確認

```shell-session
$ sudo kubectl get pod
NAME        READY   STATUS    RESTARTS   AGE
memcached   1/1     Running   0          21s
```

```shell-session
$ sudo kubectl describe pod nginx-pod-affinity
# **snip**
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  2s    default-scheduler  Successfully assigned default/nginx-pod-affinity to minikube
  Normal  Pulled     1s    kubelet, minikube  Container image "nginx:alpine" already present on machine
  Normal  Created    1s    kubelet, minikube  Created container nginx
  Normal  Started    1s    kubelet, minikube  Started container nginx
```

## Pod Anti-Affinity
Pod Affinityの逆で、特定のPodが存在していないNodeへスケジューリングをする。
以下の例では、先述のPod Affinityの例で作成した、memcachedのPodが存在しないNodeへのスケジューリング指定をしてみる。
今回は、memcachedが存在しているNodeしか用意していないため、このスケジューリングは失敗する。

```yaml:pod-c.yml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod-anti-affinity
spec:
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - memcached
        topologyKey: kubernetes.io/hostname
  containers:
  - name: nginx
    image: nginx:alpine
```

apply

```shell-session
$ sudo kubectl apply -f pod-c.yml
```

PodがPendingになっている。

```shell-session

$ sudo kubectl get pod
NAME                      READY   STATUS    RESTARTS   AGE
memcached                 1/1     Running   0          38m
nginx-pod-affinity        1/1     Running   0          109s
nginx-pod-anti-affinity   0/1     Pending   0          2s
```

Podがスケジューリング先のNodeを見つけられないため、Warningが出力された。

```shell-session
$ sudo kubectl describe pod nginx-pod-anti-affinity
# **snip**
Events:
  Type     Reason            Age                From               Message
  ----     ------            ----               ----               -------
  Warning  FailedScheduling  24s (x2 over 24s)  default-scheduler  0/1 nodes are available: 1 node(s) didn't match pod affinity/anti-affinity, 1 node(s) didn't match pod anti-affinity rules.
```

## 関連記事
- [KubernetesのTaint / Tolerationの使い方](https://qiita.com/Esfahan/items/843845bdbfefd8ea46d2)
- [KubernetesのLabel / NodeSelector / Annotationの使い方](https://qiita.com/Esfahan/items/a7f7de0a941cc03f12b1)

## 参考
- [Kubernetes道場 18日目 - Affinity / Anti-Affinity / Taint / Tolerationについて](https://cstoku.dev/posts/2018/k8sdojo-18/#pod-affinity-anti-affinity%E3%81%AE%E4%BE%8B)