QoS是Quality of Service
的縮寫,即服務質量。每個pod屬於某一個QoS分類,而Kubernetes會根據pod的QoS級別來決定pod的排程、搶佔排程和驅逐優先順序,而且pod的QoS級別也影響oomkiller對殺死程序的選擇。
QoS主要分為Guaranteed
、Burstable
和Best-Effort
三個級別,優先順序從高到低。
怎麼決定某個pod屬於哪個QoS分類呢?根據pod yaml中的cpu和記憶體資源定義決定。
同時滿足以下情形的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
...
同時滿足以下情形的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
...
同時滿足以下情形的pod屬於Best-Effort
級別:
(1)pod中的所有容器都沒有設定記憶體的request與limit;
(2)pod中的所有容器都沒有設定cpu的request與limit;
...
containers:
- name: test-a
...
- name: test-b
...
kubelet不使用pod的QoS級別來確定驅逐順序,但注意,Guaranteed
級別QoS的pod不會被驅逐。
當node節點記憶體資源不足時,會觸發kubelet的節點壓力驅逐,pod驅逐順序選擇如下(排在前面的優先被驅逐):
(1)先根據pod的記憶體使用量是否超過記憶體request排序,超過的排在前面;
(2)再根據pod的priority值大小排序,值小的排在前面;
(3)最後根據pod記憶體request值減去pod的記憶體使用量的值,得到值小的排在前面;
通過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排程上去;
詳細內容請檢視官方檔案:https://kubernetes.io/zh/docs/concepts/scheduling-eviction/pod-priority-preemption/
當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,但當你的程序佔用記憶體很大時,該程序同樣有很大的概率會被殺死;
對於Guaranteed
級別的pod,其oom_score_adj
的值被設定為-998,對於Best-Effort
級別的pod,其oom_score_adj
的值被設定為1000,對於Burstable
級別的pod,其oom_score_adj
的取值為2到999。
(1)將程序oom_score_adj
的值設定為-1000;
(2)關閉OOM killer
機制;
pod搶佔排程機制,解決的是 Pod 排程失敗時該怎麼辦的問題。
正常情況下,當一個 pod 排程失敗後,就會被暫時 「擱置」 處於 pending 狀態,直到 pod 被更新或者叢集狀態發生變化,排程器才會對這個 pod 進行重新排程。
但是有的時候,我們希望給pod分等級,即分優先順序。當一個高優先順序的 Pod 排程失敗後,該 Pod 並不會被「擱置」,而是會「擠走」某個 Node 上的一些低優先順序的 Pod(請求apiserver,刪除pod),這樣一來就可以保證高優先順序 Pod 會優先排程成功。
這裡所講的優先順序就是前面提到的pod的priority值大小。
關於pod優先順序,具體請參考:https://kubernetes.io/zh/docs/concepts/scheduling-eviction/pod-priority-preemption/
搶佔發生的原因,一定是一個高優先順序的 pod 排程失敗,我們稱這個 pod 為「搶佔者」,稱被搶佔的 pod 為「犧牲者」(victims)。