千家信息网

如何排查K8s Scheduler在调度pod过程中遗漏部分节点的问题

发表于:2025-12-03 作者:千家信息网编辑
千家信息网最后更新 2025年12月03日,本篇内容主要讲解"如何排查K8s Scheduler在调度pod过程中遗漏部分节点的问题",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何排查K8s Sc
千家信息网最后更新 2025年12月03日如何排查K8s Scheduler在调度pod过程中遗漏部分节点的问题

本篇内容主要讲解"如何排查K8s Scheduler在调度pod过程中遗漏部分节点的问题",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"如何排查K8s Scheduler在调度pod过程中遗漏部分节点的问题"吧!

问题现象

在TKE控制台上新建版本为v1.18.4(详细版本号 < v1.18.4-tke.5)的独立集群,其中,集群的节点信息如下:

有3个master node和1个worker node,并且worker 和 master在不同的可用区。

node角色label信息
ss-stg-ma-01masterlabel[failure-domain.beta.kubernetes.io/region=sh,failure-domain.beta.kubernetes.io/zone=200002]
ss-stg-ma-02masterlabel[failure-domain.beta.kubernetes.io/region=sh,failure-domain.beta.kubernetes.io/zone=200002]
ss-stg-ma-03masterlabel[failure-domain.beta.kubernetes.io/region=sh,failure-domain.beta.kubernetes.io/zone=200002]
ss-stg-test-01workerlabel[failure-domain.beta.kubernetes.io/region=sh,failure-domain.beta.kubernetes.io/zone=200004]

待集群创建好之后,再创建出一个daemonset对象,会出现daemonset的某个pod一直卡住pending状态的现象。 现象如下:

$ kubectl  get  pod  -o  wideNAME        READY STATUS  RESTARTS AGE NODE debug-4m8lc 1/1   Running 1        89m  ss-stg-ma-01debug-dn47c 0/1   Pending 0        89m  debug-lkmfs 1/1   Running 1        89m   ss-stg-ma-02debug-qwdbc 1/1   Running 1        89m  ss-stg-test-01

(补充:TKE当前支持的最新版本号为v1.18.4-tke.8,新建集群默认使用最新版本

问题结论

k8s的调度器在调度某个pod时,会从调度器的内部cache中同步一份快照(snapshot),其中保存了pod可以调度的node信息。 上面问题(daemonset的某个pod实例卡在pending状态)的原因就是同步的过程发生了部分node信息丢失,导致了daemonset的部分pod实例无法调度到指定的节点上,卡在了pending状态。

接下来是详细的排查过程。

日志排查

截图中出现的节点信息(来自客户线上集群): k8s master节点:ss-stg-ma-01、ss-stg-ma-02、ss-stg-ma-03 k8s worker节点:ss-stg-test-01

1、获取调度器的日志 这里首先是通过动态调大调度器的日志级别,比如,直接调大到V(10),尝试获取一些相关日志。 当日志级别调大之后,有抓取到一些关键信息,信息如下:

解释一下,当调度某个pod时,有可能会进入到调度器的抢占preempt环节,而上面的日志就是出自于抢占环节。 集群中有4个节点(3个master node和1个worker node),但是日志中只显示了3个节点,缺少了一个master节点。 所以,这里暂时怀疑下是调度器内部缓存cache中少了node info

2、获取调度器内部cache信息 k8s v1.18已经支持打印调度器内部的缓存cache信息。打印出来的调度器内部缓存cache信息如下:

可以看出,调度器的内部缓存cache中的node info是完整的(3个master node和1个worker node)。 通过分析日志,可以得到一个初步结论:调度器内部缓存cache中的node info是完整的,但是当调度pod时,缓存cache中又会缺少部分node信息。

问题根因

在进一步分析之前,我们先一起再熟悉下调度器调度pod的流程(部分展示)和nodeTree数据结构。

pod调度流程(部分展示)

结合上图,一次pod的调度过程就是 一次Scheduler Cycle。 在这个Cycle开始时,第一步就是update snapshot。snapshot我们可以理解为cycle内的cache,其中保存了pod调度时所需的node info,而update snapshot,就是一次nodeTree(调度器内部cache中保存的node信息)到snapshot的同步过程。 而同步过程主要是通过nodeTree.next()函数来实现,函数逻辑如下:

// next returns the name of the next node. NodeTree iterates over zones and in each zone iterates// over nodes in a round robin fashion.func (nt *nodeTree) next() string {        if len(nt.zones) == 0 {                return ""        }        numExhaustedZones := 0        for {                if nt.zoneIndex >= len(nt.zones) {                        nt.zoneIndex = 0                }                zone := nt.zones[nt.zoneIndex]                nt.zoneIndex++                // We do not check the exhausted zones before calling next() on the zone. This ensures                // that if more nodes are added to a zone after it is exhausted, we iterate over the new nodes.                nodeName, exhausted := nt.tree[zone].next()                if exhausted {                        numExhaustedZones++                        if numExhaustedZones >= len(nt.zones) { // all zones are exhausted. we should reset.                                nt.resetExhausted()                        }                } else {                        return nodeName                }        }}

再结合上面排查过程得出的结论,我们可以再进一步缩小问题范围:nodeTree(调度器内部cache)到的同步过程丢失了某个节点信息。

### nodeTree数据结构 (方便理解,本文使用了链表来展示)

在nodeTree数据结构中,有两个游标zoneIndex 和 lastIndex(zone级别),用来控制 nodeTree(调度器内部cache)到snapshot.nodeInfoList的同步过程。并且,重要的一点是:上次同步后的游标值会被记录下来,用于下次同步过程的初始值。

### 重现问题,定位根因

创建k8s集群时,会先加入master node,然后再加入worker node(意思是worker node时间上会晚于master node加入集群的时间)。

第一轮同步:3台master node创建好,然后发生pod调度(比如,cni 插件,以daemonset的方式部署在集群中),会触发一次nodeTree(调度器内部cache)到的同步。同步之后,nodeTree的两个游标就变成了如下结果:

nodeTree.zoneIndex = 1,nodeTree.nodeArray[sh:200002].lastIndex = 3,

第二轮同步:当worker node加入集群中后,然后新建一个daemonset,就会触发第二轮的同步(nodeTree(调度器内部cache)到的同步)。同步过程如下:

1、 zoneIndex=1, nodeArray[sh:200004].lastIndex=0, we get ss-stg-test-01.

2、 zoneIndex=2 >= len(zones); zoneIndex=0, nodeArray[sh:200002].lastIndex=3, return.

3、 zoneIndex=1, nodeArray[sh:200004].lastIndex=1, return.

4、 zoneIndex=0, nodeArray[sh:200002].lastIndex=0, we get ss-stg-ma-01.

5、 zoneIndex=1, nodeArray[sh:200004].lastIndex=0, we get ss-stg-test-01.

6、 zoneIndex=2 >= len(zones); zoneIndex=0, nodeArray[sh:200002].lastIndex=1, we get ss-stg-ma-02.

同步完成之后,调度器的snapshot.nodeInfoList得到如下的结果:

[    ss-stg-test-01,    ss-stg-ma-01,    ss-stg-test-01,    ss-stg-ma-02,]

ss-stg-ma-03 去哪了?在第二轮同步的过程中丢了。

解决方案

问题根因的分析中,可以看出,导致问题发生的原因,在于 nodeTree 数据结构中的游标 zoneIndex 和 lastIndex(zone级别)值被保留了,所以,解决的方案就是在每次同步SYNC时,强制重置游标(归0)。

到此,相信大家对"如何排查K8s Scheduler在调度pod过程中遗漏部分节点的问题"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

调度 同步 过程 信息 节点 问题 集群 日志 部分 就是 缓存 数据 数据结构 游标 版本 级别 结构 状态 现象 结论 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 第三方物流软件开发方案 左创互联网科技 数据库二次开源 魔兽能否关闭语音服务器 手机软件开发开发教程 外包开发公司《软件开发类》 美国 网络安全公司 吉祥航空公司招聘数据库开发信息 深圳友能网络技术有限公司 数据库中关闭窗体 数据库系统 字段 手机软件开发功能需求 易语言怎么链接外部数据库 网络安全与情报信息大队辅警 公司电脑访问不到内部服务器 农产品杂志与大数据库 广州邦聚网络技术有限公司招聘 广东服务器硬盘参数 chrome指定代理服务器 云服务器那家好 软件开发公司有哪些管理模式 软件开发成本核算报告 江西华为鲲鹏服务器供应公司 塔纳利斯并到哪个服务器 国家反诈中心数据库无法更新 军队的网络安全部队 危害网络安全的后果种类 珠海工行软件开发中心实力 魔兽世界电信区哪个服务器好 张莉网络安全教育图片
0