如何正確配置kubernetes集羣資源

【本文專欄於[頭條號]、[知乎]同步發佈,可關注同名賬號訂閱相關文章,每週固定更新】

對於大多數剛入門k8s的朋友們來說,k8s強大容器編排功能能讓我們把更多的目光聚焦在應用級的系統架構設計上。對於硬件資源充裕的團隊,甚至存在資源不夠機器來湊的情況。但kubernetes畢竟無法完全適配實際的使用場景,默認的配置只能提供最最初級的資源管理,如何讓kubernetes更好的適配我們的物理環境?如何利用kubernetes幫助我們最大可能的規避資源所帶來的風險?本文將結合實例針對kubernetes中的資源管理進行詳細的介紹。


一次集羣雪崩引發的思考

至今還清晰的記得,那是一個下雨的深夜。

熟睡的我突然被一陣報警短信驚醒。

迷迷糊糊一瞟。是節點notReady報警。非常不情願的爬起來查看集羣狀態,心想集羣機器夠用,肯定扛得住。

然而現實深深地在我臉上拍了兩下。

集羣中多個大應用同時出現慢查詢query,導致應用處理耗時過高,32核的機器load直線飆升。同時Pod壓榨到了kubelet組件的資源,導致kubelet與APIServer的心跳斷了,超過閾值節點Not Ready。

接着,該節點的Pod會在其他節點上迅速擴散,大量的Pod重建接連壓垮了多個節點,進而節點Not Ready如潮水般擴散,俗稱集羣雪崩。集羣內的Nodes逐個的Not Ready了,後果非常嚴重。後續組內同事迅速將流量切到備用集羣,盡最大可能挽回損失。

經過這一劫,讓我深深感到資源管理的重要性,對集羣的資源管理進行一次整改。先來看看kubernetes爲我們提供了怎麼的管理方式。

先拋兩張Kubernetes基礎組件架構圖:

 

K8S Master

 

K8S node

Master部分,由於在物理部署時,Master並不承載具體的業務,且單獨部署在物理機上,因此這一塊的系統資源使用率較低。這裏不做深入討論。

這裏主要對Node節點進行深入探討。Node節點的資源控制主要由Kubelet進行配置。Kubelet中Node Allocatable提供了爲系統進程預留計算資源的配置方法,從而在節點出現資源匱乏時也能保證k8s組件及System有足夠的資源。

來看Node Allocatable提供的資源管理項。

Node Capacity
--------------------------
| kube-reserved |
|-------------------------|
| system-reserved |
|-------------------------|
| eviction-threshold |
|-------------------------|
| allocatable |
| (available for pods) |
---------------------------

Node Capacity是Node的所有硬件資源

kube-reserved是給kube組件預留的資源

system-reserved是給System進程預留的資源

eviction-threshold是kubelet eviction的閾值設定

allocatable纔是真正scheduler調度Pod時的參考值(保證Node上所有Pods的request resource不超過Allocatable)

上面這個層級結構用一條公式概括就是:

Allocatable = Node Capacity - Kube-reserved - system-reserved - eviction-threshold

我們該如何設置?

系統級配置

1,--enforce-node-allocatable

--enforce-node-allocatable=pods[,][system-reserved][,][kube-reserved]

這個選項是默認開啓的,當Pod的資源使用量超過了Allocatable,pod將被驅逐。

2,--cgroups-per-qos

該選項默認開啓,開啓後,kubelet會管理所以帶負載的Pod的cgroups。

3,--cgroup-driver

配置cgroups驅動,該選項可選的參數是systemd和cgroupfs。具體的配置取決於相關容器運行時(container runtime)的配置。例如如果操作員使用 docker 運行時提供的 cgroup 驅動時,必須配置 kubelet 使用 systemd cgroup 驅動

4,--kube-reserved

用於配置爲kube組件(kubelet,kube-proxy,dockerd等)預留的資源量,比如—kube-reserved=cpu=1000m,memory=8Gi,ephemeral-storage=16Gi。

5,--kube-reserved-cgroup

如果你設置了--kube-reserved,那麼請一定要設置對應的cgroup,並且該cgroup目錄要事先創建好,否則kubelet將不會自動創建導致kubelet啓動失敗。比如設置爲kube-reserved-cgroup=/kubelet.service 。

6,--system-reserved

用於配置爲System進程預留的資源量,比如—system-reserved=cpu=500m,memory=4Gi,ephemeral-storage=4Gi。

7,--system-reserved-cgroup

如果你設置了--system-reserved,那麼請一定要設置對應的cgroup,並且該cgroup目錄要事先創建好,否則kubelet將不會自動創建導致kubelet啓動失敗。比如設置爲system-reserved-cgroup=/system.slice。

8,--eviction-hard

用來配置kubelet的hard eviction條件,只支持memory和ephemeral-storage兩種不可壓縮資源。當出現MemoryPressure時,Scheduler不會調度新的Best-Effort QoS Pods到此節點。當出現DiskPressure時,Scheduler不會調度任何新Pods到此節點。

舉個官方例子趁熱打鐵

節點擁有 32Gi 內存,16 核 CPU 和 100Gi 存儲

--kube-reserved 設置爲 cpu=1,memory=2Gi,storage=1Gi
--system-reserved 設置爲 cpu=500m,memory=1Gi,storage=1Gi
--eviction-hard 設置爲 memory.available<500Mi,nodefs.available<10%

在這個場景下,Allocatable 將會是 14.5 CPUs、28.5Gi 內存以及 98Gi 存儲。調度器保證這個節點上的所有 pod 請求的內存總量不超過 28.5Gi,存儲不超過 88Gi。當 pod 的內存使用總量超過 28.5Gi 或者磁盤使用總量超過 88Gi 時,Kubelet 將會驅逐它們。如果節點上的所有進程都儘可能多的使用 CPU,則 pod 加起來不能使用超過 14.5 CPUs 的資源。

當沒有執行 kube-reserved 和/或 system-reserved 且系統守護進程使用量超過其預留時,如果節點內存用量高於 31.5Gi 或存儲大於 90Gi,kubelet 將會驅逐 pod。

Pod級配置

配置完系統級的資源管理,別忘了還有pod級資源。

1, Request和Limit限制

Kubernetes提供了針對memory和CPU的容器級的資源限制。每個資源又分爲request和limit兩種配置項。

Request: 容器使用的最小資源需求,作爲容器調度時資源分配的判斷依賴。只有當節點上可分配資源量>=容器資源請求數時才允許將容器調度到該節點。但Request參數不限制容器的最大可使用資源。

Limit: 容器能使用資源的資源的最大值,設置爲0表示使用資源無上限。

Request能夠保證Pod有足夠的資源來運行,而Limit則是防止某個Pod無限制地使用資源,導致其他Pod崩潰。兩者之間必須滿足關係: 0<=Request<=Limit<=Infinity (如果Limit爲0表示不對資源進行限制,這時可以小於Request)

2, Pod的反親和力配置

這一配置根據已在節點上運行的pod上的標籤來限制pod可以調度到哪些節點,而不是基於節點上的標籤。

這一點在往往容易被人忽視,這個選項看起來只是限制Pod的部署方式,但恰恰是這一特性,可以幫你避免了同一個應用的多個副本同時部署在一臺節點是。結合我的雪崩例子,集羣中的應用均是以多副本的形式部署在集羣中的,在正常情況下,pod隨機分配到各個node上,同一節點有可能存在同個應用的多個副本。一旦該應用的負載升高,那這個存在多個副本的節點勢必受到成倍的負載壓力。因此對於多副本的應用,配置反親和力是非常有必要的。

舉個栗子:

podAntiAffinity:
 preferredDuringSchedulingIgnoredDuringExecution:
 - weight: 100
 podAffinityTerm:
 labelSelector:
 matchExpressions:
 - key: app
 operator: In
 values:
 - Hot
 topologyKey: kubernetes.io/hostname

這一段使用preferredDuringSchedulingIgnoredDuringExecution,表示如果某個節點已經運行着具有“app=Hot”標籤的pod,那該pod將不會優先調度到該節點。

通過對集羣進行以上的配置,相信能夠爲你的集羣可用性帶來較大的提升。

如果覺得有些收穫,記得關注我喲。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章