k8s での Pod のスケジューリングについて確認した時のメモ(nodeSelector まで)

k8s での Pod のスケジューリングについて確認した時のメモ。
長くなりそうなのでまずは nodeSelector まで
時間があれば続きの内容を書くかもしれないし、書かないかもしれない...

# 概要

+ スケジューリングでは Affinity と Anti-Affinity という考え方を利用する。Affinity では特定条件に一致する所にスケジューリングする。Anti-Affinity では特定の条件に一致しない所にスケジューリングする
+ Pod のスケジューリング方法として大きく分けて以下の5つがある
    + nodeSelecter(Simplest Node Affinity)->簡易的な Node Affinity　**この記事の範囲**
    + Node Affinity->特定のノード上だけで実行する
    + Node Anti-Affinity->特定のノード以外で実行する
    + Inter-Pod Affinity->特定の Pod がいるドメイン(ノード、ゾーン etc)上で実行する
    + Inter-Pod Anti-Affinity->特定の Pod がいないドメイン(ノード、ゾーン etc)上で実行する

# 参考

+ [Kubernetes完全ガイド impress top gearシリーズ](https://www.amazon.co.jp/dp/B07HFS7TDT/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)
+ [EKS Kubernetes Podの配置管理](http://blog.father.gedow.net/2019/10/10/eks-kubernetes-pod-positioning/)

# 検証環境

+ eksctl を利用して作成した k8s 環境を利用
+ `kubectl` は `k` として alias を設定済みの環境
+ 環境情報は以下の通り

```bash
$k version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.5", GitCommit:"20c265fef0741dd71a66480e35bd69f18351daea", GitTreeState:"clean", BuildDate:"2019-10-15T19:16:51Z", GoVersion:"go1.12.10", Compiler:"gc", Platform:"darwin/amd64"}
Server Version: version.Info{Major:"1", Minor:"14+", GitVersion:"v1.14.9-eks-f459c0", GitCommit:"f459c0672169dd35e77af56c24556530a05e9ab1", GitTreeState:"clean", BuildDate:"2020-03-18T04:24:17Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
```


# ラベルについて

Node には **ラベル** を付与することでスケジューリングの際に利用する事が出来る。大きく分けて以下の2種類のラベルがある（ラベルという意味では同じ）

+ ビルトインラベル->利用者が意識せず、自動的に付与されるラベル
+ ラベル->利用者が意図して付与するラベル

## ビルトインラベル

以下にいくつかの例の記載があるが OS や zone などの情報がある。

[補足: ビルトインNodeラベル](https://kubernetes.io/ja/docs/concepts/configuration/assign-pod-node/#%e8%a3%9c%e8%b6%b3-%e3%83%93%e3%83%ab%e3%83%88%e3%82%a4%e3%83%b3node%e3%83%a9%e3%83%99%e3%83%ab)

実際に `eksctl` より作った環境で付与されたラベルを確認してみる。

```bash
$k get nodes -o json|jq ".items[]|.metadata.labels"
{
  "alpha.eksctl.io/cluster-name": "test-cluster",
  "alpha.eksctl.io/instance-id": "i-0b26392bc266a5999",
  "alpha.eksctl.io/nodegroup-name": "standard-workers",
  "beta.kubernetes.io/arch": "amd64",
  "beta.kubernetes.io/instance-type": "t3.medium",
  "beta.kubernetes.io/os": "linux",
  "failure-domain.beta.kubernetes.io/region": "ap-northeast-1",
  "failure-domain.beta.kubernetes.io/zone": "ap-northeast-1c",
  "kubernetes.io/arch": "amd64",
  "kubernetes.io/hostname": "ip-192-168-44-10.ap-northeast-1.compute.internal",
  "kubernetes.io/os": "linux"
}
{
  "alpha.eksctl.io/cluster-name": "test-cluster",
  "alpha.eksctl.io/instance-id": "i-02b72bf1fd5120455",
  "alpha.eksctl.io/nodegroup-name": "standard-workers",
  "beta.kubernetes.io/arch": "amd64",
  "beta.kubernetes.io/instance-type": "t3.medium",
  "beta.kubernetes.io/os": "linux",
  "failure-domain.beta.kubernetes.io/region": "ap-northeast-1",
  "failure-domain.beta.kubernetes.io/zone": "ap-northeast-1d",
  "kubernetes.io/arch": "amd64",
  "kubernetes.io/hostname": "ip-192-168-65-145.ap-northeast-1.compute.internal",
  "kubernetes.io/os": "linux"
}
```

# ラベル

利用者が手動で Node にラベルを付与することも出来る。
具体的には `kubectl label nodes <node-name> <label-key>=<label-value>` という形式で任意のラベルの付与が可能

[ステップ1: Nodeへのラベルの付与](https://kubernetes.io/ja/docs/concepts/configuration/assign-pod-node/#%E3%82%B9%E3%83%86%E3%83%83%E3%83%971-node%E3%81%B8%E3%81%AE%E3%83%A9%E3%83%99%E3%83%AB%E3%81%AE%E4%BB%98%E4%B8%8E)

試しにやってみる。

```bash
# Node 名を確認
$k get nodes
NAME                                                STATUS   ROLES    AGE     VERSION
ip-192-168-44-10.ap-northeast-1.compute.internal    Ready    <none>   7m34s   v1.14.9-eks-1f0ca9
ip-192-168-65-145.ap-northeast-1.compute.internal   Ready    <none>   7m32s   v1.14.9-eks-1f0ca9

# ラベルを付与
$k label nodes ip-192-168-44-10.ap-northeast-1.compute.internal disktype=ssd
node/ip-192-168-44-10.ap-northeast-1.compute.internal labeled

# ラベルが付与された Node のみ表示
$ k get nodes -l disktype=ssd
NAME                                               STATUS   ROLES    AGE   VERSION
ip-192-168-44-10.ap-northeast-1.compute.internal   Ready    <none>   16m   v1.14.9-eks-1f0ca9

```

なお、実際には Node 起動時にラベルを付与したいというユースケースも多いと思う。
その場合、`kubelet` の `--node-labels` で付与出来る(未検証)

>--node-labels mapStringString
>Labels to add when registering the node in the cluster. Labels must be key=value pairs separated by ','. Labels in the 'kubernetes.io' namespace must begin with an allowed prefix (kubelet.kubernetes.io, node.kubernetes.io) or be in the specifically allowed set (beta.kubernetes.io/arch, beta.kubernetes.io/instance-type, beta.kubernetes.io/os, failure-domain.beta.kubernetes.io/region, failure-domain.beta.kubernetes.io/zone, failure-domain.kubernetes.io/region, failure-domain.kubernetes.io/zone, kubernetes.io/arch, kubernetes.io/hostname, kubernetes.io/instance-type, kubernetes.io/os)

# nodeSelecter(Simplest Node Affinity)

以下にも記載があるように最もシンプルならスケジューリングが `nodeSelector` となる。

[nodeSelector](https://kubernetes.io/ja/docs/concepts/configuration/assign-pod-node/#nodeselector)

>nodeSelectorは、Nodeを選択するための、最も簡単で推奨されている手法です。 

先程付与したラベル(disktype = ssd)を利用してこのラベルが付与した Node に Pod　を起動する。
上記を実現するために Pod の YAML では `nodeSelector` を記載する。

```pod-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd
```

```bash
# Pod を起動
$k apply -f pod-nginx.yaml
pod/nginx created

# disktype = ssd をラベルで設定した Node に起動した
$k describe pods |grep Node
Node:         ip-192-168-44-10.ap-northeast-1.compute.internal/192.168.44.10
Node-Selectors:  disktype=ssd
```

想定した Node に Pod を配置する事が出来た