当前位置: 首页 > 科技观察

kubelet配置资源预留的姿势

时间:2023-03-13 12:20:41 科技观察

Kubernetes节点可以根据节点的资源容量进行调度。默认情况下,Pod可以使用节点的全部可用容量。这会产生一个问题,因为节点本身通常会运行许多驱动操作系统和Kubernetes的系统守护进程。除非为这些系统守护进程预留资源,否则它们将与Pod竞争并导致节点资源匮乏问题。当我们在线使用Kubernetes集群时,如果节点配置没有正确的资源预留,我们可以考虑这样一种场景,应用程序无限制地使用节点的CPU资源,导致节点上的CPU使用率持续运行在100%。而且kubelet组件的CPU占用被压榨,会导致kubelet和apiserver的心跳出现问题,节点会出现NotReady状态。默认情况下,节点NotReady后,应用会在5分钟后被驱逐到其他节点。当这个应用程序运行到其他节点时,它也会使用100%的CPU。这个节点也会挂掉吗?同样的情况继续下去,会导致整个集群雪崩。集群中的节点没有一个一个就绪。后果非常严重。或多或少的人都遇到过Kubernetes集群的雪崩。采访中也反映了这个问题。问问题。为了解决这个问题,需要为Kubernetes集群配置资源预留。Kubelet暴露了一个名为NodeAllocatable的特性,它有助于为系统守护进程预留计算资源。Kubernetes还建议集群管理员按照每个节点Load上的工作来配置NodeAllocatable。本文运行环境为Kubernetesv1.22.1版本。在使用Containerd的containerruntime时,Containerd和Kubelet使用的cgroupdriver是systemd。NodeAllocatableKubernetes节点上的Allocatable定义为Pod可用的计算资源量,调度器不会超额订阅Allocatable。目前,支持参数CPU、内存和临时存储。我们可以使用kubectldescribenode命令查看节点可分配资源的数据:?~kubectldescribenodenode2......Capacity:cpu:4ephemeral-storage:36678148Kihugepages-1Gi:0hugepages-2Mi:0memory:7990056Kipods:110Allocatable:cpu:4ephemeral-storage:33802581141hugepages-1Gi:0hugepages-2Mi:0memory:7887656Kipods:110...可以看到有两项:Capacity和Allocatable,Allocatable是节点可以分配的资源。我们这里没有配置资源预留。所以默认情况下Capacity和Allocatable的值基本一致。下图展示了可分配资源和资源预留的关系:NodeAllocatableKubeletNodeAllocatable用于为Kube组件和System进程预留资源,保证节点满载时Kube和System进程有足够的资源H.目前支持cpu、memory、ephemeral-storage三种资源预留。NodeCapacity是节点的所有硬件资源,kube-reserved是为kube组件预留的资源,system-reserved是为系统进程预留的资源,eviction-threshold是kubelet驱逐的阈值设置,allocatable是真正的scheduler调度Pod时的参考值(保证节点上所有Pod的请求资源不超过Allocatable)。节点可分配资源的计算方法为:NodeAllocatableResource=NodeCapacity-Kube-reserved-system-reserved-eviction-threshold调度到某个节点的Pod的请求总和不能超过该节点的可分配量。配置资源预留例如我们现在需要为系统预留一定的资源,我们可以使用如下kubelet参数进行配置:--enforce-node-allocatable=pods--kube-reserved=memory=...---system-reserved=memory=...--eviction-hard=...这里我们暂时不设置对应的cgroup,比如我们只给node2添加资源预留,我们可以直接修改/var/lib/kubelet/config.yaml文件动态配置kubelet,添加如下资源预留配置:apiVersion:kubelet.config.k8s.io/v1beta1......enforceNodeAllocatable:-podskubeReserved:#Configurekuberesourcereservationcpu:500mmemory:1Giephemeral-storage:1GisystemReserved:#配置系统资源预留memory:1GievictionHard:#配置硬驱逐阈值memory.available:"300Mi"nodefs.available:"10%"修改完成后重启kubelet,启动后重启完成比较Capacity和Allocatabl的值e:?~kubectldescribenodenode2......容量:cpu:4ephemeral-storage:36678148Kihugepages-1Gi:0hugepages-2Mi:0memory:7990056Kipods:110Allocatable:cpu:3500mephemeral-storage:32728888gephuge3age93Kipo151505s内存:2Mipo151505s比较可知Allocatable的值就是Capacity减去我们上面配置的预留资源的值:allocationale=capacity-kube_reserved-system_reserved-eviction_hard55??85704Ki=7990056Ki-1*1024*1024Ki-1*1024*1024Ki-300*1024Ki然后通过查看kubepods.slice(systemd驱动以.slice结尾)对cgroup中节点上所有Pod内存的限制,这个值决定了所有Pod上Node可以使用的资源上限:?~cat/sys/fs/cgroup/memory/kubepods.slice/memory.limit_in_bytes6034333696Pod资源使用上限为:6034333696Bytes=5892904Ki=Allocatable(5585704Ki)+eviction_hard(300*1024Ki))也可以计算验证我们的配置是否正确:kubepods.slice/memory.limit_in_bytes=capacity-kube_reserved-system_reservedEviction和OOM1,eviction是指kubelet驱逐节点上的Pod,OOM是指cgroup杀死进程2,kubelet杀死进程Pod的驱逐是基于--eviction-hard参数。例如,如果参数设置为memory.available<20%,那么当宿主机的内存使用率达到80%时,kubelet将驱逐该Pod。但是--eviction-hard=memory.available<20%不会影响/sys/fs/cgroup/memory/kubepods.slice/memory.limit_in_bytes的值,因为kubepods.slice/memory.limit_in_bytes=capacity-kube-reserved-system-reserved也就是Pod的总内存使用率可以超过80%,不会OOM-killed,只会被驱逐。3、kubernetes的pod驱逐机制如下(其实就是QoS章节的定义):首先驱逐没有资源限制的pod,然后驱逐资源上限和资源下限不同的pod,最后驱逐具有较低资源限制(例如资源上限)的pod将被驱逐。我们在配置资源预留的时候,有一个enforceNodeAllocatable配置项(--enforce-node-allocatable),其帮助信息为:--enforce-node-allocatablestringsAcommaseparatedlistoflevelsofnodeallocatableenforcementtobeenforcedbykubelet.Acceptableoptionsare'none','pods','system-reserved',和'kube-reserved'。如果指定了后两个选项,则还必须分别设置“--system-reserved-cgroup”和“--kube-reserved-cgroup”。如果指定了“无”,则不应设置其他选项。请参阅https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/formoredetails。(默认[pods])(已弃用:应通过Kubelet的--config指定的配置文件设置此参数标志。参见https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/fororeinformation。)Kubelet默认在Pod上实现Allocatable分配约束。如果所有Pod的总使用量超过Allocatable,将实施驱逐Pod的措施。我们可以设置kubelet--enforce-node-aLlocatable标志值控制pod的此度量。另外,我们还可以通过这个flag同时指定kube-reserved和system-reserved的值,让kubelet强制执行kube-reserved和system-reserved的约束。但是需要注意的是,如果kube-reserved配置了Reserved或者system-reserved约束,那么需要相应地设置--kube-reserved-cgroup或者--system-reserved-cgroup参数。如果设置了对应的--system-reserved-cgroup和--kube-reserved-cgroup参数,Pod实际可以使用的资源上限不会改变,但是system进程和kube进程也会受到上限的限制资源的限制。如果系统进程超过预留资源,系统进程会被cgroup杀死。但是如果不设置这两个参数,那么系统进程可以使用超过预留的资源上限。所以如果要配置cgroups做systemreservation和kubereservation,需要非常小心。如果强制执行kube-reserved约束,那么kubelet不能在突然加载时用完所有可用资源,否则它会被杀死。system-reserved可以用来为sshd、udev等系统守护进程争取资源预留,但是如果强制执行system-reserved约束,节点上的关键系统服务可能会因为某种原因耗尽CPU资源或者由于某些原因而阻塞内存不足。终止,所以如果不是很清楚怎么配置的话,最好不要配置cgroupconstraints。如需自行配置,可参考第一期资源预留文档进行相关操作。因此,我们强烈建议用户默认使用enforce-node-allocatable配置的pod,并为system和kube进程预留适当的资源,以维护整体节点的可靠性。不需要cgroup约束,除非运营商指定系统非常了解。