Kubernetes 的系统资源分为可压缩资源(CPU)和不可压缩资源(memory、storage)。默认情况下,kubelet 没有做资源预留限制,这样节点上的所有资源都能被 Pod 使用。若节点上的 pod 负载较大,会引发一系列问题。本文介绍了针对该问题 Kubernetes 提供的 kubelet 的 Node Allocatable 特性。
背景简介
Kubernetes 的系统资源分为可压缩资源(CPU)和不可压缩资源(memory、storage)。可压缩资源(比如 CPU)在系统满负荷时会划分时间片分时运行进程,通常情况下系统整体会变慢;不可压缩资源(如 Memory)在系统满负荷时,严重时会导致某些进程被系统 OOM killer 机制杀掉。
默认情况下,kubelet 没有做资源预留限制,这样节点上的所有资源都能被 Pod 使用。若节点上的 pod 负载较大,这些 pod 可能会与节点上的系统守护进程和 k8s 组件争夺资源,严重时甚至会引发系统 OOM 而杀掉一些进程。若被杀掉的进程是系统进程或 K8S 组件,可能导致更严重的问题,甚至会导致集群的雪崩。
针对这种问题,kubernetes 提供了 kubelet 的 Node Allocatable 特性,为系统进程和 k8s 组件预留资源。
资源预留
1 Node Allocatable
kubelet 的启动配置中有一个 Node Allocatable 特性,来为系统守护进程和 k8s 组件预留计算资源,使得即使节点满负载运行时,也不至于出现 pod 去和系统守护进程以及 k8s 组件争抢资源,导致节点挂掉的情况。目前支持对 CPU, memory, ephemeral-storage 三种资源进行预留。kubernetes 官方建议根据各个节点的负载情况来具体配置相关参数。
节点计算资源的分配如下图所示:
其中各个部分的含义如下:
Node Capacity:Node 的硬件资源总量;
kube-reserved:为 k8s 系统进程预留的资源(包括 kubelet、container runtime 等,不包括以 pod 形式的资源);
system-reserved:为 linux 系统守护进程预留的资源;
eviction-threshold:通过–eviction-hard 参数为节点预留内存;
allocatable:可供节点上 Pod 使用的容量,kube-scheduler 调度 Pod 时的参考此值。
从公式可以看出,默认情况下(不设置 kube-reserved、system-reserved、eviction-threshold)节点上提供给 Pod 使用的资源总量等于节点的总容量。
2 参数含义及配置
Kubelet Node Allocatable 的代码比较简单,主要在 pkg/kubelet/cm/node_container_manager.go,感兴趣的同学可以看一下。以下是相关配置参数:
–enforce-node-allocatable,默认为 pods(默认情况下,kubelet 会为所有 pod 的总 cgroup 做资源限制,限制为公式计算出的 allocatable 的大小)。要为 kube 组件和 System 进程预留资源,则需要设置为 pods,kube-reserved,system-reserve,同时还要分别加上–kube-reserved-cgroup 和–system-reserved-cgroup 以指定分别限制在哪个 cgroup 里;
–cgroups-per-qos,Enabling QoS and Pod level cgroups,默认开启。开启后,kubelet 会将管理所有 workload Pods 的 cgroups;
–cgroup-driver,默认为 cgroupfs,另一可选项为 systemd。取决于容器运行时使用的 cgroup driver,kubelet 与其保持一致;
–kube-reserved,用于配置为 kube 组件(kubelet,kube-proxy,dockerd 等)预留的资源量,比如—kube-reserved=cpu=2000m,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=2000m,memory=4Gi,ephemeral-storage=8Gi;
–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 到此节点。
配置与验证
针对 pod、system、kube 均做 cgroup 级别限制,需要进行以下配置:
为 system.slice、kubelet.service 创建 cpuset 子系统:未创建前 system.slice 这个 cgroup 是没有 cpuset 子系统的,而 kubelet(1.9)启动时会去查看这些 cgroup 子系统是否存在,如果不存在会报相应的 cgroup 错误。
重启 kubelet 后,可以验证(以内存为例):
通过公式计算、节点实际 capacity 及 allocatable 的值(kubectl describe node xxx)、 kubepods 控制组中对内存的限制值(/sys/fs/cgroup/memory/kubepods/memory.limit_in_bytes)均与预期相符。
并且 system.slice(/sys/fs/cgroup/memory/system.slice/memory.limit_in_bytes)、kubelet.service(/sys/fs/cgroup/memory/system.slice/kubelet.service/memory.limit_in_bytes)控制组对内存的限制值也与预期相符。
最佳实践
生产环境中,建议同时限制 pod、k8s 系统组件、linux system 进程资源,以免任一类资源负载过高影响其他组件,甚至造成雪崩;
针对 daemonset 创建出来的系统级别 pod,建议为其配置 Guaranteed 的服务质量等级。
本文转载自公众号 360 云计算(ID:hulktalk)。
原文链接:
https://mp.weixin.qq.com/s/CmHok-9gKVrHfiXpYUQ4nw
评论