k8s QoS與pod驅逐
- 2022 年 7 月 31 日
- 筆記
- kubernetes源碼解析
概述
QoS是Quality of Service
的縮寫,即服務品質。每個pod屬於某一個QoS分類,而Kubernetes會根據pod的QoS級別來決定pod的調度、搶佔調度和驅逐優先順序,而且pod的QoS級別也影響oomkiller對殺死進程的選擇。
pod QoS級別
QoS主要分為Guaranteed
、Burstable
和Best-Effort
三個級別,優先順序從高到低。
怎麼決定某個pod屬於哪個QoS分類呢?根據pod yaml中的cpu和記憶體資源定義決定。
Guaranteed
同時滿足以下情形的pod屬於Guaranteed級別:
(1)pod中的所有容器都設置了cpu的request、limit值;
(2)pod中每個容器的cpu的request值與limit值都相等;
(1)pod中的所有容器都設置了記憶體的request、limit值;
(2)pod中每個容器的記憶體的request值與limit值都相等;
...
containers:
- name: test-a
resources:
limits:
cpu: 10m
memory: 1Gi
requests:
cpu: 10m
memory: 1Gi
...
- name: test-b
resources:
limits:
cpu: 100m
memory: 100Mi
requests:
cpu: 100m
memory: 100Mi
...
Burstable
同時滿足以下情形的pod屬於Burstable
級別:
(1)pod不符合Guaranteed
的QoS級別標準;
(2)pod中至少有一個容器設置了記憶體或cpu的request或limit值;
...
containers:
- name: test-a
...
- name: test-b
resources:
limits:
memory: 200Mi
requests:
memory: 100Mi
...
Best-Effort
同時滿足以下情形的pod屬於Best-Effort
級別:
(1)pod中的所有容器都沒有設置記憶體的request與limit;
(2)pod中的所有容器都沒有設置cpu的request與limit;
...
containers:
- name: test-a
...
- name: test-b
...
kubelet驅逐pod順序
kubelet不使用pod的QoS級別來確定驅逐順序,但注意,Guaranteed
級別QoS的pod不會被驅逐。
當node節點記憶體資源不足時,會觸發kubelet的節點壓力驅逐,pod驅逐順序選擇如下(排在前面的優先被驅逐):
(1)先根據pod的記憶體使用量是否超過記憶體request排序,超過的排在前面;
(2)再根據pod的priority值大小排序,值小的排在前面;
(3)最後根據pod記憶體request值減去pod的記憶體使用量的值,得到值小的排在前面;
關於pod的priority
通過pod.spec.priorityClassName
、pod.spec.priority
可為pod設置priority值大小,另外,Guaranteed
級別QoS的pod也會間接設置priority值;
pod的priority值大小會影響kubelet驅逐pod的順序,還會影響kube-scheduler對於pod調度、搶佔調度的優先順序順序:
(1)當kubelet驅逐pod時,pod其他條件相同的情況下,priority值越小的越容易被驅逐;
(2)priority值越大,kube-scheduler對於pod調度的優先順序越高;
(3)當pod因資源不足而調度失敗時,kube-scheduler會搶佔調度該pod,即將priority值比它小的pod驅逐掉,然後將該pod調度上去;
詳細內容請查看官方文檔://kubernetes.io/zh/docs/concepts/scheduling-eviction/pod-priority-preemption/
OOM killer機制
當kubelet沒來得及觸發pod驅逐,使得節點記憶體耗盡時,將觸發節點上的OOM killer
機制;
Linux上有個機制叫OOM killer
(Out Of Memory kille
r),這個機制會在系統記憶體耗盡的情況下發揮作用,即根據一定的演算法規則,選擇性的殺死一些進程,以釋放部分記憶體,讓系統繼續穩定運行。
如何選擇殺死哪個進程
當發生oomkill時,OOM killer
給進程打分,得到oom_score
,然後優先把oom_score
最大的進程先殺死;
oom_score
怎麼計算獲得呢?oom_score
=oom_score_adj
+進程記憶體佔用大小
;
而oom_score_adj
則是可以人工給每個進程設置的,從而讓用戶通過設置進程的oom_score_adj
值來影響OOM killer
殺死進程的選擇;
當oom_score_adj
的值設置為-1000時,表示該進程將不會被OOM killer
殺死,但如果設置的值不是-1000,那這個進程還是會參與打分,會受oom_score_adj
以及進程記憶體佔用大小的影響,需要注意的是,即使oom_score_adj
的值設置的很小,比如-999,但當你的進程佔用記憶體很大時,該進程同樣有很大的概率會被殺死;
pod中容器進程的oom_score_adj
對於Guaranteed
級別的pod,其oom_score_adj
的值被設置為-998,對於Best-Effort
級別的pod,其oom_score_adj
的值被設置為1000,對於Burstable
級別的pod,其oom_score_adj
的取值為2到999。
怎麼避免OOM Killer殺死某個業務進程?
(1)將進程oom_score_adj
的值設置為-1000;
(2)關閉OOM killer
機制;
pod搶佔調度
pod搶佔調度機制,解決的是 Pod 調度失敗時該怎麼辦的問題。
正常情況下,當一個 pod 調度失敗後,就會被暫時 「擱置」 處於 pending 狀態,直到 pod 被更新或者集群狀態發生變化,調度器才會對這個 pod 進行重新調度。
但是有的時候,我們希望給pod分等級,即分優先順序。當一個高優先順序的 Pod 調度失敗後,該 Pod 並不會被「擱置」,而是會「擠走」某個 Node 上的一些低優先順序的 Pod(請求apiserver,刪除pod),這樣一來就可以保證高優先順序 Pod 會優先調度成功。
這裡所講的優先順序就是前面提到的pod的priority值大小。
關於pod優先順序,具體請參考://kubernetes.io/zh/docs/concepts/scheduling-eviction/pod-priority-preemption/
搶佔發生的原因,一定是一個高優先順序的 pod 調度失敗,我們稱這個 pod 為「搶佔者」,稱被搶佔的 pod 為「犧牲者」(victims)。