はじめに
この記事では、KubernetesにおけるPodの配置戦略についてまとめています。具体的には以下の4点についてまとめました。
- nodeSelector
- nodeAffinity / nodeAntiAffinity
- podAffinity / podAntiAffinity
- Taints / Tolerations
Version
Kubernetes v1.17.3
Podの配置戦略
Kubernetes上でアプリケーションを稼働させるときに考慮すべきこととして冗長性があります。具体的には複数NodeでKubernetes clusterを構成している場合に、あるNodeに障害が起きた場合でもアプリケーションを停止させないことが重要です。このようなことを実現させるためにはPodをどのNodeに配置するのかが重要になってきます。アプリケーションが実行されているPodを複数起動している場合、各Podを別々のNode上で起動することでNode障害に耐えられるアプリケーションを構築することができます。
KubernetesではPodの配置戦略を設定する方法として、以下の4点が用意されています。
- nodeSelector
- nodeAffinity / nodeAntiAffinity
- podAffinity / podAntiAffinity
- Taints / Tolerations
それぞれについて解説していきます。
nodeSelector
nodeSelectorはその名の通り「Podを配置したいNodeラベル」をキーバリュー形式で指定します。例えばcity: tokyoというラベルのあるNodeへ配置したい場合、以下のような指定をします。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
web: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Always
nodeSelector:
city: tokyo
ちなみにNodeへのラベル付与の仕方は以下の通りです。
$ kubectl label nodes [Node名] city=tokyo
このnodeSelectorはいずれなくなるようです。 理由はこの後に説明するnodeAffinityで代替できるからとのことです。
nodeAffinity / nodeAntiAffinity
nodeAffinityはnodeSelectorよりも柔軟なNode指定ができます。AntiAffinity や、この後に紹介するTaints / Tolerationsと維持する動作も表現可能です。
Node選択する際、「配置する時(DuringScheduling)の必須度合(requiredまたはpreferred)」と「既に配置されて実行されているPod(DuringExecution)の対応(IgnoreまたはRequired)」の組み合わせで4パターンの動作が考えられます。 どのような動作をさせたいかで選択します。
-
requiredDuringSchedulingIgnoredDuringExecution
Pod配置時は必須条件とするが、すでに配置されているPodに対しては無視する。 -
preferredDuringSchedulingIgnoredDuringExecution
Pod配置時にできるだけ配慮して配置する。すでに配置されているPodに対しては無視する。 -
requiredDuringSchedulingRequiredDuringExecution
Pod配置時に必須条件とし、すでに配置されているPodがある場合は退去させる。 Kubernetes v1.17.3時点では利用不可。 今後実装予定の機能。 -
preferredDuringSchedulingRequiredDuringExecution
組み合わせ上は存在するが機能としては存在しない。
例えば以下のような設定を記述することができます。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
web: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: Always
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: country
operator: In
values:
- japan
- america
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: city
operator: In
values:
- tokyo
ここで細かな設定項目について解説します。
matchExpressionsはkey、operator、valuesで構成されます。keyには条件にしたいNodeのラベル名、valuesには値を指定します。operatorに使える演算子は以下の通りです。
演算子 | 意味 |
---|---|
In | keyと一致するラベルの値がvaluesに指定したリスト内に存在するかを指定できる。 |
NotIn | keyと一致するラベルの値がvaluesに指定したリスト内に存在しないかを指定できる。 |
Exists | keyに指定したラベルが存在するかを指定できる。 |
DoesNotExists | keyに指定したラベルが存在しないかを指定できる。 |
preferredDuringSchedulingには上記の条件に加えてweightが1~100の範囲で指定できます。 このweightはNode選択時に利用します。各Nodeにおいてラベルマッチした条件のweightを加算し、最終的に合計weightの高いNodeにPodを配置します。
podAffinity / podAntiAffinity
podAffinityおよびpodAntiAffinityはすでに動いているPodをもとにどこへPodを配置するかを定義するものになります。podAffinityは「指定されたラベルに一致するPodが動作しているNodeがもつtopologyKeyが同一のNodeにPodを配置させる」動作になります。podAntiAffinityは「topologyKey の範囲内に指定されたラベルに一致するPodが動作していなければ、PodをtopologyKey範囲内のNodeのいずれかにPodを配置する」動作になります。
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
containers:
- name: with-pod-affinity
image: k8s.gcr.io/pause:2.0
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S1
topologyKey: failure-domain.beta.kubernetes.io/zone
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: security
operator: In
values:
- S2
topologyKey: failure-domain.beta.kubernetes.io/zone
topologyKeyはNodeのLabelを使った範囲の指定です。topologyKeyで指定されたKeyに対応するValueで一致したものが同一のトポロジーとして扱われます。意図的にすべてのNodeに対して付与しているラベルがないのであれば標準的に付与される以下のようなラベルを利用します。
- kubernetes.io/hostname
- node.kubernetes.io/instance-type
- topology.kubernetes.io/region
- topology.kubernetes.io/zone
- kubernetes.io/arch
- kubernetes.io/os
topology.kubernetes.io/region等はクラウドプロバイダーに依存するラベルとなります。
Taints / Tolerations
Taint / TolerationsはNodeAffinityと逆の機能でNodeへPodをスケジュールさせないための機能です。
Taints
NodeにTaintをつけることでその条件が受け入れられないPodはそのNodeにスケジュールされない。Taintは"kubectl taint"コマンドで追加する。表記については以下の通り。
<Key>=<Value>:<Effect>
KeyとValueについてはLabelと同様に任意の値をつける。Effectについては以下の3つの値を指定できる。
- NoSchedule
このTaintが許容できない場合はそのNodeにスケジュールできない。 - PreferNoSchedule
このTaintが許容できない場合はそのNode以外にスケジュールを試みる。 - NoExecute
このTaintが許容できない場合はそのNode以外にスケジュールされ、実行されているPodも追い出される。
taintは以下のように設定します。
$ kubectl taint node node1 test-taint=hoge:NoSchedule
Tolerations
PodがNodeに設定されているTaintを容認するかを指定する機能です。tolerationにマッチしたTaintを容認し、そのNodeにスケジュールできるようになります。このTolerationはPodの spec.tolerations にリストで指定する。指定するフィールドは以下のものです。
- key
TaintのKeyを指定 - operator
Valueに比較の種類を指定。 EqualとExistsが指定できる。デフォルトはEqual。 - value
TaintのValueを指定。 operatorがExistsの場合、Valueを省略できる。 - effect
TaintのEffectを指定。指定しなかった場合、全てのEffectにマッチする。 - tolerationSeconds
NoExecuteを指定した際、追い出されるまでの時間を秒数で指定する。指定しなかった場合、追い出されないないようになる。0や負の数を指定した場合、即時に追い出される。
tolerationは以下のように設定します。
apiVersion: v1
kind: Pod
metadata:
name: nginx-toleration
spec:
containers:
- name: nginx
image: nginx:alpine
terminationGracePeriodSeconds: 0
tolerations:
- key: test-taint
value: hoge
effect: NoSchedule
これによりtest-taint=hoge:NoScheduleというTaintを容認し、そのNodeでPodが起動できるようになる。