K8s 自定义调度器导致 Pod 调度失效排查
2026-08-11 00:53:03 # Kubernetes

业务 Pod 指定了自研调度器后,在高峰期扩容时必现 Pending,提示资源不足,但监控显示资源充裕;一旦切回默认调度器立刻恢复正常。这种”只有特定 Pod 出问题、且换调度器就好”的现象,指向自定义调度器自身的逻辑缺陷。

问题现象与背景原因

典型现象:指定了自定义调度器的业务 Pod 卡在 Pending。

1
2
3
kubectl get pod biz-app
NAME READY STATUS RESTARTS AGE
biz-app-7d9 0/1 Pending 0 3m

核心原因:自定义调度器存在缓存与 etcd 数据不一致的 BUG

  • 业务 Pod 通过 spec.schedulerName 指定了自研调度器。
  • 自研调度器的评分插件(如 NodeAffinityPriority)读取了过期缓存,认为节点不满足亲和性,直接打 0 分,于是所有节点”都不合格” → Pending。
  • 因为事件去重机制,这种”打分逻辑错误”不会在 Events 里留下明显异常日志,只表现为 Pending,极难发现。

提示:只有”指定了自定义调度器”的 Pod 出问题、且切换回默认调度器立刻正常——这是自定义调度器故障的强特征。

排查过程(思路与定位方法)

第一步:确认 Pod 用的是哪个调度器。

1
2
kubectl get pod biz-app -o jsonpath='{.spec.schedulerName}'
# 输出非 default-scheduler 即自定义调度器

第二步:启用调度器详细追踪,看它到底怎么给节点打分。

1
2
3
4
5
# 修改自定义调度器部署,提高日志级别
kubectl edit deployment <custom-scheduler> -n kube-system
# 给启动参数加:--v=6 (甚至 --v=8 看打分细节)
kubectl rollout restart deployment <custom-scheduler> -n kube-system
kubectl logs -n kube-system deployment/<custom-scheduler> --tail=200 -f

关注日志里对每个节点的 scorefeasible 判断,看是否出现”本应合格却被打 0 分”。

第三步:对比 etcd 真实状态与调度器缓存。

1
2
3
4
# 看节点真实标签 / 资源
kubectl get nodes --show-labels
kubectl describe node <node> | sed -n '/Allocated resources/,/Events/p'
# 把以上与调度器日志里"它以为的节点状态"对比,不一致即缓存陈旧

第四步:验证”切换回默认调度器能否立刻调度”。(运行中 Pod 的 schedulerName 不可变,需用新 Pod 或改模板后重建来验证。)

最终的解决方法

  • 修复逻辑漏洞:检查评分插件读取缓存的刷新机制,确保节点状态变更(标签 / 污点 / 资源)及时失效缓存。
  • 增加兜底策略:当自定义调度器打分全为 0 时,fallback 到默认调度逻辑,避免整批 Pending。
  • 开启调度失败可观测性:关闭事件去重或单独打点,让”所有节点 0 分”这种异常能被告警捕获。
  • 关键教训:性能优化(用缓存提速)不能牺牲逻辑严谨性;缓存一致性必须兜底。

长期:为自定义调度器补单元测试 + 集成测试,覆盖”节点状态变更后缓存刷新”场景;并为调度失败配置监控(如 Pending 队列长度、调度时延)。

操作命令(可直接复制执行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 看 Pod 用的调度器
kubectl get pod <pod> -o jsonpath='{.spec.schedulerName}'

# 2. 调高自定义调度器日志级别
kubectl edit deployment <custom-scheduler> -n kube-system # 加 --v=6
kubectl rollout restart deployment <custom-scheduler> -n kube-system

# 3. 看调度器打分日志
kubectl logs -n kube-system deployment/<custom-scheduler> --tail=200 | grep -iE 'score|feasible|filter'

# 4. 对比节点真实状态
kubectl get nodes --show-labels
kubectl describe node <node> | sed -n '/Allocated resources/,/Events/p'

# 5. 验证:用默认调度器起一个测试 Pod 看能否调度
kubectl run test-default --image=<img> --dry-run=server -o yaml > /tmp/t.yaml
# 编辑 /tmp/t.yaml 确保 schedulerName: default-scheduler 后 apply 验证