Taint/Toleration による Pod 配置制御とノードの隔離
- Authors
- Name
- ごとれん
- X
- @ren510dev
目次
- 目次
- はじめに
- Pod のスケジュールを制御する仕組み
- Node Selector
- Node Affinity
- Node Anti-Affinity
- Pod Affinity
- Pod Anti-Affinity
- Taints/Tolerations
- Taints/Tolerations によるノードグループの隔離
- 使用方法
- effect の種類
- メタデータに基づく Pod のスケジュール挙動
- 前提
- マニフェスト
- ノードグループの確認
- 1. affinity + tolerations を付与している場合
- 2. tolerations のみを付与している場合
- 3. affinity のみを付与している場合
- 4. affinity + tolerations のどちらも付与していない場合
- ノードの状態に起因した Pod のスケジュール挙動
- 前提
- 1. taint(占有)ノードが 0 台の場合
- 検証結果
- まとめ

はじめに
Kubernetes には Pod の配置を制御する機能があります。 Pod の配置制御とは、任意の Pod を特定のノードにスケジュールしたり、逆に特定のノードに対して Pod をスケジュールさせないようにコントロールすることです。
最も簡易的な方法として、Node Selector を使用することで任意の Pod を所定のノードにスケジュールすることができます。 また、Node Selector に加え、より細やかな制御が可能な Node Affinity を使用することもできます。
Node Selector および Node Affinity が、ある Pod を特定のノードにスケジュールさせるために使用されるのに対し、Pod をあるノードから遠ざけたい、または特定のノードをワークロードから隔離したいという要件に対しては Taints/Tolerations という機能が用意されています。 Taints と Tolerations は互いに作用しあい、Pod が不適当なノードにスケジュールされるのを防ぎます。
Node Affinity の場合は、未指定の場合、どのノードにでも Pod をスケジュール可能ですが、Taints/Tolerations の場合は、指定しない限りそのノードに Pod がスケジュールされることはありません。
Taints/Tolerations は、例えば Production 用のノードには他の Pod をスケジュールさせたくない場合や、GPU(Graphics Processing Unit) や FPGA(Field Programmable Gate Array) 等の特殊なデバイスを持つノードには特定の Pod 以外をスケジュールさせたくないといった場合に有効です。
今回のブログでは、Taints/Tolerations による Pod の配置制御とノードの隔離策についてまとめたいと思います。
Pod のスケジュールを制御する仕組み

Pod の配置を制御する仕組みとして Kubernetes ネイティブに以下の機能がサポートされています。
機能 | 説明 | 用途と特徴 |
---|---|---|
Node Selector | • 最も簡単なラベルベースのノード選択 • 単純な key=value の一致のみ対応 | シンプルなラベルマッチングに基づいて Pod をスケジューリングする場合に適している。 |
Node Affinity | • Node Selector の拡張版 • 同じくラベルを基準にするが、条件式(例: In, NotIn, Exists)や強度(必須/優先)を指定可能 | 柔軟なルール(優先配置や複数の条件)を必須とする場合に使用する。 |
Node Anti-Affinity | • あるノード上で特定の Pod が動作している場合、他の Pod がそのノードにスケジュールされないように制御 | 特定の Pod が他の Pod と同じノードで動作しないことを保証したい場合や、障害の影響範囲を分散させたい場合に使用する。 |
Pod Affinity | • Pod が他の Pod と近接して配置されるようにスケジューリングを制御 | Pod 間の近接性を制御したい場合に使用する。 |
Pod Anti-Affinity | • 特定の Pod が他の一連の Pod から離れてスケジュールされることを保証 | フェイルオーバと可用性を高めるために重要となる。 例えば、マイクロサービスのインスタンスが同一ノード上に配置されないように、Anti-Affinity を使用して分散させる。 |
Taints/Tolerations | • ノードが特定の Pod を 受諾 / 拒否する仕組み | 特定のノードを隔離する等、専用ノードを作成する場合に使用する。 |
Node Selector
Node Selector は Pod を特定のノードにスケジュールするための最も基本的な方法です。 ノードのラベル(Key-Value 形式)に基づいて Pod を配置するノードを指定します。 もし、クラスタ内に条件を満たすノードが無い(指定されたラベルを持つノードが存在しない)場合、Pod は Pending となり、スケジューリングされることはありません。
Node Affinity
クラスタ内で Pod のスケジューリングを柔軟に制御するためのメカニズムの 1 つであり、ノードに設定された ラベル を基準に配置を制御します。 Node Affinity は、Pod を特定のノードに スケジューリングする際の優先条件を指定するための機能 となっており、特定のノードまたは特定の属性を持つノードに Pod が配置されるように制御することができます。
- ルールの強制度合い
Node Affinity は、ルールの強制度合いによって 2 つのカテゴリに分けられます。
requiredDuringSchedulingIgnoredDuringExecution
- 強制的(必須)のルール
- この条件を満たさないノードには Pod はスケジューリングされない
preferredDuringSchedulingIgnoredDuringExecution
- 任意(優先的)なルール
- この条件を満たすノードがある場合にはスケジューリングするが、条件を満たさない場合でも配置される可能性がある
Node Anti-Affinity
Node Anti-Affinity は Node Affinity の逆で、Pod が特定の条件やルールに基づいて 「一緒に配置されない」ことを保証するための制約 となっています。 主に、ノード間または Pod 間の負荷分散、冗長性の向上を目的 として追加されている機能です。
Pod Affinity
Pod Affinity は、対象となる Pod 同士が近くにスケジュールされる近接性を保証します。 Pod Affinity は、任意の Pod 同士を物理的に近距離に配置することで、効率的な通信を行うことが可能となり、パフォーマンスを向上させることができます。
例えば、ある Pod がすでに特定のノードに配置されていて、その Pod と同じノードに別の Pod を配置したい場合に使用します。
Pod Anti-Affinity
Pod Anti-Affinity は Pod Affinity の逆で、特定の Pod が他の一連の Pod から離れてスケジュールされることを保証します。 これは特定の Pod が互いに障害領域(例:物理的な場所、ネットワーク、電源等)を分離することで、フェイルオーバや可用性を高める際に有効です。
例えば、マイクロサービスのデプロイ先が同一ノード上に集中しないように、Pod Anti-Affinity を使用して分散させることができます。
Taints/Tolerations
Taints は、ノードに特定の条件(ステイン・汚れ)を設定することで 「Pod を受け入れない意図を示す」仕組みであり、Tolerations は Pod がそのステインを許容できることを定義するものです。 これは、特定のノードにのみ Pod を配置したい場合や、逆に特定のワークロードを他のノードから隔離したい場合 に有効です。
Taints/Tolerations によるノードグループの隔離
本題となる Taints/Tolerations の使い方について説明します。
使用方法
Taints/Tolerations では、1 つもしくは複数の taints ラベルをノードに付与し、Pod には 1 つもしくは複数の tolerations 条件を設定します。
taint は "汚れ" という意味で、toleration は "容認" という意味です。 『"汚れ" を "容認" できる場合にはスケジュールするよ』といったニュアンスだと思われます。
- Taints は "ノード" に設定
kubectl taint nodes <node-name> key=value:Effect
Effect
にはNoSchedule
,PreferNoSchedule
,NoExecute
のいずれかを指定
- Tolerations は "Pod" に設定
tolerations: - key: 'key' operator: 'Equal' value: 'value' effect: 'NoSchedule'
$ kubectl describe node master.k8s
Name: master.k8s
Role:
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/hostname=master.k8s
node-role.kubernetes.io/master=
Annotations: node.alpha.kubernetes.io/ttl=0
volumes.kubernetes.io/controller-managed-attach-detach=true
Taints: app=batch:NoSchedule ## これが taint ラベル
この例では、app=batch:NoSchedule
が Taints の設定です。 Taints は <key>=<value>:<effect>
で構成されており、app
が key、batch
が value、NoSchedule
が effect となっています。
effect の種類
effect には、Pod がノードにスケジュールできない場合に、どのように扱うかという挙動を決定するためのパラメータを指定します。
effect には以下の 3 種類があり、Taints/Tolerations の双方で使用します。
- NoSchedule
- taint が許容できなければノードへスケジュールさせない
- すでにスケジュールされている Pod はそのまま
- PreferNoSchedule
- taint が許容できるノードを探し、なければ許容できないノードであってもスケジュールする
- NoExecute
- スケジュール時に影響がある
NoSchedule
やPreferNoSchedule
と違って、NoExecute
はノード上で実行中の Pod へも影響がある - もし
NoExecute
エフェクトをもった taint をノードへ追加した場合で、かつ Pod がその taint を許容できない場合、その Pod は停止(ノードから追い出される)される
- スケジュール時に影響がある
メタデータに基づく Pod のスケジュール挙動
ノードに付与したメタデータに基づく Pod のスケジュール挙動を確認します。
ここでは、主に Pod 配置制御を確認する上で以下の 2 つを検証します。
- Taints/Tolerations により部外 Pod が占有ノードにスケジュールされないこと
- Node Affinity により特定の Pod が占有ノードにスケジュールできること
前提
検証には Amazon EKS を使用し、taint ラベル taint-type=special:NoSchedule
、affinity ラベル type=special-1a
がそれぞれ付与されているノードグループを作成します。
Kubernetes クラスタを構築した後、special-1a
という taint ラベルを持つノードを 2 台起動させます。
マニフェスト
検証には以下のマニフェストを用いる。
./deployment.yaml
対象となる Deployment を定義
apiVersion: apps/v1
kind: Deployment
metadata:
name: tolerations-sample-deployment
namespace: ren510dev
labels:
app: tolerations-sample-deployment
spec:
replicas: 3
selector:
matchLabels:
app: tolerations-sample-pod
template:
metadata:
labels:
app: tolerations-sample-pod
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
resources:
limits:
memory: '512Mi'
cpu: '0.4'
requests:
memory: '256Mi'
cpu: '0.2'
./kustomization.yaml
対象となる Deployment に適用する Kustomize パッチを定義
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ren510dev
resources:
- ./deployment.yaml
patches:
## tolerations をつけることで 占有ノードグループへのスケジュールを許可する
- path: ../../../../kustomize/patches/tolerations/special-only.yaml
target:
group: apps
version: v1
kind: Deployment
name: tolerations-sample-deployment
## node affinity で占有ノードグループを指定してスケジュールする
- path: ../../../../kustomize/patches/nodeaffinity/special-1a.yaml
target:
group: apps
version: v1
kind: Deployment
name: tolerations-sample-deployment
labels:
- pairs:
app.kubernetes.io/env: playground
app.kubernetes.io/owner: cloud-platform
app.kubernetes.io/group: tolerations-sample
includeTemplates: true
../../../../kustomize/patches/tolerations/special-only.yaml
対象の Deployment に適用する Tolerations パッチを定義
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
template:
metadata:
labels:
nodeGroup: special-only
spec:
tolerations:
- key: 'taint-type'
operator: 'Equal'
value: 'special'
effect: 'NoSchedule'
../../../../kustomize/patches/nodeaffinity/special-1a.yaml
対象の Deployment に適用する Affinity パッチを定義
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
template:
metadata:
labels:
nodeAffinityKind: ''
nodeAffinityType: special-1a # Node Affinity Path Type
nodeAffinityName: special-1a # Node Affinity Patch Name
spec:
priorityClassName: ''
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: type
operator: In
values:
- special-1a
ノードグループの確認
EKS の場合、kubectl get node
を実行しても、ノード名を直感的に把握することができないため、以下のようなスクリプトでノード名と taint ラベルを確認することにします。
#!/bin/bash
NODES=$(kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{" "}{end}')
for NODE in $NODES; do
TYPE_LABEL=$(kubectl get node "$NODE" -o jsonpath='{.metadata.labels.type}' 2>/dev/null)
TAINTS=$(kubectl get node "$NODE" -o jsonpath='{range .spec.taints[*]}{.key}{"="}{.value}{":"}{.effect}{"\n"}{end}' 2>/dev/null)
if [ -z "$TYPE_LABEL" ]; then
echo "$NODE => <no type label>"
else
echo "$NODE => $TYPE_LABEL"
fi
if [ -z "$TAINTS" ]; then
echo " Taints: <none>"
else
echo " Taints:"
echo "$TAINTS" | sed 's/^/ /'
fi
done
### 実行結果
ip-10-251-0-183.ap-northeast-1.compute.internal => development
Taints: <none>
ip-10-251-0-99.ap-northeast-1.compute.internal => special-1a
Taints:
taint-type=special:NoSchedule
ip-10-251-1-139.ap-northeast-1.compute.internal => production
Taints: <none>
ip-10-251-1-52.ap-northeast-1.compute.internal => special-1a
Taints:
taint-type=special:NoSchedule
ip-10-251-10-198.ap-northeast-1.compute.internal => private-cpu
Taints: <none>
ip-10-251-2-180.ap-northeast-1.compute.internal => development
Taints: <none>
ip-10-251-2-83.ap-northeast-1.compute.internal => development
Taints: <none>
ip-10-251-4-229.ap-northeast-1.compute.internal => development
Taints: <none>
ip-10-251-5-227.ap-northeast-1.compute.internal => development
Taints: <none>
ip-10-251-6-176.ap-northeast-1.compute.internal => system
Taints: <none>
ip-10-251-8-13.ap-northeast-1.compute.internal => system
Taints: <none>
ここで、以下の 2 ノードが taint ラベルを持っていることが分かります。
ip-10-251-0-99.ap-northeast-1.compute.internal
ip-10-251-1-52.ap-northeast-1.compute.internal
1. affinity + tolerations を付与している場合
まず、Pod が affinity
と tolerations
を持っている状態で確認します。 利便性の観点からこれらは kustomize patch で定義して、ベースマニフェストをオーバーライドする形で使用します。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ren510dev
resources:
- ./deployment.yaml
patches:
## tolerations をつけることで 占有ノードグループへのスケジュールを許可する
- path: ../../../../kustomize/patches/tolerations/special-only.yaml
target:
group: apps
version: v1
kind: Deployment
name: tolerations-sample-deployment
## node affinity で占有ノードグループを指定してスケジュールする
- path: ../../../../kustomize/patches/nodeaffinity/special-1a.yaml
target:
group: apps
version: v1
kind: Deployment
name: tolerations-sample-deployment
labels:
- pairs:
app.kubernetes.io/env: playground
app.kubernetes.io/owner: cloud-platform
app.kubernetes.io/group: tolerations-sample
includeTemplates: true
### 適用
$ kustomize build . --load-restrictor=LoadRestrictionsNone | kubectl apply -f -
### 実行結果
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tolerations-sample-deployment-5f465cc755-gqkr9 1/1 Running 0 40s 10.251.0.112 ip-10-251-0-99.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持つノード
tolerations-sample-deployment-5f465cc755-rzgnb 1/1 Running 0 47s 10.251.0.247 ip-10-251-1-52.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持つノード
tolerations-sample-deployment-5f465cc755-tkp2f 1/1 Running 0 52s 10.251.1.157 ip-10-251-0-99.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持つノード
tolerations
と affinity
の両方のパッチを適用すると、そのワークロードは占有ノードに配置されていることが分かります。 ここで、tolerations
は占有ノードに配置することを許可するために付与しており、affinity
は占有ノードグループのうち、特定のノード(ゾーンタイプ)を指定してスケジュールするために使用しています。
2. tolerations のみを付与している場合
次に、Pod が tolerations のみを持っている場合の挙動を確認します。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ren510dev
resources:
- ./deployment.yaml
patches:
## tolerations をつけることで 占有ノードグループへのスケジュールを許可する
- path: ../../../../kustomize/patches/tolerations/special-only.yaml
target:
group: apps
version: v1
kind: Deployment
name: tolerations-sample-deployment
# ## node affinity で占有ノードグループを指定してスケジュールする
# - path: ../../../../kustomize/patches/nodeaffinity/special-1a.yaml
# target:
# group: apps
# version: v1
# kind: Deployment
# name: tolerations-sample-deployment
labels:
- pairs:
app.kubernetes.io/env: playground
app.kubernetes.io/owner: cloud-platform
app.kubernetes.io/group: tolerations-sample
includeTemplates: true
### 適用
$ kustomize build . --load-restrictor=LoadRestrictionsNone | kubectl apply -f -
### 実行結果
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tolerations-sample-deployment-6cc55cccb7-2z8gs 1/1 Running 0 36s 10.251.1.252 ip-10-251-0-99.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持つノード
tolerations-sample-deployment-6cc55cccb7-p566d 1/1 Running 0 36s 10.251.1.118 ip-10-251-1-52.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持つノード
tolerations-sample-deployment-6cc55cccb7-vkffk 1/1 Running 0 36s 10.251.3.215 ip-10-251-2-83.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持たないノード
Pod はスケジュールされましたが、一つの Pod は占有ノード以外のノードグループに配置されていることが分かります。
つまり、tolerations のみを付与している場合は、その Pod は占有ノードにスケジュールすることができるというだけで、必ずしも占有ノードに配置されることは保証されません。 すなわち、占有ノードにスケジュールさせる場合は affinity を併用する必要があるということが分かります。
3. affinity のみを付与している場合
affinity のみを持っている場合を検証する。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ren510dev
resources:
- ./deployment.yaml
patches:
# ## tolerations をつけることで 占有ノードグループへのスケジュールを許可する
# - path: ../../../../kustomize/patches/tolerations/special-only.yaml
# target:
# group: apps
# version: v1
# kind: Deployment
# name: tolerations-sample-deployment
## node affinity で占有ノードグループを指定してスケジュールする
- path: ../../../../kustomize/patches/nodeaffinity/production.yaml ## production.yaml 等、special 以外の affinity を使用
target:
group: apps
version: v1
kind: Deployment
name: tolerations-sample-deployment
labels:
- pairs:
app.kubernetes.io/env: playground
app.kubernetes.io/owner: cloud-platform
app.kubernetes.io/group: tolerations-sample
includeTemplates: true
### 適用
$ kustomize build . --load-restrictor=LoadRestrictionsNone | kubectl apply -f -
### 実行結果
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tolerations-sample-deployment-54c5755d86-9t5x8 1/1 Running 0 117s 10.251.0.42 ip-10-251-1-139.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持たないノード
tolerations-sample-deployment-54c5755d86-kcfrv 1/1 Running 0 117s 10.251.1.191 ip-10-251-1-139.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持たないノード
tolerations-sample-deployment-54c5755d86-z9hjh 1/1 Running 0 117s 10.251.1.63 ip-10-251-1-139.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持たないノード
Pod は taint ラベルが付与されている占有ノードグループに配置されることはなく、それ以外のノードに配置されています。 今回は affinity として指定している special-only は taint ラベルが付与されているため、この状態では Pod を配置することができず、Pending 状態となります。 試しに affinity として production 等を指定すると、Pod は taint ラベルを持たない他ノードに配置されることが確認できます。
ここで、ip-10-251-1-139.ap-northeast-1.compute.internal
は production を affinity ラベルとして持っています。
4. affinity + tolerations のどちらも付与していない場合
最後に affinity
も tolerations
も設定されていない Pod がどのようにスケジュールされるかを確認します。
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ren510dev
resources:
- ./deployment.yaml
patches:
# ## tolerations をつけることで 占有ノードグループへのスケジュールを許可する
# - path: ../../../../kustomize/patches/tolerations/special-only.yaml
# target:
# group: apps
# version: v1
# kind: Deployment
# name: tolerations-sample-deployment
## node affinity で占有ノードグループを指定してスケジュールする
# - path: ../../../../kustomize/patches/nodeaffinity/special-1a.yaml
# target:
# group: apps
# version: v1
# kind: Deployment
# name: tolerations-sample-deployment
labels:
- pairs:
app.kubernetes.io/env: playground
app.kubernetes.io/owner: cloud-platform
app.kubernetes.io/group: tolerations-sample
includeTemplates: true
### 適用
$ kustomize build . --load-restrictor=LoadRestrictionsNone | kubectl apply -f -
### 実行結果
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tolerations-sample-deployment-77cc49b65-dkm2m 1/1 Running 0 2m21s 10.251.3.87 ip-10-251-2-83.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持たないノード
tolerations-sample-deployment-77cc49b65-fkn7s 1/1 Running 0 2m21s 10.251.1.153 ip-10-251-1-139.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持たないノード
tolerations-sample-deployment-77cc49b65-msn42 1/1 Running 0 2m21s 10.251.4.162 ip-10-251-5-227.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持たないノード
Pod は占有ノード(taint ラベルを持たないノード)以外のノードにスケジュールされることが分かります。
ここで、以下 3 つは何も taint ラベルを持たないノードです。
ip-10-251-2-83.ap-northeast-1.compute.internal
ip-10-251-1-139.ap-northeast-1.compute.internal
ip-10-251-5-227.ap-northeast-1.compute.internal
これは最も基本的なパターンで tolerations ラベルを持たない Pod は taint ラベルを持つ占有ノードに配置されることはなく、affinity ラベルを持たないため特定のノードグループにスケジュールすることも保証されていません。
つまり、kube-scheduler は空いているノードを見つけると、そのノードに Pod を適宜配置するようです。
ノードの状態に起因した Pod のスケジュール挙動
次に、Taint/Tolerations や Affinity を使用する状況下において、ノードがダウンした場合の Pod のスケジュール挙動を確認します。
前提
Pod に所定のラベルを設定した上で、例えばノードに何らかの障害(ストックアウト等)が発生し、1 台も起動しなかった場合の Pod のスケジューリング挙動を確認します。
ここでは、主に Pod 配置制御を確認する上で以下を検証します。
- taint ラベルを付与している対象ノードが 0 台の時の Pod のスケジュール挙動
1. taint(占有)ノードが 0 台の場合
affinity + tolerations の状態において、対象としている taint ノードが 1 台も起動していない場合を検証します。 Pod が taint ノードにスケジュールされたことを確認した上で、cordon を実行して確かめることにします。
まず、対象ノードを確認します。 今回は以下のノードが taint ラベルを持っているため、これらのノードを cordon していきます。
ip-10-251-0-99.ap-northeast-1.compute.internal
ip-10-251-1-52.ap-northeast-1.compute.internal
$ kubectl cordon ip-10-251-0-99.ap-northeast-1.compute.internal
$ kubectl cordon ip-10-251-1-52.ap-northeast-1.compute.internal
$ kubectl get node
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ip-10-251-0-183.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.0.183 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-0-8.ap-northeast-1.compute.internal Ready <none> 19s v1.29.12-eks-aeac579 10.251.0.8 <none> Amazon Linux 2 5.10.230-223.885.amzn2.x86_64 containerd://1.7.23
ip-10-251-0-99.ap-northeast-1.compute.internal Ready,SchedulingDisabled <none> 6h28m v1.29.12-eks-aeac579 10.251.0.99 <none> Amazon Linux 2 5.10.230-223.885.amzn2.x86_64 containerd://1.7.23
ip-10-251-1-139.ap-northeast-1.compute.internal Ready <none> 104d v1.29.8-eks-a737599 10.251.1.139 <none> Amazon Linux 2 5.10.226-214.879.amzn2.x86_64 containerd://1.7.22
ip-10-251-1-52.ap-northeast-1.compute.internal Ready,SchedulingDisabled <none> 6h28m v1.29.12-eks-aeac579 10.251.1.52 <none> Amazon Linux 2 5.10.230-223.885.amzn2.x86_64 containerd://1.7.23
ip-10-251-10-198.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.10.198 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-2-180.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.2.180 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-2-83.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.2.83 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-4-229.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.4.229 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-5-227.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.5.227 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-6-176.ap-northeast-1.compute.internal Ready <none> 104d v1.29.8-eks-a737599 10.251.6.176 <none> Amazon Linux 2 5.10.226-214.879.amzn2.x86_64 containerd://1.7.22
ip-10-251-8-13.ap-northeast-1.compute.internal Ready <none> 104d v1.29.8-eks-a737599 10.251.8.13 <none> Amazon Linux 2 5.10.226-214.879.amzn2.x86_64 containerd://1.7.22
taint ノードが SchedulingDisabled
になったことを確認し、既存の Pod(taint ノードにスケジュールされた Pod)を削除します。
### 実行結果
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tolerations-sample-deployment-5f465cc755-qtjd4 0/1 Pending 0 29s <none> <none> <none> <none>
tolerations-sample-deployment-5f465cc755-r9vzw 0/1 Pending 0 25s <none> <none> <none> <none>
tolerations-sample-deployment-5f465cc755-rfsrh 0/1 Pending 0 23s <none> <none> <none> <none>
この時、Pod は Reconciliation 処理によって再作成されますが、今回の affinitty + tolerations を満たすノードが存在しないため、他のノードに再スケジュールされることはなく Pending 状態に陥りました。
ここで、再度 uncordon してスケジュール可能な状態に戻してみます。
$ kubectl uncordon ip-10-251-0-99.ap-northeast-1.compute.internal
$ kubectl uncordon ip-10-251-1-52.ap-northeast-1.compute.internal
uncordon を実行したら、taint ノードへのスケジュールが有効になっていることを確認します。
$ kubectl get node
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ip-10-251-0-183.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.0.183 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-0-8.ap-northeast-1.compute.internal Ready <none> 2m4s v1.29.12-eks-aeac579 10.251.0.8 <none> Amazon Linux 2 5.10.230-223.885.amzn2.x86_64 containerd://1.7.23
ip-10-251-0-99.ap-northeast-1.compute.internal Ready <none> 6h30m v1.29.12-eks-aeac579 10.251.0.99 <none> Amazon Linux 2 5.10.230-223.885.amzn2.x86_64 containerd://1.7.23
ip-10-251-1-139.ap-northeast-1.compute.internal Ready <none> 104d v1.29.8-eks-a737599 10.251.1.139 <none> Amazon Linux 2 5.10.226-214.879.amzn2.x86_64 containerd://1.7.22
ip-10-251-1-52.ap-northeast-1.compute.internal Ready <none> 6h30m v1.29.12-eks-aeac579 10.251.1.52 <none> Amazon Linux 2 5.10.230-223.885.amzn2.x86_64 containerd://1.7.23
ip-10-251-10-198.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.10.198 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-2-180.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.2.180 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-2-83.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.2.83 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-4-229.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.4.229 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-5-227.ap-northeast-1.compute.internal Ready <none> 40d v1.28.8-eks-ae9a62a 10.251.5.227 <none> Amazon Linux 2 5.10.217-205.860.amzn2.x86_64 containerd://1.7.11
ip-10-251-6-176.ap-northeast-1.compute.internal Ready <none> 104d v1.29.8-eks-a737599 10.251.6.176 <none> Amazon Linux 2 5.10.226-214.879.amzn2.x86_64 containerd://1.7.22
ip-10-251-8-13.ap-northeast-1.compute.internal Ready <none> 104d v1.29.8-eks-a737599 10.251.8.13 <none> Amazon Linux 2 5.10.226-214.879.amzn2.x86_64 containerd://1.7.22
すると、Pending 状態の Pod は占有ノードグループに 自動的に再配置される ことが分かります。
$ kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tolerations-sample-deployment-5f465cc755-4gm2q 1/1 Running 0 5m18s 10.251.1.77 ip-10-251-0-8.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持つノード
tolerations-sample-deployment-5f465cc755-96kkz 1/1 Running 0 5m13s 10.251.0.184 ip-10-251-0-8.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持つノード
tolerations-sample-deployment-5f465cc755-jp75n 1/1 Running 0 5m20s 10.251.0.155 ip-10-251-0-8.ap-northeast-1.compute.internal <none> <none> ## taint ラベルを持つノード
ここで、ip-10-251-0-8.ap-northeast-1.compute.internal
は taint ラベルを持つ占有ノードグループです。
検証結果
検証結果をまとめると以下の通りとなります。
- affinitty:特定の Pod を特定のノードにスケジュールさせるために利用
- tolerations:占有ノードグループに対して特定の Pod をスケジュールさせないために利用
これらを組み合わせることで、特定の Pod のみを占有ノードグループへスケジュールさせるとともに、他の Pod が占有ノードグループへスケジュールされるのを防ぐことができます。
一方で、affinitty + tolerations を満たすノードが存在しない場合に Pod がスケジュールされると、その Pod は Pending 状態に陥ります。
もし、対象の Pod を一時的に占有(taint)ノードグループ以外のノードにスケジュールすることを許容する場合、taint ラベルに effect: PreferNoSchedule
を指定することで実現できます。
しかし、この場合は、再度占有ノードが復帰しても、退避した Pod を自動的に元に戻す術はなく、手動での再作成が(削除後、Reconcilation させる)必要となります。
まとめ
今回は Pod の配置を制御する仕組みとして主に、Node Affinity と Taints/Tolerations を取り上げました。
Node Affinity は Pod を特定のノードにスケジュールする際に有効です。 また、Taints/Tolerations は占有ノードグループを構築した場合に、ノードを隔離して特定の Pod のみを受け入れるように制御することができます。
特に、Taints/Tolerations は開発環境と本番環境が単一のクラスタに集約されており、ノードグループ(GKE の場合はノードプール)単位で分割しているような場合に有効的に利用できると思います。