bigywater.tech
Kubernetes · 47

nodeSelector 与节点标签:调度不上的原因怎么看

Pod 一直 Pending,0/5 nodes are available 后面那一串到底在说什么?nodeSelector 写错了会怎样?nodeName 是怎么回事?这篇用故意调度不上的 Pod 把 scheduler 的各类淘汰原因都打出来,并验证标签后加、标签后删、nodeName 绕过调度器这几件事。

0.2 秒
给节点打上 Pending Pod 需要的标签之后,Pod 被调度的耗时
OutOfcpu
nodeName 指向放不下的节点时,Pod 的失败原因(由 kubelet 而不是调度器给出)
5 = 1 + 1 + 3
Pending message 里各类淘汰原因的节点数加起来等于节点总数 5

默认标签

实测 · 本机执行输出
  worker 的标签(5 个):
    beta.kubernetes.io/arch=arm64
    beta.kubernetes.io/os=linux
    kubernetes.io/arch=arm64
    kubernetes.io/hostname=kx-sched-worker
    kubernetes.io/os=linux
  控制面比 worker 多的标签:['node-role.kubernetes.io/control-plane', 'node.kubernetes.io/exclude-from-external-load-balancers']

worker 节点只有 5 个标签:kubernetes.io/hostname、kubernetes.io/arch、kubernetes.io/os 以及两个 beta.kubernetes.io/… 的老名字;控制面多 node-role.kubernetes.io/control-plane 和 exclude-from-external-load-balancers。其他的(磁盘类型、GPU、可用区)都得自己 kubectl label 或由云厂商、插件打上。

nodeSelector

实测 · 本机执行输出
  on-ssd      nodeSelector disk=ssd(worker2、worker3 有):worker3
  on-ssd-gpu  nodeSelector disk=ssd 且 gpu=yes(只有 worker3 同时有):worker3
  on-nvme     nodeSelector disk=nvme(没有任何节点有):(未调度);0/5 nodes are available: 1 node(s) had untolerated taint(s), 4 node(s) didn't match Pod's node affinity/selector. preemption: 0/5 nodes are available: 5 Preemption is not
  给 worker 打上 disk=nvme 之后:on-nvme 在 0.2 秒内被调度到 worker(调度器监听节点变化,不用重建 Pod)
  把 worker3 的 disk 改成 hdd 之后:已经调度的 on-ssd 在 worker3(标签变了也不会被赶走)

标签 disk=ssd(worker2、worker3)、gpu=yes(worker3)。nodeSelector: {disk: ssd} 调度到 worker3;{disk: ssd, gpu: "yes"}(多个键 AND)也到 worker3;disk: nvme 没有节点有,Pod 保持 Pending。给 worker 打上 disk=nvme 之后 0.2 秒就被调度过去,不需要重建 Pod——调度器监听节点变化。反过来,把 worker3 的 disk 改成 hdd,已经调度的 Pod 不会被赶走。

nodeName 绕过调度器

实测 · 本机执行输出
  nodeName 直接指定:worker;phase=Running;事件里有 Scheduled 吗:False(没有经过调度器)
  nodeName 指向已经 cordon 的节点:worker;phase=Running
  nodeSelector 指向已经 cordon 的节点:(未调度);phase=Pending;0/5 nodes are available: 1 node(s) had untolerated taint(s), 1 node(s) were unschedulable, 3 node(s) didn't match Pod's node affinity/selector. preemption: 0/5 nodes are 
  nodeName 指向的节点放不下(请求 100 核):phase=Failed;reason=OutOfcpu;message=Pod was rejected: Node didn't have enough resource: cpu, requested: 100000, used: 100, capacity: 10000

直接写 nodeName 的 Pod 不经过调度器(事件里没有 Scheduled):指向已 cordon 的节点照样 Running,而 nodeSelector 指向它就 Pending(1 node(s) were unschedulable)。指向的节点放不下时没人替你挑别的节点,kubelet 直接拒绝:phase=Failed、reason=OutOfcpu、Pod was rejected: Node didn't have enough resource: cpu, requested: 100000, used: 100, capacity: 10000(单位是毫核)。想固定节点用 nodeSelector 加 kubernetes.io/hostname。

怎么读 Pending 的原因

实测 · 本机执行输出
  need-label nodeSelector: {no-such: label}                                 → 0/5 nodes are available: 1 node(s) had untolerated taint(s), 1 node(s) were unschedulable, 3 node(s) didn't match Pod's node affinity/selector. preemp
  need-cpu   resources: {requests: {cpu: "100"}}                            → 0/5 nodes are available: 1 node(s) had untolerated taint(s), 1 node(s) were unschedulable, 3 Insufficient cpu. preemption: 0/5 nodes are available: 5 
  need-mem   resources: {requests: {memory: 1000Gi}}                        → 0/5 nodes are available: 1 node(s) had untolerated taint(s), 1 node(s) were unschedulable, 3 Insufficient memory. preemption: 0/5 nodes are available:
  need-eph   resources: {requests: {ephemeral-storage: 1000Gi}}             → 0/5 nodes are available: 1 node(s) had untolerated taint(s), 1 node(s) were unschedulable, 3 Insufficient ephemeral-storage. preemption: 0/5 nodes are
  on-cordon  nodeSelector: {kubernetes.io/hostname: kx-sched-worker4}       → 0/5 nodes are available: 1 node(s) had untolerated taint(s), 1 node(s) were unschedulable, 3 node(s) didn't match Pod's node affinity/selector. preemp
  need-cp    nodeSelector: {node-role.kubernetes.io/control-plane: ""}      → 0/5 nodes are available: 1 node(s) had untolerated taint(s), 1 node(s) were unschedulable, 3 node(s) didn't match Pod's node affinity/selector. preemp

message 是 0/5 nodes are available: 1 node(s) had untolerated taint(s), 1 node(s) were unschedulable, 3 …,最后一项因 Pod 而异:标签不匹配是 didn't match Pod's node affinity/selector,资源不足是 Insufficient cpu、Insufficient memory 或 Insufficient ephemeral-storage。每个节点只被计入第一个淘汰它的过滤器,所以各项加起来正好是 5(这里 worker4 被 cordon,控制面有污点,三个正常 worker 才轮到具体原因)。

分步演示

节点标签与调度
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。独立的 5 节点 kind 集群 kx-sched(1 控制面 + 4 个 worker,Kubernetes v1.37.0,与前几篇共用),标签、cordon 都在实验后还原;Pod 是 busybox:1.36;“被调度的耗时”由 0.1 秒间隔轮询 spec.nodeName 得到;第 4 节为了让各行有一个共同的“unschedulable”项,先 cordon 了 worker4,所以 on-cordon 一行与其他行的 message 前半段相同;每种情形各一次
    • 没有验证:节点标签的限制(受限前缀 node-restriction.kubernetes.io/ 与 NodeRestriction 准入);nodeSelector 与 nodeAffinity 同时存在时的合并(两者都要满足);云厂商自动打的 topology.kubernetes.io/zone 等标签;Pod 因 PVC 绑定到特定节点而 Pending 的 message(volume node affinity conflict);调度器的 percentageOfNodesToScore 对大集群的影响
    京ICP备2026067502号-1京公网安备11010502063487号