k8s筆記--驅逐與重排程,以及deschueduler的一次實驗

DogTwo發表於2022-02-16

    在Kubernetes中,排程是指將Pod放置到合適的Node上,然後對應的Node上的Kubelet才能夠執行這些pod。排程器通過Kubernetes的監測機制來發現叢集中新建立且尚未被排程的Node上的Pod。K8s中預設的排程器是kube-scheduler, 當然,也可以自行實現一個自定義的排程器。

   在開始之前,先來看幾個相關的概念:

驅逐:

    kubelet監控叢集節點的CPU, 記憶體,磁碟空間和檔案系統的inode等資源。當這些資源中的一個或多個達到特定的消耗水平,kubelet可以通過主動地使節點上一個或多個Pod失效,以回收資源防止資源不足。(當然,kubelet在終止終端使用者Pod之前會嘗試回收節點級資源。例如,它會在磁碟資源不足時刪除未使用的容器映象。當然這不在我們的考慮範圍內。) 驅逐實質上是kubelet主動終止Pod以回收節點上資源的過程。

    由kubelet發起的驅逐稱為節點壓力驅逐,這種方式下,如果使用了 軟碟機逐條件 kubelet會考慮配置的 eviction-max-pod-grace-period (驅逐寬限期), 如果使用了 硬驅逐條件 它會立即驅逐pod。

    當然也可以通過API發起驅逐,API發起的驅逐通過Eviction API建立驅逐物件,由它來體面地中止Pod。API發起的驅逐將尊村你的PodDisruptionBudgets (干擾預算,即PDB) 和 terminationGracePeriodSeconds (pod生命週期)配置。

重排程:

    將pod排程到指定的Node上執行是一個比較複雜的過程,有幾個概念需要介紹一下:

  • nodeSelector 通過在PodSpec中定義它,選擇node標籤中包含每個鍵值對的對應的節點
  • 親和性與反親和性(affinity/antiaffinity) 相比之下,這個規則更想是 軟需求 或是 偏好,因此如果排程器無法滿足該要求,仍然排程該pod
    • 可以使用node裡的pod的標籤來約束,而不是使用node本身的標籤。這可以實現允許哪些pod應當放到一起,或者不應當放到一起。
  • 汙點和容忍度(taints/tolerations) 上面的親和性與反親和性,nodeSelector都是Pod的一種屬性。而汙點則是Node上屬性,它能使節點排斥一類特定的Pod
    • 想像一下pod都是有潔癖的,一旦node上有汙點並且pod不能容忍這個汙點,那麼這個pod就不會被分配在這個node上
    • 同樣,pod如果可以容忍汙點,還是可以正常的分配。
    • 一個node上可以有0個或多個汙點
  • PDB: PodDisruptionBudget能夠針對自發的驅逐(即上面提到的通過API發起驅逐)提供保護
    • 例如將minAvailable設定為10,那麼即使是在干擾期間,也必須保證始終有10個Pod可用
    • PDB不能完全保證指定數量/指定百分比的Pod一直處於執行狀態,如當Pod集合的規模處於預算指定的最小值時,恰好某個pod又發生了故障,就會導致pod數量低於預期值。

    汙點的effect值NoExecute會影響已經在節點上執行的Pod,此時

    • 如果pod不能忍受effect值為NoExecute的汙點,那麼Pod將被馬上驅逐
    • 如果Pod能忍受這個汙點,但在容忍度tolerationSeconds上沒有定義,則Pod還會一直在節點上執行
    • 如果Pod能夠忍受這個汙點,並且指定了tolerationSeconds,那麼pod還會在這個節點上執行指定的時間長度

 

------------------------------------------------分割線-------------------------------------------------------------------------------------------------

 

下面是筆者關於descheduler的一次實驗

    先簡單介紹一下,descheduler是由社群提供,用於支援多種策略的排程器,可以根據不同策略對pod進行二次排程,使得node的使用率更加均衡一些。descheduler本身也支援許多不同的排程策略。

 

準備工作:

deschueduler部署:

    社群提供了基於Helm, Kustomize等多種部署方式,這次實驗採用的是手動部署的方式

  1. git clone 原始碼
  2. make image 生成映象檔案
  3. docker tag / docker push 準備好映象檔案
  4. 修改descheduler/kubernetes/base下的configMap檔案,禁用其他策略,僅保留RemoveDuplicates,用於驅逐在同一個node上部署的多個相同pod的副本
  5. kubectl create -f kubernetes/base/rbac.yaml 為descheduler授權
  6. kubectl create -f kubernetes/base/configmap.yaml 初始化配置相關檔案


其他準備:

    針對要測試用的pod

    1. 修改pod spec, 新增nodeSelector
    2. 為叢集下105,106,108node新增對應的labels
    3. 部署pod有一定概率在108機器上同時部署兩個相同的pod (此處基於kube-scheduler的預設排程策略,未檢視具體原因)

實驗記錄:

    1. 通過kubectl get pods -n 你的namespace -o wide 檢視pod,確認確實有兩個相同的pod都部署到了108節點上

 

 

    2. 通過kubectl apply -f descheduler/kubernetes/cronjob/cronjob.yaml 開啟descheduler的cronjob (cronjob 根據cron表示式指定的週期定期執行job,具體針對k8s來說,cronjob controller會定期建立對應的job pod)

 

 

此時的descheduler的配置為:

 

 

僅開啟了RemoveDuplicates策略

    3. 一段時間後再次通過kubectl get pods -n cloudadvisor-qa -o wide 檢視pod,顯示結果如下,發現原有pod已被驅逐並在105節點上重建

 

 

    4. 通過 kubectl get jobs -n kube-system 找到當前cronjob建立的descheduler job,  然後再通過kubectl get pods -n kube-system -l job-name='jobname' 檢視當前job所在的pod  注意-l 根據label選擇的使用

 

 

    5. 檢視這個pod對應的日誌,並搜尋與我們要觀察的oversold相關的部分(這裡為了後續檢視,已經匯出為檔案了)

 

 

    這裡可以看到descheduler先是發現了 duplicate的node節點,然後進行Adjusting feasible調整,並且可以看到驅逐的節點hkcl8正是剛剛我們在108建立的重複pod之一

 

相關文章