系统资源可分为两类:可压缩资源(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组件,会导致比较严重的问题。
针对这种问题,主要有两种解决方案(两种也可以结合使用):
启用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特性,来为系统守护进程和k8s组件预留计算资源,使得即使节点满负载运行时,也不至于出现pod去和系统守护进程以及k8s组件争抢资源,导致节点挂掉的情况。kubernetes官方建议根据各个节点的负载情况来具体配置相关参数。
Node Allocatable Resource = Node Capacity - Kube-reserved - system-reserved - eviction-threshold
pods,kube-reserved,system-reserve
。pkg/kubelet/cm/node_container_manager.go
,感兴趣的同学自己去走读一遍。
根据是否对system和kube做cgroup上的硬限制进行划分,资源预留主要有两种方式:
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: 8
memory: 32930152Ki(约31.4G)
pods: 110
Allocatable:
cpu: 6
memory: 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,与实际一致。
配置过程
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
/sys/fs/cgroup/devices/system.slice/kubelet.service
/sys/fs/cgroup/memory/system.slice/kubelet.service
/sys/fs/cgroup/blkio/system.slice/kubelet.service
/sys/fs/cgroup/cpu,cpuacct/system.slice/kubelet.service
/sys/fs/cgroup/systemd/system.slice/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