特定のノードに特定のPodのみを配置したいこと、ありますよね。今回はその設定を行ってみました。
今回のルールは、
- GPUノードには指定したAI用Pod以外はスケジューリングさせない
- AI用Podは必ずGPUノードで動かす
の2点です。
結論
TaintsとNode Affinityの両方を設定する必要があります。
まとめると以下のような感じです(イメージはGemini生成)。
| 設定箇所 | 使用する機能 | 役割 | イメージ |
|---|---|---|---|
| Node側 | Taints |
「拒否」 許可証(Toleration)を持たないPodを追い返す。 |
「関係者以外立入禁止」の札 |
| Pod側 | Tolerations |
「通行許可」 Taintされたノードに入るための許可証。 |
入館パス |
| Pod側 | Node Affinity |
「指定」 特定のノードを選んでスケジューリングする。 |
指定席チケット |
なぜTaintsとNode Affinityの両方が必要か
Taints/Tolerationsだけだと
他のPodがノードに配置されることは防ぐことができますが、AI用Podが普通のノードにスケジュールされる可能性があります(Tolerationsは「配置許可」だけで、「強制的に配置する」ではないため)。
Node Affinityだけだと
AI用PodをGPUノードに寄せることはできるが、GPUノードが空いている時に普通のPodがスケジュールされてしまう可能性がある(Affinityは「ほかのPodを配置しない」ルールではない)。
やってみた
では実際にやってみます。
検証環境
- Oracle Kubernetes Engine (OKE) ← 一般的なKubernetesでも変わりません
- Target Node:
10.0.10.130← これをGPUノードと見立てます - Other Node:
10.0.10.77,10.0.10.246 - Taint設定:
workload=ai:NoSchedule
手順
Taintsの設定
まずはGPUノードに関係のないPodが配置されないように、Taintsを設定します。
kubectl taint nodes 10.0.10.130 workload=ai:NoSchedule
この状態で、特別な設定をしていない下記Pod(Deployment)をデプロイしてみます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: other-pods
spec:
replicas: 6
selector:
matchLabels:
app: other-pods
template:
metadata:
labels:
app: other-pods
spec:
containers:
- image: docker.io/nginx
name: nginx
下記のような配置状態になります。
k get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
other-pods-58bc79d994-7xf96 1/1 Running 0 91s 10.0.10.94 10.0.10.246 <none> <none>
other-pods-58bc79d994-j7c78 1/1 Running 0 27s 10.0.10.88 10.0.10.246 <none> <none>
other-pods-58bc79d994-kdh5p 1/1 Running 0 27s 10.0.10.51 10.0.10.77 <none> <none>
other-pods-58bc79d994-ll4sh 1/1 Running 0 91s 10.0.10.91 10.0.10.246 <none> <none>
other-pods-58bc79d994-xbnlp 1/1 Running 0 27s 10.0.10.240 10.0.10.77 <none> <none>
other-pods-58bc79d994-zhc75 1/1 Running 0 91s 10.0.10.233 10.0.10.77 <none> <none>
このように、Taintsが付与されたノードには配置されていないことがわかります。
AI Podの配置(Tolerationのみの場合)
次に、AI用PodにTolerationのみを与えた場合にどのようにスケジューリングされるかをみてみます。
下記のマニフェストファイルを使用してデプロイします。
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-pod
spec:
replicas: 6
selector:
matchLabels:
app: ai-pod
template:
metadata:
labels:
app: ai-pod
spec:
containers:
- image: docker.io/nginx
name: nginx
tolerations:
- key : "workload"
operator: "Equal"
effect: "NoSchedule"
value: "ai"
配置を確認してみます。
k get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ai-pod-795c8dfbc9-8gtnx 1/1 Running 0 8s 10.0.10.90 10.0.10.77 <none> <none>
ai-pod-795c8dfbc9-jd426 1/1 Running 0 8s 10.0.10.37 10.0.10.77 <none> <none>
ai-pod-795c8dfbc9-ksrgt 1/1 Running 0 8s 10.0.10.243 10.0.10.246 <none> <none>
ai-pod-795c8dfbc9-sq6z2 1/1 Running 0 8s 10.0.10.198 10.0.10.130 <none> <none>
ai-pod-795c8dfbc9-tn6bq 1/1 Running 0 8s 10.0.10.184 10.0.10.246 <none> <none>
ai-pod-795c8dfbc9-zwhl9 1/1 Running 0 8s 10.0.10.53 10.0.10.130 <none> <none>
このように、Taintが付与されたノードにも配置できていることがわかります。しかし、GPUノードではないノード(10.0.10.77, 10.0.10.246)にも配置されてしまっています。
Affinityも付与する
最後に、Node Affinityを追加して「必ずこのノードプールを使う」と言う指定を行います。
Affinityで指定するためのラベルをノードにつけます。
k label node 10.0.10.130 pooltype=pool-ai
次に、AI用Podの定義を見直します。以下の2点の記述が必要です。
-
affinity:pooltype=pool-aiラベルを持つノードを必須とする -
tolerations:workload=ai
これをマニフェストファイルにすると以下のようになります。
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-pod
spec:
replicas: 6
selector:
matchLabels:
app: ai-pod
template:
metadata:
labels:
app: ai-pod
spec:
containers:
- image: docker.io/nginx
name: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: pooltype
operator: In
values:
- pool-ai
tolerations:
- key : "workload"
operator: "Equal"
effect: "NoSchedule"
value: "ai"
このPodをデプロイしてみると、下記のような配置になりました。
k get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ai-pod-7fcd767cf9-jl8ln 1/1 Running 0 20s 10.0.10.71 10.0.10.130 <none> <none>
ai-pod-7fcd767cf9-lh6p4 1/1 Running 0 20s 10.0.10.2 10.0.10.130 <none> <none>
ai-pod-7fcd767cf9-nrzvg 1/1 Running 0 20s 10.0.10.142 10.0.10.130 <none> <none>
ai-pod-7fcd767cf9-st8sc 1/1 Running 0 20s 10.0.10.48 10.0.10.130 <none> <none>
ai-pod-7fcd767cf9-wc2dq 1/1 Running 0 20s 10.0.10.49 10.0.10.130 <none> <none>
ai-pod-7fcd767cf9-zg8mv 1/1 Running 0 20s 10.0.10.95 10.0.10.130 <none> <none>
このように、すべてのPodがGPUノード(10.0.10.130)に配置されていることがわかります。
まとめ
Kubernetesで特定のワークロードを完全に隔離したい場合は、
- ノード側: Taintで関係ないノードが配置されないようにして、ラベルで目的のPodが配置できるようにする
- Pod側: TolerationでTaintを通過し、nodeAffinityでラベルの場所を指定する
が必要なことがわかりました。