記一次kubernetes驅逐踩坑


最近在公司的線上服務器上發現了一個現象: 將某個node的kubelet短暫的停掉之后,其上的pod馬上會被驅逐,這讓筆者大吃一驚,印象之中,停掉kubelet后,該node會變為NotReady狀態,隨后controller-manger會經過一段時間才開始驅逐其上的pod。還有個參數專門來控制這個時間:

--pod-eviction-timeout The grace period for deleting pods on failed nodes. (default 5m0s)`

該參數默認值為5min, 也就是說當node NotReady之后,最少也得五分鍾之后其上的pod才會被驅逐。但是現實情況明顯不符合預期啊,這樣就有點奇怪了。
鑒於該問題影響巨大,筆者果斷開啟了debug之旅。

首先我們從直接原因下手,需要了解一下當node NotReady之后,controller-manager是如何判斷並驅逐其上的pod的,這部分工作是由node lifecycel controller模塊負責。

node lifecycle controller 主要負責對node生命周期進行檢查,判斷node是否存活,如果長時間檢測不到node心跳則驅逐其上的pod。在目前的版本(v1.16)中,默認開啟了TaintBasedEvictions, TaintNodesByCondition這兩個feature gate,則所有node生命周期管理都是通過condition + taint的方式進行管理。其主要邏輯由三部分組成:

  1. 不斷地檢查所有node狀態,設置對應的condition
  2. 不斷地根據node condition 設置對應的taint
  3. 不斷地根據taint驅逐node上面的pod

想要詳細了解node lifecycle controller工作機制的同學可以翻閱筆者上一篇文章: kubernetes中node心跳處理邏輯分析

查看代碼發現--pod-eviction-timeout並未起作用,原來在v1.13版本之前TaintBasedEvictions功能還未開啟,此時node not-ready之后,controller直接判斷not-ready時間是否超過了--pod-eviction-timeout,超過就進行刪除。而v1.13,TaintBasedEvictions功能開啟之后就不會使用了該參數,轉而使用了上面描述的condition+taint方案。也就是說node NotReady之后,pod的驅逐時間完全由每個pod toleration中 tolerationSecond決定,而不是由controller-manager的參數--pod-eviction-timeout統一決定。這樣想想也合情合理,每個pod對於故障的容忍時間不同,tolerationSecond可以更加靈活地為每個pod指定不同的驅逐時間。

這樣說來,所有的pod都需要設置一個toleration才對,查閱相關資料后發現,社區已經有了一個DefaultTolerationSeconds admisson controller自動地幫助我們設置toleration,每次創建更新pod, 在請求發送到apiserver之后會自動設置5min的默認toleration。

This admission controller sets the default forgiveness toleration for pods to tolerate the taints notready:NoExecute and unreachable:NoExecute for 5 minutes, if the pods don’t already have toleration for taints node.kubernetes.io/not-ready:NoExecute or node.alpha.kubernetes.io/unreachable:NoExecute.

文檔上顯示該admission controller默認開啟,但是為什么我司的環境上面沒有生效,仔細看了一下文檔,是因為自己使用了一個deprecated的參數:--admission-control,使用這個參數的話必須顯式指定所有要開啟的admisson controller plugin列表。該參數在v1.10被廢棄,由兩個新的參數--enable-admission-plugins--disable-admission-plugins替換,這兩個參數如果不指定的話會有默認值,其中DefaultTolerationSeconds就屬於--enable-admission-plugins參數的默認值之一,也就是會默認開啟該plugin。又是一個升級導致的坑! 正確修改了該參數之后,新創建的pod就會默認帶上了toleration,DefaultTolerationSeconds adminssion controller plugin總算生效了。 

新創建的pod總算沒有問題了,但是對於集群中已經存在的pod還沒有toleration該怎么辦? 顯然社區對這種情況未做處理,DefaultTolerationSeconds是社區很早就開發的一個feature,但是TaintBasedEvictions是v1.13才默認開啟,估計社區在開發時前后沒有做好兼容。翻了下DefaultTolerationSecondsadminssion plugin源碼,發現該plugin對於pod create, update操作都會設置toleration, 所以一般情況下, 我們升級集群的時候,總是能觸發pod發生update,該toleration會自動添加上,無需過多操作,大可不必擔心,心里知道有這個事情並檢查一下就行。但是筆者的環境已經升級完成了,只能手動觸發pod update了,思來想去,想要觸發pod update又不能影響業務,給pod打label是一個比較好的方式,於是筆者寫了一個腳本將集群中所有的pod都打了一個無關緊要的label, 觸發uodate后就自動添加了toleration。

至此整個修復工作全部完成,回過頭來仔細想想,kubernetes版本間升級挑戰還是挺大的,兼容性問題防不勝防,很可能兩個小版本間完全兼容,沒任何問題,但是當一步步從低版本升級上來的時候問題就出現了,而且在兼容性測試的時候難以覆蓋到每種情況,很可能需要很久問題才能暴露出來。對於這種情況,唯有掌握內部機理,熟讀源碼才能快速診斷,修復。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM