💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] 节点压力驱逐是 kubelet 主动终止 Pod 以回收节点上资源的过程。kubelet 监控集群节点的 CPU、内存、磁盘空间和文件系统的 inode 等资源。 当这些资源中的一个或者多个达到特定的消耗水平, kubelet 可以主动地使节点上一个或者多个 Pod 失效,以回收资源防止资源不足。 kubelet中有几个参数,通过这几个参数可以为系统进程预留资源,不至于pod把计算资源耗尽,而导致系统操作都无法正常进行。 ```shell --enforce-node-allocatable --system-reserved --system-reserved-cgroup --kube-reserved --kube-reserved-cgroup --eviction-hard ``` 在kubernetes 1.6版本后,引入了Node的Allocatable特性,通过该特性我们可以控制每个节点可分配的资源。 ![01](https://img.kancloud.cn/7d/48/7d48aafb660cb81ee02c5cf471f472e8_505x370.png) Kubernetes 节点上的 'Allocatable' 被定义为 pod 可用计算资源量。 调度器不会超额申请 'Allocatable'。 目前支持 'CPU', 'memory' 和 'ephemeral-storage' 这几个参数。 Capacity是指Node的容量,allocatable的值为 `allocatable = capacity - kube_reserved - system_reserved - eviction_threshhold` 当kubelet启动后,Node的allocatable就是固定的,不会因为pod的创建与销毁而改变。 ## allocatable、 requests 和 limits 三者关系 在pod的yaml文件中,我们可以为pod设置requests与limits。其中limits与allocatable没有什么关系。但requests与allocatable关系紧密。调度到某个节点上的Pod的requests总和不能超过该节点的allocatable。limits的总和没有上限。 比如某个节点的内存的allocatable为10Gi,有三个Pod(requests.memory=3Gi)已经调度到该节点上,那么第4个Pod就无法调度到该节点上,即使该Node上的空闲内存大于3Gi。 ## 系统资源预留 系统资源预留分为两种`不设cgroup` 和 `设置cgroup`。 - 不设cgroup:Pod使用的资源上限不会超过allocatable,如超过则被系统oom掉。系统使用资源超过kube-reserved和system-reserved阈值。可以使用allocatable的资源 - 设置cgroup:Pod使用的资源上限还是不会超过allocatable。但是系统使用资源超过kube-reserved和system-reserved阈值的话,会被cgroup杀掉。所以推荐使用第一种。 ### 不设cgroup 假设我们现在需要为系统预留一定的资源,那么我们可以配置如下的kubelet参数(在这里不设置对应的cgroup参数): ```shell --enforce-node-allocatable=pods --kube-reserved=memory=... --system-reserved=memory=... --eviction-hard=... ``` 1. 设置kubelet参数 这里的设置是将kubelet的配置写在配置文件中,使用`--config` 的参数指定配置文件即可。上面的参数设置会在某个版本移除。官方推荐将配置写在文件中 ```yaml enforceNodeAllocatable: ["pods"] systemReserved: cpu: 1000m memory: 500Mi kubeReserved: cpu: 1000m memory: 500Mi evictionHard: memory.available: 10% imagefs.available: 10% imagefs.inodesFree: 10% nodefs.available: 10% nodefs.inodesFree: 10% ``` 2. 查看capacity及allocatable 查看到Node的capacity及allocatable的值如下: ```shell $ kubectl describe node k8s-master01 ... Capacity: cpu: 8 ephemeral-storage: 40940Mi hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 3861512Ki pods: 100 Allocatable: cpu: 6 ephemeral-storage: 36635831233 hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 2510193454 pods: 100 ``` 以内存为例,可以计算出allocatable的值,刚好与上面的一致: ```shell allocatable = capacity - kube_reserved - system_reserved - eviction_threshhold 2510193454/1024Ki = 3861512Ki - 500*1024Ki - 500*1024Ki - 3861512*10%Ki ``` 3. 查看kubepods控制组 查看kubepods控制组中对内存的限制,该值决定了Node上所有的Pod能使用的资源上限: ```shell $ cat /sys/fs/cgroup/memory/kubepods.slice/memory.limit_in_bytes 2905612288 ``` 2905612288Bytes = 2837512Ki = Allocatable + 1000Mi 根据上面的计算可知,Node上Pod能实际使用的资源上限值为: ```shell kubepods/memory.limit_in_bytes = capacity - kube_reserved - system_reserved ``` **注意:根据上面的公式,我们可以知道,一个节点上所有Pod能使用的内存总和,与eviction-hard无关** ### 设置cgroup 假设我们现在需要为系统预留一定的资源,那么我们可以配置如下的kubelet参数(在这里设置对应的cgroup参数): ```shell --enforce-node-allocatable=pods,kube-reserved,system-reserved --kube-reserved=memory=... --kube-reserved-cgroup=... --system-reserved=memory=... --system-reserved-cgroup=... --eviction-hard=.. ``` 如果还设置了对应的 --system-reserved-cgroup 和 --kube-reserved-cgroup参数,Pod能实际使用的资源上限不会改变(即kubepods.limit_in_bytes不变),但系统进程与kube进程也会受到资源上限的限制。如果系统进程超过了预留资源,那么系统进程会被cgroup杀掉。 但是如果不设这两个参数,那么系统进程可以使用超过预留的资源上限。 ## 配置建议 ```shell --enforce-node-allocatable=pods --kube-reserved=cpu=xx,memory=xx,ephemeral-storage=xx --system-reserved=cpu=xx,memory=xx,ephemeral-storage=xx --eviction-hard=memory.available<10%,nodefs.available<10% ``` 一般来说,我们不希望资源的使用率超过70%,所以kube-reserved、system-reserved、eviction-hard都应该设为10%。但由于kube-reserved与system-reserved不能设置百分比,所以它们要设置为绝对值。 ## 总结 1. Node的allocatable在kubelet启动后是一个固定的值,不会因为pod的创建与删除而改变 2. 当我们为Pod设置了resources.requests时,调度到Node上的Pod的resources.requests的总和不会超过Node的allocatable。但Pod的resources.limits总和可以超过Node的allocatable 3. 一个Pod能否成功调度到某个Node,关键看该Pod的resources.request是否小于Node剩下的request,而不是看Node实际的资源空闲量。即使空闲资源小于Pod的requests,Pod也可以调度到该Node上 4. 当Pod的内存资源实际使用量超过其limits时,docker(实际是cgroup)会把该Pod内超出限额的进程杀掉(OOM);如果CPU超过,不会杀掉进程,只是进程会一直等待CPU。 5. allocatable与kubepods.limit的值不一样,它们之间相差一个 eviction_hard 6. 当我们不设置cgroup时,可以达到为系统预留资源的效果,即Pod的资源实际使用量不会超过allocatable的值(因为kubepods控制组中memory.limit_in_bytes的值就为allocatable的值)。即使系统本身没有使用完预留的那部分资源,Pod也无法使用。当系统超出了预留的那部分资源时,系统进程可以抢占allocatable中的资源,即对系统使用的资源没有限制。 7. 当我们设置了cgroup参数,还设置了对应的cgroup时(如下),那么除了Pod使用的资源上限不会超过allocatable外,系统使用的资源上限也不会超过预留资源。当系统进程超过预留资源时,系统进程也会被cgroup杀掉。所以推荐使用上面的设置方法 ## 参考 https://kubernetes.io/zh/docs/tasks/administer-cluster/out-of-resource/ https://kubernetes.io/zh/docs/concepts/scheduling-eviction/node-pressure-eviction/