您好,登錄后才能下訂單哦!
本篇內容主要講解“如何排查K8s Scheduler在調度pod過程中遺漏部分節(jié)點的問題”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何排查K8s Scheduler在調度pod過程中遺漏部分節(jié)點的問題”吧!
在TKE控制臺上新建版本為v1.18.4(詳細版本號 < v1.18.4-tke.5)的獨立集群,其中,集群的節(jié)點信息如下:
有3個master node和1個worker node,并且worker 和 master在不同的可用區(qū)。
node | 角色 | label信息 |
---|---|---|
ss-stg-ma-01 | master | label[failure-domain.beta.kubernetes.io/region=sh,failure-domain.beta.kubernetes.io/zone=200002] |
ss-stg-ma-02 | master | label[failure-domain.beta.kubernetes.io/region=sh,failure-domain.beta.kubernetes.io/zone=200002] |
ss-stg-ma-03 | master | label[failure-domain.beta.kubernetes.io/region=sh,failure-domain.beta.kubernetes.io/zone=200002] |
ss-stg-test-01 | worker | label[failure-domain.beta.kubernetes.io/region=sh,failure-domain.beta.kubernetes.io/zone=200004] |
待集群創(chuàng)建好之后,再創(chuàng)建出一個daemonset對象,會出現(xiàn)daemonset的某個pod一直卡住pending狀態(tài)的現(xiàn)象。 現(xiàn)象如下:
$ kubectl get pod -o wide NAME READY STATUS RESTARTS AGE NODE debug-4m8lc 1/1 Running 1 89m ss-stg-ma-01 debug-dn47c 0/1 Pending 0 89m <none> debug-lkmfs 1/1 Running 1 89m ss-stg-ma-02 debug-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狀態(tài))的原因就是同步的過程發(fā)生了部分node信息丟失,導致了daemonset的部分pod實例無法調度到指定的節(jié)點上,卡在了pending狀態(tài)。
接下來是詳細的排查過程。
截圖中出現(xiàn)的節(jié)點信息(來自客戶線上集群): k8s master節(jié)點:ss-stg-ma-01、ss-stg-ma-02、ss-stg-ma-03 k8s worker節(jié)點:ss-stg-test-01
1、獲取調度器的日志 這里首先是通過動態(tài)調大調度器的日志級別,比如,直接調大到V(10)
,嘗試獲取一些相關日志。 當日志級別調大之后,有抓取到一些關鍵信息,信息如下:
解釋一下,當調度某個pod時,有可能會進入到調度器的搶占preempt
環(huán)節(jié),而上面的日志就是出自于搶占環(huán)節(jié)。 集群中有4個節(jié)點(3個master node和1個worker node),但是日志中只顯示了3個節(jié)點,缺少了一個master節(jié)點。 所以,這里暫時懷疑下是調度器內部緩存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數(shù)據結構。
結合上圖,一次pod的調度過程就是 一次Scheduler Cycle
。 在這個Cycle
開始時,第一步就是update snapshot
。snapshot我們可以理解為cycle內的cache,其中保存了pod調度時所需的node info
,而update snapshot
,就是一次nodeTree(調度器內部cache中保存的node信息)到snapshot
的同步過程。 而同步過程主要是通過nodeTree.next()
函數(shù)來實現(xiàn),函數(shù)邏輯如下:
// 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)到的同步過程丟失了某個節(jié)點信息。
### nodeTree數(shù)據結構 (方便理解,本文使用了鏈表來展示)
在nodeTree數(shù)據結構中,有兩個游標zoneIndex 和 lastIndex(zone級別),用來控制 nodeTree(調度器內部cache)到snapshot.nodeInfoList
的同步過程。并且,重要的一點是:上次同步后的游標值會被記錄下來,用于下次同步過程的初始值。
### 重現(xiàn)問題,定位根因
創(chuàng)建k8s集群時,會先加入master node,然后再加入worker node(意思是worker node時間上會晚于master node加入集群的時間)。
第一輪同步:3臺master node創(chuàng)建好,然后發(fā)生pod調度(比如,cni 插件,以daemonset的方式部署在集群中),會觸發(fā)一次nodeTree(調度器內部cache)到的同步。同步之后,nodeTree的兩個游標就變成了如下結果:
nodeTree.zoneIndex = 1, nodeTree.nodeArray[sh:200002].lastIndex = 3,
第二輪同步:當worker node加入集群中后,然后新建一個daemonset,就會觸發(fā)第二輪的同步(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 去哪了?在第二輪同步的過程中丟了。
從問題根因
的分析中,可以看出,導致問題發(fā)生的原因,在于 nodeTree 數(shù)據結構中的游標 zoneIndex 和 lastIndex(zone級別)值被保留了,所以,解決的方案就是在每次同步SYNC時,強制重置游標(歸0)。
到此,相信大家對“如何排查K8s Scheduler在調度pod過程中遺漏部分節(jié)點的問題”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續(xù)學習!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。