Appearance
把 Pending 拆成队列、过滤与绑定
调度队列给有待放置的 Pod 排序;Filter 找能承载它的节点,Score 对可行节点打分,Reserve 为调度周期保存插件状态,Permit 可等待组调度条件,Bind 才把 Pod 关联到节点。失败时可以 Unreserve、重新入队并退避。Reserve 不是给外部业务平台发放持久锁。CPU/Memory requests 用于放置;limits 用于运行时限制。QoS 分类影响驱逐优先序,但 Guaranteed 不是“永远不会被驱逐”。
例如两台机器各剩两张卡,待部署 Pod 需三张,即使总数为四也没有合法节点。best fit 倾向把小作业塞到剩余最少且可容纳的节点,为大作业留下连续容量;spread 降低单点故障集中度,两者优化目标不同。nodeSelector 和 required affinity 是硬约束,preferred affinity 是偏好。toleration 解除 taint 的阻挡,不代表一定调到该节点。PriorityClass 可以触发低优先级受害者评估,驱逐无法解决硬件类型或标签不匹配。
传统 Device Plugin 向 kubelet 公告整数扩展资源,例如 nvidia.com/gpu;scheduler 依据 allocatable/requests 选节点,具体设备由节点侧分配。DRA 通过 ResourceClaim、设备类和驱动分配描述更丰富的设备约束,并非给现有 Pod 自动加上物理 GPU。Mac 上的 SQL gpu_pool 是账本,不能据此向容器注入 CUDA 设备。参考 Scheduling Framework、Device Plugin。
实验:先看 PodScheduled condition,再看同 UID 的 FailedScheduling Events,最后核对节点标签和 allocatable。若根本未绑定节点就去查应用日志,往往没有容器可查。实际案例。
一次运行,得到三种不同证据
只在专用 Kind 上执行。脚本生成唯一 namespace;同一个镜像,第一份要求不存在的 hostname,第二份请求 100000 核,第三份要求真实节点和 10m CPU。最后创建最多 3 个 Pod 的配额再申请第 4 个。退出时脚本删除自己的 namespace。
sh
export KUBECONFIG="$PWD/tmp/handbook.kubeconfig"
./labs/kube/scheduler.sh完整源码:labs/kube/scheduler.sh · 第 18–35 行
sh
spec:
restartPolicy: Never
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: kubernetes.io/hostname, operator: In, values: ["$2"]}
containers:
- name: runtime
image: modeldock-cpu:lab
imagePullPolicy: IfNotPresent
resources: {requests: {cpu: "$3", memory: 16Mi}}
YAML
}
pod wrong-label no-such-study-host 10m
pod too-large "$node" 100000
pod fits "$node" 10m实测:前两份的 PodScheduled=False;Events 分别指向 affinity/selector 与 Insufficient cpu。第三份成功绑定,第四份在 API 创建时返回 Forbidden/exceeded quota,连待调度 Pod 都没有。按 Scheduling Framework 对照:队列退避控制重试节奏;只有通过 Filter 的节点参加 Score;Reserve/Unreserve 为插件状态服务,Permit 可延迟绑定。失败在 Filter 时调高偏好分数不会增加候选节点。
改一个条件,预测结果
把 required 改成 preferred 时需要改 YAML 结构(preferred 项使用 weight 和 preference),原先硬性排除才变成可选;若同时要求不存在的 GPU,仍然无候选。Pod affinity 用其他 Pod 的标签和 topologyKey 表达共置;反亲和可减少故障域集中,但减少可放置位置。toleration 只允许进入带污点节点,不会吸引 Pod。
在独立实验集群试 PriorityClass:kubectl create priorityclass study-high --value=1000 --preemption-policy=Never,在 Pod 的 spec 指定 priorityClassName。它能提高待处理优先级,但禁止主动抢占。即便允许抢占也不能改变不存在的节点标签。用完删实验 Pod 后 kubectl delete priorityclass study-high。这一扩展与前面的实测脚本分开。
追问。 两个节点各剩 2 卡,为何放不下要 3 卡的 Pod?调度以单 Pod 的单节点可满足性过滤,总量相加没有意义。对比SQL best fit:账本决定谁有预算,kubelet 的设备插件才负责实际设备。
替换一个约束,预言事件会怎样变
设租户有预算,节点有 GPU,但模型要求的节点标签不存在。抢占其他 Pod 能腾出可计量资源,不能让未匹配的节点获得那个标签。先运行本章脚本,对照 wrong-label 和 too-large 的 FailedScheduling 原文。若二者在你的报告里都只显示“资源不足”,告警已经丢掉了决定修复方案的信息。在 OpsPilot 中保留事件原文与目标模板,正是为了让模型不要因看到 Pending 就建议同一个动作。