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段構えにします。

  1. ノードに taint を付けて、他の Pod を締め出す
  2. 同じノードにラベルを付け、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 のイベントで、ノードごとの理由として確認できます。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲