2026年6月30日
2026年6月30日
KubernetesのNodeのtaint・tolerationの設定方法|専用ノードの作り方とPendingの読み方
Kubernetes で「このノードには特定の Pod だけを置きたい」ときは、ノードに taint(汚れ)を付け、そこに置いてよい Pod にだけ toleration(許容)を書きます。taint は Pod を遠ざける仕組み、toleration はその taint を気にしなくてよいという許可です。この記事では、kubectl taint の書き方、3種類の effect の違い、専用ノードを作るときに nodeAffinity と組み合わせる理由、Pod が Pending のままになったときの確認方法までを説明します。
taint と toleration の関係
taint はノード側に付ける「key=value:effect」の組です。taint の付いたノードには、それに合う toleration を持たない Pod はスケジュールされません。
ここで誤解されやすいのが、toleration は「そのノードに行ってよい」という許可にすぎず、「そのノードに行け」という指定ではない点です。GPU ノードに taint を付け、GPU を使う Pod に toleration を書いても、その Pod は taint の無い一般ノードにも普通に配置されます。特定のノードに寄せたい場合は、後で説明する nodeAffinity(または nodeSelector)を併用します。
役割を整理すると次のとおりです。
- taint(ノード側): 合わない Pod を締め出す
- toleration(Pod 側): 特定の taint を無視してよいと宣言する
- nodeAffinity / nodeSelector(Pod 側): 置き場所を特定のノードに絞る
taint を付ける・外す・確認する
taint は kubectl taint で付けます。書式は key=value:effect です。
# GPU 用ノードに taint を付ける
kubectl taint nodes gpu-node-1 dedicated=gpu:NoSchedule
# 付いている taint を確認する
kubectl describe node gpu-node-1 | grep -A3 -i taints
# すべてのノードの taint を一覧で見る
kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
# 外すときは末尾にハイフンを付ける
kubectl taint nodes gpu-node-1 dedicated=gpu:NoSchedule-
外すときの末尾の - を忘れると、同じ taint を付け直そうとしてエラーになります。また、value を省略した dedicated:NoSchedule のような taint も付けられます。
EKS のマネージドノードグループや GKE のノードプールのように、ノードが入れ替わる環境では注意が必要です。kubectl taint で付けた taint はそのノードオブジェクトにしか残らないため、オートスケールやアップグレードで作り直されたノードには付きません。こうした環境では、ノードグループやノードプールの設定として taint を定義してください。設定項目の名前や指定方法はサービスとバージョンによって異なるため、各クラウドのドキュメントで確認します(2026年10月現在)。
3種類の effect の違い
effect は、合わない Pod をどう扱うかを決めます。
| effect | 新しい Pod の配置 | すでに動いている Pod |
|---|---|---|
| NoSchedule | 配置しない | そのまま残る |
| PreferNoSchedule | なるべく避ける(他に置き場が無ければ配置する) | そのまま残る |
| NoExecute | 配置しない | toleration が無ければ追い出す |
最も使うのは NoSchedule です。NoExecute は、すでに動いている Pod まで追い出すので、本番のノードに付けるとその場で Pod が停止します。メンテナンスで Pod を移したい場合は、taint を手で付けるより kubectl drain を使うほうが、PodDisruptionBudget を考慮して順に退避させてくれるので安全です。なお kubectl cordon は内部で node.kubernetes.io/unschedulable:NoSchedule という taint を付けています。
Pod に toleration を書く
toleration は Pod の spec.tolerations に書きます。Deployment であれば spec.template.spec.tolerations です。
apiVersion: apps/v1
kind: Deployment
metadata:
name: gpu-worker
spec:
replicas: 2
selector:
matchLabels:
app: gpu-worker
template:
metadata:
labels:
app: gpu-worker
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
containers:
- name: worker
image: registry.example.com/gpu-worker:1.2.0
operator には次の2つがあります。
- Equal(省略時の既定値): key、value、effect がすべて一致した taint を許容します。
- Exists: key と effect が一致すれば value は問いません。このとき
valueは書きません。
effect を省略すると、その key のすべての effect を許容します。さらに key を省略して operator: Exists だけを書くと、どんな taint でも許容する設定になります。監視エージェントなど全ノードで動かしたいもの以外には使わないでください。コントロールプレーンや専用ノードの保護をすり抜けてしまいます。
専用ノードを作るときは nodeAffinity と組み合わせる
「GPU ノードには GPU の Pod だけ、GPU の Pod は GPU ノードだけ」にしたい場合は、次の2段構えにします。
- ノードに taint を付けて、他の Pod を締め出す
- 同じノードにラベルを付け、GPU の Pod に nodeAffinity を書いて、置き場所を絞る
kubectl label nodes gpu-node-1 dedicated=gpu
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: dedicated
operator: In
values: ["gpu"]
taint だけでは GPU の Pod が一般ノードに流れ、nodeAffinity だけでは一般の Pod が GPU ノードに入り込みます。両方そろえて初めて専用ノードになります。
NoExecute と tolerationSeconds
NoExecute の taint に対しては、tolerationSeconds で「何秒までなら居続けてよいか」を指定できます。
tolerations:
- key: "node.kubernetes.io/unreachable"
operator: "Exists"
effect: "NoExecute"
tolerationSeconds: 60
Kubernetes は、ノードが応答しなくなると node.kubernetes.io/not-ready や node.kubernetes.io/unreachable といった taint を自動で付けます。多くのクラスターでは、Pod にこれらを300秒許容する toleration が自動で追加されるため、ノード障害から5分ほどで Pod が別ノードへ移ります。上の例のように短くすると早く移りますが、ネットワークの一時的な途切れでも Pod が移動するようになるため、短くしすぎないよう注意します。
このほか、メモリやディスクの逼迫時には node.kubernetes.io/memory-pressure、node.kubernetes.io/disk-pressure などの taint が付きます。DaemonSet の Pod には、こうしたノード状態の taint に対する toleration が自動で追加されるため、普通の Deployment とは配置のされ方が異なります。
コントロールプレーンの taint
kubeadm で構築したクラスターでは、コントロールプレーンのノードに node-role.kubernetes.io/control-plane:NoSchedule が付いており、通常のワークロードは置かれません。古い記事では node-role.kubernetes.io/master という名前が出てきますが、現在の版では control-plane に置き換わっています。
検証用の1台構成で、コントロールプレーンにも Pod を置きたい場合は、この taint を外します。
kubectl taint nodes --all node-role.kubernetes.io/control-plane:NoSchedule-
本番のクラスターでは、API サーバーや etcd と負荷を奪い合うため、外さないのが基本です。
Pod が Pending のままのときの確認方法
taint が原因で配置できない Pod は Pending のまま止まります。まずイベントを確認します。
kubectl describe pod gpu-worker-7d9f8c6b5-abcde
Events 欄に、次のような趣旨のメッセージが出ます(文言はバージョンにより少し異なります)。
0/3 nodes are available: 1 node(s) had untolerated taint {dedicated: gpu}, 2 node(s) didn't match Pod's node affinity/selector.
このメッセージは「ノードごとに配置できない理由」を数えたものです。読み方の例です。
- untolerated taint が並ぶ: Pod の toleration の key・value・effect のつづりを、ノードの taint と1文字ずつ照合します。
Equalなのに value が違う、effect を書き間違えている、などがよくある原因です。 - node affinity/selector が並ぶ: nodeAffinity で指定したラベルがノードに付いているかを
kubectl get nodes --show-labelsで確認します。 - 両方が混ざる: taint を許容できるノードと、ラベルが合うノードが別々になっていないかを確かめます。
toleration を直したら Deployment を適用し直し、kubectl get pods -o wide で狙ったノードに配置されたかを確認します。
まとめ
- taint はノードから Pod を締め出し、toleration はその taint を許容する宣言です。toleration だけでは配置先は絞られません。
- 専用ノードは「taint で締め出す」と「ラベル+nodeAffinity で寄せる」の両方で作ります。
- effect は NoSchedule が基本です。NoExecute は動いている Pod も追い出すので、メンテナンスには
kubectl drainを使います。 - マネージドなノードグループでは、
kubectl taintではなくノードグループ側の設定で taint を定義します。 - Pending の原因は
kubectl describe podのイベントで、ノードごとの理由として確認できます。