在Kubernetes中,節(jié)點(diǎn)可以按照容量進(jìn)行調(diào)度。默認(rèn)情況下,Pod能夠使用節(jié)點(diǎn)的全部可用容量。然而,這可能會導(dǎo)致問題,因?yàn)楣?jié)點(diǎn)本身通常運(yùn)行了許多驅(qū)動(dòng)操作系統(tǒng)和Kubernetes的系統(tǒng)守護(hù)進(jìn)程。如果未為這些系統(tǒng)守護(hù)進(jìn)程留出資源,它們將與Pod競爭資源,從而導(dǎo)致節(jié)點(diǎn)資源短缺的問題。因此,為了確保系統(tǒng)的穩(wěn)定運(yùn)行,需要為這些系統(tǒng)守護(hù)進(jìn)程預(yù)留一定的資源。
kubelet 公開了一個(gè)名為 ‘Node Allocatable’ 的特性,有助于為系統(tǒng)守護(hù)進(jìn)程預(yù)留計(jì)算資源。 Kubernetes 推薦集群管理員按照每個(gè)節(jié)點(diǎn)上的工作負(fù)載密度配置 ‘Node Allocatable’。
一、準(zhǔn)備
1、必須擁有一個(gè) Kubernetes 的集群,同時(shí)必須配置 kubectl 命令行工具與集群通信。 建議在至少有兩個(gè)不作為控制平面主機(jī)的節(jié)點(diǎn)的集群上運(yùn)行本教程。 如果還沒有集群,可以通過 Minikube 構(gòu)建一個(gè)自己的集群,或者可以使用下面的 Kubernetes 練習(xí)環(huán)境之一:
- Killercoda
- 玩轉(zhuǎn) Kubernetes
2、Kubernetes 服務(wù)器版本必須不低于版本 1.8. 要獲知版本信息,請輸入 kubectl version.
3、 kubernetes 服務(wù)器版本必須至少是 1.17 版本,才能使用 kubelet 命令行選項(xiàng) –reserved-cpus 設(shè)置顯式預(yù)留 CPU 列表。
二、節(jié)點(diǎn)可分配資源
Kubernetes 節(jié)點(diǎn)上的 ‘Allocatable’ 被定義為 Pod 可用計(jì)算資源量。 調(diào)度器不會超額申請 ‘Allocatable’。 目前支持 ‘CPU’、’memory’ 和 ‘ephemeral-storage’ 這幾個(gè)參數(shù)。
可分配的節(jié)點(diǎn)暴露為 API 中 v1.Node 對象的一部分,也是 CLI 中 kubectl describe node 的一部分。
在 kubelet 中,可以為兩類系統(tǒng)守護(hù)進(jìn)程預(yù)留資源。
1、啟用 QoS 和 Pod 級別的 cgroups
為了恰當(dāng)?shù)卦诠?jié)點(diǎn)范圍實(shí)施節(jié)點(diǎn)可分配約束,必須通過 –cgroups-per-qos 標(biāo)志啟用新的 cgroup 層次結(jié)構(gòu)。這個(gè)標(biāo)志是默認(rèn)啟用的。 啟用后,kubelet 將在其管理的 cgroup 層次結(jié)構(gòu)中創(chuàng)建所有終端用戶的 Pod。
2、配置 cgroup 驅(qū)動(dòng)
kubelet 支持在主機(jī)上使用 cgroup 驅(qū)動(dòng)操作 cgroup 層次結(jié)構(gòu)。 該驅(qū)動(dòng)通過 –cgroup-driver 標(biāo)志進(jìn)行配置。
支持的參數(shù)值如下:
- cgroupfs 是默認(rèn)的驅(qū)動(dòng),在主機(jī)上直接操作 cgroup 文件系統(tǒng)以對 cgroup 沙箱進(jìn)行管理;
- systemd 是可選的驅(qū)動(dòng),使用 init 系統(tǒng)支持的資源的瞬時(shí)切片管理 cgroup 沙箱。
取決于相關(guān)容器運(yùn)行時(shí)的配置,操作員可能需要選擇一個(gè)特定的 cgroup 驅(qū)動(dòng)來保證系統(tǒng)正常運(yùn)行。 例如,如果操作員使用 containerd 運(yùn)行時(shí)提供的 systemd cgroup 驅(qū)動(dòng)時(shí), 必須配置 kubelet 使用 systemd cgroup 驅(qū)動(dòng)。
3、Kube 預(yù)留值
- Kubelet 標(biāo)志:–kube-reserved=[cpu=100m][,][memory=100Mi][,][ephemeral-storage=1Gi][,][pid=1000]
- Kubelet 標(biāo)志:–kube-reserved-cgroup=
kube-reserved 用來給諸如 kubelet、容器運(yùn)行時(shí)、節(jié)點(diǎn)問題監(jiān)測器等 Kubernetes 系統(tǒng)守護(hù)進(jìn)程記述其資源預(yù)留值。 該配置并非用來給以 Pod 形式運(yùn)行的系統(tǒng)守護(hù)進(jìn)程預(yù)留資源。kube-reserved 通常是節(jié)點(diǎn)上 Pod 密度 的函數(shù)。
除了 cpu、內(nèi)存 和 ephemeral-storage 之外,pid 可用來指定為 Kubernetes 系統(tǒng)守護(hù)進(jìn)程預(yù)留指定數(shù)量的進(jìn)程 ID。要選擇性地對 Kubernetes 系統(tǒng)守護(hù)進(jìn)程上執(zhí)行 kube-reserved 保護(hù),需要把 kubelet 的 –kube-reserved-cgroup 標(biāo)志的值設(shè)置為 kube 守護(hù)進(jìn)程的父控制組。推薦將 Kubernetes 系統(tǒng)守護(hù)進(jìn)程放置于頂級控制組之下(例如 systemd 機(jī)器上的 runtime.slice)。 理想情況下每個(gè)系統(tǒng)守護(hù)進(jìn)程都應(yīng)該在其自己的子控制組中運(yùn)行。
注意:如果 –kube-reserved-cgroup 不存在,Kubelet 將 不會 創(chuàng)建它。 如果指定了一個(gè)無效的 cgroup,Kubelet 將會無法啟動(dòng)。就 systemd cgroup 驅(qū)動(dòng)而言, 要為所定義的 cgroup 設(shè)置名稱時(shí)要遵循特定的模式: 所設(shè)置的名字應(yīng)該是為 –kube-reserved-cgroup 所給的參數(shù)值加上 .slice 后綴。
4、系統(tǒng)預(yù)留值
- Kubelet 標(biāo)志:–system-reserved=[cpu=100m][,][memory=100Mi][,][ephemeral-storage=1Gi][,][pid=1000]
- Kubelet 標(biāo)志:–system-reserved-cgroup=
system-reserved 用于為諸如 sshd、udev 等系統(tǒng)守護(hù)進(jìn)程記述其資源預(yù)留值。 system-reserved 也應(yīng)該為 kernel 預(yù)留 內(nèi)存,因?yàn)槟壳?kernel 使用的內(nèi)存并不記在 Kubernetes 的 Pod 上。 同時(shí)還推薦為用戶登錄會話預(yù)留資源(systemd 體系中的 user.slice)。
除了 cpu、內(nèi)存 和 ephemeral-storage 之外,pid 可用來指定為 Kubernetes 系統(tǒng)守護(hù)進(jìn)程預(yù)留指定數(shù)量的進(jìn)程 ID要想為系統(tǒng)守護(hù)進(jìn)程上可選地實(shí)施 system-reserved 約束,請指定 kubelet 的 –system-reserved-cgroup 標(biāo)志值為 OS 系統(tǒng)守護(hù)進(jìn)程的父級控制組推薦將 OS 系統(tǒng)守護(hù)進(jìn)程放在一個(gè)頂級控制組之下(例如 systemd 機(jī)器上的 system.slice)。
注意:如果 –system-reserved-cgroup 不存在,kubelet 不會 創(chuàng)建它。 如果指定了無效的 cgroup,kubelet 將會失敗。就 systemd cgroup 驅(qū)動(dòng)而言, 在指定 cgroup 名字時(shí)要遵循特定的模式: 該名字應(yīng)該是為 –system-reserved-cgroup 參數(shù)所設(shè)置的值加上 .slice 后綴。
5、顯式預(yù)留的CPU列表
- Kubelet 標(biāo)志: –reserved-cpus=0-3 KubeletConfiguration 標(biāo)志:reservedSystemCPUs: 0-3
reserved-cpus 旨在為操作系統(tǒng)守護(hù)程序和 Kubernetes 系統(tǒng)守護(hù)程序預(yù)留一組明確指定編號的 CPU。 reserved-cpus 適用于不打算針對 cpuset 資源為操作系統(tǒng)守護(hù)程序和 Kubernetes 系統(tǒng)守護(hù)程序定義獨(dú)立的頂級 cgroups 的系統(tǒng)。 如果 Kubelet 沒有 指定參數(shù) –system-reserved-cgroup 和 –kube-reserved-cgroup, 則 reserved-cpus 的設(shè)置將優(yōu)先于 –kube-reserved 和 –system-reserved 選項(xiàng)。
此選項(xiàng)是專門為電信/NFV 用例設(shè)計(jì)的,在這些用例中不受控制的中斷或計(jì)時(shí)器可能會影響其工作負(fù)載性能。 可以使用此選項(xiàng)為系統(tǒng)或 Kubernetes 守護(hù)程序以及中斷或計(jì)時(shí)器顯式定義 cpuset, 這樣系統(tǒng)上的其余 CPU 可以專門用于工作負(fù)載,因不受控制的中斷或計(jì)時(shí)器的影響得以降低。 要將系統(tǒng)守護(hù)程序、Kubernetes 守護(hù)程序和中斷或計(jì)時(shí)器移動(dòng)到此選項(xiàng)定義的顯式 cpuset 上,應(yīng)使用 Kubernetes 之外的其他機(jī)制。 例如:在 CentOS 系統(tǒng)中,可以使用 tuned 工具集來執(zhí)行此操作。
6、驅(qū)逐閾值
- Kubelet 標(biāo)志:–eviction-hard=[memory.available<500Mi]
節(jié)點(diǎn)級別的內(nèi)存壓力將導(dǎo)致系統(tǒng)內(nèi)存不足,這將影響到整個(gè)節(jié)點(diǎn)及其上運(yùn)行的所有 Pod。 節(jié)點(diǎn)可以暫時(shí)離線直到內(nèi)存已經(jīng)回收為止。為了防止系統(tǒng)內(nèi)存不足(或減少系統(tǒng)內(nèi)存不足的可能性), kubelet 提供了資源不足管理。 驅(qū)逐操作只支持 memory 和 ephemeral-storage。 通過 –eviction-hard 標(biāo)志預(yù)留一些內(nèi)存后,當(dāng)節(jié)點(diǎn)上的可用內(nèi)存降至預(yù)留值以下時(shí), kubelet 將嘗試驅(qū)逐 Pod。 如果節(jié)點(diǎn)上不存在系統(tǒng)守護(hù)進(jìn)程,Pod 將不能使用超過 capacity-eviction-hard 所指定的資源量。 因此,為驅(qū)逐而預(yù)留的資源對 Pod 是不可用的。
7、實(shí)施節(jié)點(diǎn)可分配約束
- Kubelet 標(biāo)志:–enforce-node-allocatable=pods[,][system-reserved][,][kube-reserved]
調(diào)度器將 ‘Allocatable’ 視為 Pod 可用的 capacity(資源容量)。
kubelet 默認(rèn)對 Pod 執(zhí)行 ‘Allocatable’ 約束。 無論何時(shí),如果所有 Pod 的總用量超過了 ‘Allocatable’,驅(qū)逐 Pod 的措施將被執(zhí)行。 可通過設(shè)置 kubelet –enforce-node-allocatable 標(biāo)志值為 pods 控制這個(gè)措施。
可選地,通過在同一標(biāo)志中同時(shí)指定 kube-reserved 和 system-reserved 值, 可以使 kubelet 強(qiáng)制實(shí)施 kube-reserved 和 system-reserved 約束。 請注意,要想執(zhí)行 kube-reserved 或者 system-reserved 約束, 需要對應(yīng)設(shè)置 –kube-reserved-cgroup 或者 –system-reserved-cgroup。
三、一般原則
系統(tǒng)守護(hù)進(jìn)程一般會被按照類似 Guaranteed 的 Pod 一樣對待。 系統(tǒng)守護(hù)進(jìn)程可以在與其對應(yīng)的控制組中出現(xiàn)突發(fā)資源用量,這一行為要作為 Kubernetes 部署的一部分進(jìn)行管理。 例如,kubelet 應(yīng)該有它自己的控制組并和容器運(yùn)行時(shí)共享 kube-reserved 資源。 不過,如果執(zhí)行了 kube-reserved 約束,則 kubelet 不可出現(xiàn)突發(fā)負(fù)載并用光節(jié)點(diǎn)的所有可用資源。
在執(zhí)行 system-reserved 預(yù)留策略時(shí)請加倍小心,因?yàn)樗赡軐?dǎo)致節(jié)點(diǎn)上的關(guān)鍵系統(tǒng)服務(wù)出現(xiàn) CPU 資源短缺、 因?yàn)閮?nèi)存不足而被終止或者無法在節(jié)點(diǎn)上創(chuàng)建進(jìn)程。 建議只有當(dāng)用戶詳盡地描述了他們的節(jié)點(diǎn)以得出精確的估計(jì)值, 并且對該組中進(jìn)程因內(nèi)存不足而被殺死時(shí),有足夠的信心將其恢復(fù)時(shí), 才可以強(qiáng)制執(zhí)行 system-reserved 策略。
- 作為起步,可以先針對 pods 上執(zhí)行 ‘Allocatable’ 約束;
- 一旦用于追蹤系統(tǒng)守護(hù)進(jìn)程的監(jiān)控和告警的機(jī)制到位,可嘗試基于用量估計(jì)的方式執(zhí)行 kube-reserved 策略;
- 隨著時(shí)間推進(jìn),在絕對必要的時(shí)候可以執(zhí)行 system-reserved 策略。
隨著時(shí)間推進(jìn)和越來越多特性被加入,kube 系統(tǒng)守護(hù)進(jìn)程對資源的需求可能也會增加。 以后 Kubernetes 項(xiàng)目將嘗試減少對節(jié)點(diǎn)系統(tǒng)守護(hù)進(jìn)程的利用,但目前這件事的優(yōu)先級并不是最高。 所以,將來的發(fā)布版本中 Allocatable 容量是有可能降低的。
四、示例
這是一個(gè)用于說明節(jié)點(diǎn)可分配(Node Allocatable)計(jì)算方式的示例:
- 節(jié)點(diǎn)擁有 32Gi memory、16 CPU 和 100Gi Storage 資源;
- –kube-reserved 被設(shè)置為 cpu=1,memory=2Gi,ephemeral-storage=1Gi;
- –system-reserved 被設(shè)置為 cpu=500m,memory=1Gi,ephemeral-storage=1Gi;
- –eviction-hard 被設(shè)置為 memory.available<500Mi,nodefs.available<10%。
在這個(gè)場景下,’Allocatable’ 將會是 14.5 CPUs、28.5Gi 內(nèi)存以及 88Gi 本地存儲。 調(diào)度器保證這個(gè)節(jié)點(diǎn)上的所有 Pod 的內(nèi)存 requests 總量不超過 28.5Gi,存儲不超過 ’88Gi’。 當(dāng) Pod 的內(nèi)存使用總量超過 28.5Gi 或者磁盤使用總量超過 88Gi 時(shí),kubelet 將會驅(qū)逐它們。 如果節(jié)點(diǎn)上的所有進(jìn)程都盡可能多地使用 CPU,則 Pod 加起來不能使用超過 14.5 CPUs 的資源。
當(dāng)沒有執(zhí)行 kube-reserved 和/或 system-reserved 策略且系統(tǒng)守護(hù)進(jìn)程使用量超過其預(yù)留時(shí), 如果節(jié)點(diǎn)內(nèi)存用量高于 31.5Gi 或 storage 大于 90Gi,kubelet 將會驅(qū)逐 Pod。