TT Lab
开始
学习 学习路径 课程

KCNA — Kubernetes 与云原生入门

三个节点,Pod 却无处可去

在 TT Lab 中继续学习

目标

亲手设置污点/容忍度、nodeSelector 和 node affinity,观察它们各自如何改变 Pod 的放置位置, 并看到同样是 Pending,原因(容忍不了污点 / 标签不匹配 / 没有符合条件的可用区)可以完全不同。

为什么重要

在 Kubernetes 中,“Pod 运行在哪个节点上”不是偶然,而是调度器的计算结果。 kube-scheduler 会盯着尚未分配节点的 Pod,逐个节点比对污点、标签、资源和 affinity, 选出通过检查的节点并填写 spec.nodeName。如果读不懂这个决定为什么会这样做出, 面对一个 Pending 你就只会来回猜:“是没有资源了吗?”“是节点挂了吗?”

污点是节点在宣告“我不接受随便什么 Pod”,容忍度是 Pod 在回答“这个我能容忍”。 nodeSelector 和 node affinity 则反过来,是 Pod 在提出“我喜欢这样的节点 / 必须是这样的节点”。 两者方向相反,经常同时起作用,所以只看其中一个,无法解释 Pod 的放置结果。

步骤

  1. 创建命名空间 kcna-sched,把节点名称和可用区标签导出到文件。
  2. 给三个节点都加上 tier=reserved:NoSchedule 污点。
  3. 确认没有容忍度的 Pod plain 停在 Pending。
  4. 确认声明了可容忍该污点的容忍度的 Pod tolerant 被分配到节点。
  5. 给 lab-node-0 加上 disktype=ssd 标签,创建一个通过 nodeSelector 只落在该节点上的 Pod。
  6. 创建一个通过 node affinity 只落在 zone-1、zone-2 节点上的 Pod。
  7. 创建一个要求不存在的标签(disktype=nvme)、因而停在 Pending 的 Pod。
  8. 把每个 Pod 的结果以账簿形式记录到 /root/kcna-sched/report.txt。

参考

创建工作命名空间和节点图

创建命名空间 kcna-sched,并把节点名称和每个节点的 topology.kubernetes.io/zone 标签按每行一个、이름=존 的格式(占位符依次为节点名与可用区)保存到 /root/kcna-sched/nodes.txt。

调度器能看到的世界只有节点对象。可以用 kubectl get nodes -L <라벨키>(占位符为标签键)或 -o jsonpath 一并取出名称和可用区标签。命名空间先用 create 加 --dry-run=client 生成再 apply,这样重复运行也是安全的。

给三个节点都加上预留标记

给三个节点都加上 tier=reserved:NoSchedule 污点,让没有容忍度的 Pod 哪里都进不去。

NoSchedule 污点会把没有声明容忍(toleration)该污点的 Pod 挡在节点之外。对三个节点都执行 kubectl taint node <이름> key=value:NoSchedule(占位符为节点名)。即使已经加过,也要能再加一次,所以请附上 --overwrite。

无处可去的 Pod 停在 Pending

在命名空间 kcna-sched 中创建一个完全没有容忍度和选择器的 Pod plain(镜像 nginx:1.27-alpine)。这个 Pod 无法被调度,应该停留在 Pending。

三个节点都被 NoSchedule 污点锁住,所以没有任何容忍度的普通 Pod 无法分配到任何节点。请用 kubectl get pod plain -o wide 和 describe 确认 PodScheduled 条件的 reason。

能容忍预留标记的 Pod 可以进入

在命名空间 kcna-sched 中创建 Pod tolerant(镜像 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 中创建 Pod pinned-ssd(镜像 nginx:1.27-alpine)。这个 Pod 要在容忍预留污点的同时,通过 nodeSelector 只落在 disktype=ssd 的节点上,最终必须被分配到 lab-node-0。

nodeSelector 会把候选节点缩小到带有该标签的节点。污点仍然有效,所以还需要同时加上容忍度。标签只加在一个节点上,nodeSelector 就会把分配结果集中到这一个节点。

用 node affinity 只发往特定可用区

在命名空间 kcna-sched 中创建 Pod zoned(镜像 nginx:1.27-alpine)。在容忍预留污点的同时,用 requiredDuringSchedulingIgnoredDuringExecution node affinity,使它只落在 topology.kubernetes.io/zone 为 zone-1 或 zone-2 的节点上。结果节点必须是 lab-node-1 或 lab-node-2。

node affinity 的表达能力比 nodeSelector 更强。给 In 运算符一个值列表,匹配其中任意一个即可。请根据第 1 步导出的可用区标签,事先确认哪些节点是候选。required 规则在没有匹配节点时会让 Pod 停在 Pending。

没有任何节点能满足的要求

在命名空间 kcna-sched 中创建 Pod nowhere(镜像 nginx:1.27-alpine)。让它容忍预留污点,但通过 nodeSelector 要求 disktype=nvme。没有这样的节点,所以这个 Pod 必须停留在 Pending。

即使有容忍度,只要选择器找不到匹配的节点,Pod 也不会被调度。因容忍不了污点而被挡住,与因标签不匹配而被挡住,原因不同,但症状同样是 Pending。请在 describe 的 Events 中读一读到底缺了什么。

把是什么决定了放置结果记成账簿

把每个 Pod 的结果写成四行,记录到 /root/kcna-sched/report.txt——plain=pending、tolerant=scheduled、pinned-ssd=lab-node-0、nowhere=pending。值必须与集群的实际状态一致(处于 Pending 的 Pod 写 pending,已分配的 Pod 写其节点名)。

评分器会把这个文件的四行与集群的实际状态逐一比对。已分配的 Pod 写 spec.nodeName,处于 Pending 的 Pod 写 pending。不要凭猜测填写,请抄写用 kubectl get pods -n kcna-sched -o wide 确认过的值。