工具簡介
Descheduler 的出現就是為了解決 Kubernetes 自身調度(一次性調度)不足的問題。它以定時任務方式運行,根據已實現的策略,重新去平衡 pod 在集群中的分布。
截止目前,Descheduler 已實現的策略和計划中的功能點如下:
已實現的調度策略
- RemoveDuplicates
移除重復 pod - LowNodeUtilization
節點低度使用 - RemovePodsViolatingInterPodAntiAffinity
移除違反pod反親和性的 pod - RemovePodsViolatingNodeAffinity
路線圖中計划實現的功能點
- Strategy to consider taints and tolerations
考慮污點和容忍 - Consideration of pod affinity
考慮 pod 親和性 - Strategy to consider pod life time
考慮 pod 生命周期 - Strategy to consider number of pending pods
考慮待定中的 pod 數量 - Integration with cluster autoscaler
與集群自動伸縮集成 - Integration with metrics providers for obtaining real load metrics
與監控工具集成來獲取真正的負載指標 - Consideration of Kubernetes’s scheduler’s predicates
考慮 k8s 調度器的預判機制
策略介紹
-
RemoveDuplicates
此策略確保每個副本集(RS)、副本控制器(RC)、部署(Deployment)或任務(Job)只有一個 pod 被分配到同一台 node 節點上。如果有多個則會被驅逐到其它節點以便更好的在集群內分散 pod。 -
LowNodeUtilization
a. 此策略會找到未充分使用的 node 節點並在可能的情況下將那些被驅逐后希望重建的 pod 調度到該節點上。
b. 節點是否利用不足由一組可配置的 閾值(thresholds
) 決定。這組閾值是以百分比方式指定了 CPU、內存以及 pod數量 的。只有當所有被評估資源都低於它們的閾值時,該 node 節點才會被認為處於利用不足狀態。
c. 同時還存在一個 目標閾值(targetThresholds
),用於評估那些節點是否因為超出了閾值而應該從其上驅逐 pod。任何閾值介於thresholds
和targetThresholds
之間的節點都被認為資源被合理利用了,因此不會發生 pod 驅逐行為(無論是被驅逐走還是被驅逐來)。
d. 與之相關的還有另一個參數numberOfNodes
,這個參數用來激活指定數量的節點是否處於資源利用不足狀態而發生 pod 驅逐行為。 -
RemovePodsViolatingInterPodAntiAffinity
此策略會確保 node 節點上違反 pod 間親和性的 pod 被驅逐。比如節點上有 podA 並且 podB 和 podC(也在同一節點上運行)具有禁止和 podA 在同一節點上運行的反親和性規則,則 podA 將被從節點上驅逐,以便讓 podB 和 podC 可以運行。 -
RemovePodsViolatingNodeAffinity
此策略會確保那些違反 node 親和性的 pod 被驅逐。比如 podA 運行在 nodeA 上,后來該節點不再滿足 podA 的 node 親和性要求,如果此時存在 nodeB 滿足這一要求,則 podA 會被驅逐到 nodeB 節點上。
遵循機制
當 Descheduler 調度器決定於驅逐 pod 時,它將遵循下面的機制:
-
Critical pods (with annotations scheduler.alpha.kubernetes.io/critical-pod) are never evicted
關鍵 pod(帶注釋 scheduler.alpha.kubernetes.io/critical-pod)永遠不會被驅逐。 -
Pods (static or mirrored pods or stand alone pods) not part of an RC, RS, Deployment or Jobs are never evicted because these pods won’t be recreated
不屬於RC,RS,部署或作業的Pod(靜態或鏡像pod或獨立pod)永遠不會被驅逐,因為這些pod不會被重新創建。 -
Pods associated with DaemonSets are never evicted
與 DaemonSets 關聯的 Pod 永遠不會被驅逐。 -
Pods with local storage are never evicted
具有本地存儲的 Pod 永遠不會被驅逐。 -
BestEffort pods are evicted before Burstable and Guaranteed pods
QoS 等級為 BestEffort 的 pod 將會在等級為 Burstable 和 Guaranteed 的 pod 之前被驅逐。
工具使用
Descheduler 會以 Job 形式在 pod 內運行,因為 Job 具有多次運行而無需人為介入的優勢。為了避免被自己驅逐 Descheduler 將會以 關鍵型 pod 運行,因此它只能被創建建到 kube-system
namespace 內。
關於 Critical pod 的介紹請參考:Guaranteed Scheduling For Critical Add-On Pods
要使用 Descheduler,我們需要編譯該工具並構建 Docker 鏡像,創建 ClusterRole、ServiceAccount、ClusterRoleBinding、ConfigMap 以及 Job。
由於文檔中有一些小問題,手動執行這些步驟不會很順利,我們推薦使用有人維護的現成 helm charts。
項目地址:https://github.com/komljen/helm-charts/tree/master/descheduler
使用方式:
helm repo add akomljen-charts \
https://raw.githubusercontent.com/komljen/helm-charts/master/charts/
helm install --name ds --namespace kube-system akomljen-charts/descheduler
該 Chart 默認設置如下:
- Descheduler 以 CronJob 方式運行,每 30 分鍾執行一次,可根據實際需要進行調整;
- 在 ConfigMap 中同時內置了 4種策略,可根據實際需要禁用或調整;
值得注意的是,Descheduler 項目文檔中是以 Job 方式運行,屬於一次性任務。
問題處理
在手動編譯構建 Descheduler 過程中,我們發現官方文檔有個小問題。
比如,文檔中 Job 的啟動方式如下:
command:
- "/bin/sh"
- "-ec"
- |
/bin/descheduler --policy-config-file /policy-dir/policy.yaml
即,指定使用 sh
來運行 descheduler
,然而該工具的 Dockerfile 卻是以白手起家(FROM scratch)方式添加 descheduler 的編譯產物到容器內,新容器並不包含工具sh
, 這就導致 Job 在運行后因為沒有 sh
而失敗並不斷拉起新的 Job,短時間內大量 Job 被創建, node 節點資源也逐漸被消耗。
關於該問題我提交了一個 isusse #133,解決辦法有2種:
- 從 command 中移除
/bin/sh -ec
- 修改 Dockerfile 中
From scratch
為From alpine
或 busybox 或 centos 等
然后重新構建並創建 Job。