ノードは3台あるのに、Pod の行き場がない
目標
テイント/トレラレーション、nodeSelector、ノードアフィニティが、Podの配置をそれぞれどう変えるのかを実際に設定して確かめ、同じPendingでも原因(テイントに耐えられない / ラベルが合わない / 合うゾーンがない)が異なることを観察します。
なぜ重要なのか
Kubernetesで「Podがどのノードで動くのか」は偶然ではなく、スケジューラーの計算結果です。kube-schedulerは割り当てられていないPodを見張り、ノードごとにテイント・ラベル・リソース・アフィニティを調べて、通過するノードを選び、spec.nodeNameを埋めます。この判断がなぜそうなったのかを読めないと、Pending1つを前にして「リソースが足りないのか」「ノードが落ちたのか」と迷うことになります。
テイントは、ノードが「私は誰でも受け入れるわけではない」と宣言するもので、トレラレーションは、Podが「私はそれに耐えられる」と答えるものです。nodeSelectorとノードアフィニティは逆に、Podが「私はこういうノードが好ましい/必須だ」と要求するものです。両者は向きが逆なので、同時に設定されることが多く、そのため片方だけを見ても配置を説明できません。
ステップ
- ネームスペース
kcna-schedを作成し、ノード名とゾーンラベルをファイルに取り出してください。 - 3つのノードすべてに
tier=reserved:NoScheduleテイントを設定してください。 - トレラレーションのないPod
plainがPendingで止まることを確認してください。 - テイントに耐えるトレラレーションを与えたPod
tolerantが割り当てられることを確認してください。 lab-node-0にdisktype=ssdラベルを付け、nodeSelectorでそのノードだけに配置されるPodを作成してください。- ノードアフィニティで
zone-1・zone-2のノードだけに配置されるPodを作成してください。 - 存在しないラベル(
disktype=nvme)を要求してPendingで止まるPodを作成してください。 - 各Podの結果を
/root/kcna-sched/report.txtに帳簿として残してください。
参考
kubectl describe pod <이름> -n kcna-schedのEventsとPodScheduled条件のreasonが、「なぜ配置されなかったのか」を教えてくれます(プレースホルダーはPod名です)。- テイントに耐えられずブロックされる場合とセレクターが合わずブロックされる場合は症状が同じなので、describeで原因を見分けてください。
- 公式ドキュメント: テイントとトレラレーション・ノードへのPodの割り当て・kube-scheduler
作業用ネームスペースとノードマップを作成する
ネームスペースkcna-schedを作成し、ノード名と各ノードのtopology.kubernetes.io/zoneラベルを、1行に1つずつ이름=존の形式で(プレースホルダーは名前とゾーンです)/root/kcna-sched/nodes.txtに保存してください。
スケジューラーから見える世界はノードオブジェクトだけです。kubectl get nodes -L <라벨키>または-o jsonpathで、名前とゾーンラベルを一緒に取り出せます(プレースホルダーはラベルのキーです)。ネームスペースはcreateを--dry-run=clientで作ってapplyすれば、何度実行しても安全です。
3つのノードをすべて予約マークでロックする
3つのノードすべてにtier=reserved:NoScheduleテイントを付け、トレラレーションのないPodがどこにも入れないようにしてください。
NoScheduleテイントは、そのテイントに耐える(toleration)と宣言していないPodをノードから遠ざけます。kubectl taint node <이름> key=value:NoScheduleを3つのノードに設定します(プレースホルダーはノード名です)。すでに設定されていても再設定できるように、--overwriteを付けてください。
行き場のないPodがPendingで止まる
ネームスペースkcna-schedに、トレラレーションもセレクターもまったくないPodplain(イメージnginx:1.27-alpine)を作成してください。このPodはスケジュールされず、Pendingのままになるはずです。
3つのノードがすべてNoScheduleテイントでロックされているので、トレラレーションのない普通のPodは、どのノードにも割り当てられません。kubectl get pod plain -o wideとdescribeで、PodScheduled条件のreasonを確認してください。
予約マークに耐えるPodは入れる
ネームスペースkcna-schedにPodtolerant(イメージnginx:1.27-alpine)を作成してください。その際、tier=reservedのNoScheduleテイントに耐えるトレラレーションを宣言し、実際にノードへ割り当てられるようにしてください。
トレラレーションは、key・operator・value・effectでテイントと対応させます。operatorはEqualでvalueを明示するか、Existsでキーだけを合わせられます。割り当てられるとspec.nodeNameが埋まり、kwokがRunningにしてくれます。
SSDのノードにだけ配置する
ノードlab-node-0にラベルdisktype=ssdを付け、ネームスペースkcna-schedにPodpinned-ssd(イメージnginx:1.27-alpine)を作成してください。このPodは予約テイントに耐えつつ、nodeSelectorでdisktype=ssdのノードにだけ配置される必要があり、結果としてlab-node-0に割り当てられなければなりません。
nodeSelectorは、そのラベルを持つノードに候補を絞り込みます。テイントがまだ生きているので、トレラレーションも一緒に必要です。ラベルを1つのノードにだけ付ければ、nodeSelectorがそのノード1つに割り当てを寄せてくれます。
特定のゾーンにだけ送るノードアフィニティ
ネームスペースkcna-schedにPodzoned(イメージnginx:1.27-alpine)を作成してください。予約テイントに耐えつつ、requiredDuringSchedulingIgnoredDuringExecutionのノードアフィニティで、topology.kubernetes.io/zoneがzone-1またはzone-2のノードにだけ配置されるようにしてください。結果のノードはlab-node-1またはlab-node-2でなければなりません。
ノードアフィニティはnodeSelectorより表現力が高いです。In演算子に値のリストを渡すと、そのうちのどれか1つに合えばよくなります。ステップ1で取り出したゾーンラベルを見て、どのノードが候補になるか事前に確認してください。requiredルールは、合うノードがないとPodをPendingのままにします。
どのノードも満たせない要求
ネームスペースkcna-schedにPodnowhere(イメージnginx:1.27-alpine)を作成してください。予約テイントには耐えつつ、nodeSelectorでdisktype=nvmeを要求するようにしてください。そのようなノードはないので、このPodはPendingのままになるはずです。
トレラレーションがあっても、セレクターに合うノードを見つけられなければスケジュールされません。テイントに耐えられずブロックされるのと、ラベルが合わずブロックされるのは原因が違いますが、症状は同じくPendingです。describeのEventsで、何が足りないのかを読んでみてください。
何が配置を決めたのかを帳簿に残す
各Podがどうなったかを、/root/kcna-sched/report.txtに4行で書いてください。plain=pending、tolerant=scheduled、pinned-ssd=lab-node-0、nowhere=pendingです。値は実際のクラスターの状態と一致している必要があります(PendingのPodはpending、割り当てられたPodはそのノード名です)。
採点ツールは、このファイルの4行を実際のクラスターの状態と照合します。割り当てられたPodはspec.nodeNameを、PendingのPodはpendingを書いてください。推測で書かず、kubectl get pods -n kcna-sched -o wideで確認した値を写してください。