[kubernetes] 资源管理 --- 资源预留实践
一 概述
1.1 問題
系統資源可分為兩類:可壓縮資源(CPU)和不可壓縮資源(memory、storage)。可壓縮資源比如CPU超配后,在系統滿負荷時會劃分時間片分時運行進程,系統整體會變慢(一般不會導致太大的問題)。但不可壓縮資源如Memory,當系統內存不足時,就有可能觸發系統 OOM;這時候根據 oom score 來確定優先殺死哪個進程,而 oom_score_adj 又是影響 oom score 的重要參數,其值越低,表示 oom 的優先級越低。在計算節點中,進程的 oom_score_adj 如下:
?
所以,OOM 的優先級如下:
BestEffort Pod > Burstable Pod > 其它進程 > Guaranteed Pod > kubelet/docker 等 > sshd 等
在Kubernetes平臺,默認情況下Pod能夠使用節點全部可用資源。如果節點上的Pod負載較大,那么這些Pod可能會與節點上的系統守護進程和k8s組件爭奪資源并導致節點資源短缺,甚至引發系統OOM,導致某些進程被Linux系統的OOM killer機制殺掉,假如被殺掉的進程是系統進程或K8S組件,會導致比較嚴重的問題。
1.2 解決方案
針對這種問題,主要有兩種解決方案(兩種也可以結合使用):
??? 啟用kubelet的Node Allocatable特性,為系統守護進程和k8s組件預留資源。 官方文檔:https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources
??? 設置pod的驅逐策略,在pod使用資源到一定程度時進行pod驅逐。官方文檔:https://kubernetes.io/docs/tasks/administer-cluster/out-of-resource/#eviction-policy
?
二? Kubelet Node Allocatable
kubelet的啟動配置中有一個Node Allocatable特性,來為系統守護進程和k8s組件預留計算資源,使得即使節點滿負載運行時,也不至于出現pod去和系統守護進程以及k8s組件爭搶資源,導致節點掛掉的情況。kubernetes官方建議根據各個節點的負載情況來具體配置相關參數。
- Kubelet Node Allocatable用來為Kube組件和System進程預留資源,從而保證當節點出現滿負荷時也能保證Kube和System進程有足夠的資源。
- 目前支持cpu, memory, ephemeral-storage三種資源預留。
- Node Capacity是Node的所有硬件資源,kube-reserved是給kube組件預留的資源,system-reserved是給System進程預留的資源, eviction-threshold是kubelet eviction的閾值設定,allocatable才是真正scheduler調度Pod時的參考值(保證Node上所有Pods的request resource不超過Allocatable)。
- Node Allocatable Resource = Node Capacity - Kube-reserved - system-reserved - eviction-threshold
如何配置
- --enforce-node-allocatable,默認為pods,要為kube組件和System進程預留資源,則需要設置為pods,kube-reserved,system-reserve。
- --cgroups-per-qos,Enabling QoS and Pod level cgroups,默認開啟。開啟后,kubelet會將管理所有workload Pods的cgroups。
- --cgroup-driver,默認為cgroupfs,另一可選項為systemd。取決于容器運行時使用的cgroup driver,kubelet與其保持一致。比如你配置docker使用systemd cgroup driver,那么kubelet也需要配置--cgroup-driver=systemd。
- --kube-reserved,用于配置為kube組件(kubelet,kube-proxy,dockerd等)預留的資源量,比如—kube-reserved=cpu=1000m,memory=8Gi,ephemeral-storage=16Gi。
- --kube-reserved-cgroup,如果你設置了--kube-reserved,那么請一定要設置對應的cgroup,并且該cgroup目錄要事先創建好,否則kubelet將不會自動創建導致kubelet啟動失敗。比如設置為kube-reserved-cgroup=/kubelet.service 。
- --system-reserved,用于配置為System進程預留的資源量,比如—system-reserved=cpu=500m,memory=4Gi,ephemeral-storage=4Gi。
- --system-reserved-cgroup,如果你設置了--system-reserved,那么請一定要設置對應的cgroup,并且該cgroup目錄要事先創建好,否則kubelet將不會自動創建導致kubelet啟動失敗。比如設置為system-reserved-cgroup=/system.slice。
- --eviction-hard,用來配置kubelet的hard eviction條件,只支持memory和ephemeral-storage兩種不可壓縮資源。當出現MemoryPressure時,Scheduler不會調度新的Best-Effort QoS Pods到此節點。當出現DiskPressure時,Scheduler不會調度任何新Pods到此節點。關于Kubelet Eviction的更多解讀,請參考我的相關博文。
- Kubelet Node Allocatable的代碼很簡單,主要在pkg/kubelet/cm/node_container_manager.go,感興趣的同學自己去走讀一遍。
?
3. 實踐
根據是否對system和kube做cgroup上的硬限制進行劃分,資源預留主要有兩種方式:
- 只對所有pod使用的資源總量做cgroup級別的限制,對system和kube不做cgroup級別限制
- 對pod、system、kube均分別做cgroup級別限制
方式1—只限制pod資源總量
1? 將以下內容添加到kubelet的啟動參數中:
--enforce-node-allocatable=pods \
--cgroup-driver=cgroupfs \
--kube-reserved=cpu=1,memory=1Gi,ephemeral-storage=10Gi \
--system-reserved=cpu=1,memory=2Gi,ephemeral-storage=10Gi \
--eviction-hard=memory.available<500Mi,nodefs.available<10%
按以上設置
??? 節點上可供Pod所request的資源總和allocatable計算如下:
??? allocatable = capacity - kube-reserved - system-reserved - eviction-hard
??? 節點上所有Pod實際使用的資源總和不會超過:
??? capacity - kube-reserved - system-reserved
2. 重啟kubelet
service kubelet restart
3. 驗證
1.驗證公式計算的allocatable與實際一致
通過kubectl describe node查看節點實際capacity及allocatable的值
Capacity:cpu: 8memory: 32930152Ki(約31.4G)pods: 110 Allocatable:cpu: 6memory: 29272424Ki(約27.9G)pods: 110根據公式capacity - kube-reserved - system-reserved - eviction-hard,memory的allocatable的值為31.4G - 1G - 2G - 0.5G = 27.9G,與Allocatable的值一致。
2.驗證公式計算的總使用量限制與實際值一致
查看kubepods控制組中對內存的限制值memory.limit_in_bytes(memory.limit_in_bytes值決定了Node上所有的Pod實際能使用的內存上限)
$ cat /sys/fs/cgroup/memory/kubepods/memory.limit_in_bytes
30499250176(約28.4G)
根據公式capacity - kube-reserved - system-reserved,Node上Pod能實際使用的資源上限值為:31.4G - 1G -2G = 28.4G,與實際一致。
?
方式2—同時限制pod、k8s系統組件、linux系統守護進程資源
配置過程
1.將以下內容添加到kubelet的啟動參數中:
--enforce-node-allocatable=pods,kube-reserved,system-reserved \
--cgroup-driver=cgroupfs \
--kube-reserved=cpu=1,memory=1Gi,ephemeral-storage=10Gi \
--kube-reserved-cgroup=/system.slice/kubelet.service \
--system-reserved cpu=1,memory=2Gi,ephemeral-storage=10Gi \
--system-reserved-cgroup=/system.slice \
--eviction-hard=memory.available<500Mi,nodefs.available<10%
至于如何設置cgroup結構,請參考官方建議。
2.為system.slice創建cpuset子系統:
mkdir -p /sys/fs/cgroup/cpuset/system.slice/kubelet.service
mkdir -p /sys/fs/cgroup/pids/system.slice/kubelet.service
mkdir -p /sys/fs/cgroup/devices/system.slice/kubelet.service
mkdir -p /sys/fs/cgroup/memory/system.slice/kubelet.service
mkdir -p /sys/fs/cgroup/hugetlb/system.slice/kubelet.service
mkdir -p /sys/fs/cgroup/cpu,cpuacct/system.slice/kubelet.service
mkdir -p /sys/fs/cgroup/blkio/system.slice/kubelet.service
mkdir -p /sys/fs/cgroup/systemd/system.slice/kubelet.service
備注:這一步手工創建,否則啟動kubelet會報找不到相應cgroup的錯誤。
1. 可以看到未創建前system.slice這個cgroup是沒有cpuset子系統的:
find /sys/fs/cgroup -name system.slice
/sys/fs/cgroup/devices/system.slice/sys/fs/cgroup/memory/system.slice/sys/fs/cgroup/blkio/system.slice/sys/fs/cgroup/cpu,cpuacct/system.slice/sys/fs/cgroup/systemd/system.slice?
2. 可以看到未創建前kubelet是沒有cpuset子系統的:
find /sys/fs/cgroup -name kubelet.service
??
3.重啟kubelet
驗證過程
這種情況下pod可分配的資源和實際可使用資源理論上與方法一的計算方式和結果是一樣的,實際實驗中也是一樣的,在這里不做贅述。重點驗證此情況下是否對k8s系統組件和linux系統守護進程做了cgroup硬限制。
查看system.slice控制組中對內存的限制值memory.limit_in_bytes:
$ cat /sys/fs/cgroup/memory/system.slice/memory.limit_in_bytes
2147483648(2G)
查看kubelet.service控制組中對內存的限制值memory.limit_in_bytes:
$ cat /sys/fs/cgroup/memory/system.slice/kubelet.service/memory.limit_in_bytes
1073741824(1G)
可以看到,方法2這種預留方式,對k8s組件和系統進程也做了cgroup硬限制,當k8s組件和系統組件資源使用量超過這個限制時,會出現這些進程被殺掉的情況。
?
例子
以如下的kubelet資源預留為例,Node Capacity為memory=32Gi, cpu=16, ephemeral-storage=100Gi,我們對kubelet進行如下配置:
--enforce-node-allocatable=pods,kube-reserved,system-reserved --kube-reserved-cgroup=/system.slice/kubelet.service --system-reserved-cgroup=/system.slice --kube-reserved=cpu=1,memory=2Gi,ephemeral-storage=1Gi --system-reserved=cpu=1,memory=1Gi,ephemeral-storage=1Gi --eviction-hard=memory.available<500Mi,nodefs.available<10%NodeAllocatable = NodeCapacity - Kube-reserved - system-reserved - eviction-threshold =
cpu=14, memory=28Gi ephemeral-storage=98Gi.
Scheduler會確保Node上所有的Pod Resource Request不超過NodeAllocatable。Pods所使用的memory和storage之和超過NodeAllocatable后就會觸發kubelet Evict Pods。
?
參考:
https://my.oschina.net/jxcdwangtao/blog/1629059
https://blog.csdn.net/liukuan73/article/details/81054961
https://blog.csdn.net/liukuan73/article/details/82024085
?
總結
以上是生活随笔為你收集整理的[kubernetes] 资源管理 --- 资源预留实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Win10系统键盘无法打字怎么办(教你固
- 下一篇: [机器学习] TF-IDF算法