Kubernetes为用户提供了基础设施能力,包含了应用定义 资源管理和调度

而作为Kubernets的资源模型,Pod是如何进行调度的,而Pod中最重要的调度,就是Pod和CPU和内存配置,如下所示

apiVersion: v1

kind: Pod

metadata:

name: frontend

spec:

containers:

– name: db

image: mysql

env:

– name: MYSQL_ROOT_PASSWORD

value: “password”

resources:

requests:

memory: “64Mi”

cpu: “250m”

limits:

memory: “128Mi”

cpu: “500m”

– name: wp

image: wordpress

resources:

requests:

memory: “64Mi”

cpu: “250m”

limits:

memory: “128Mi”

cpu: “500m”

在这个Pod中,定义了Container的CPU和Memory,而在Kubernetes中,CPU这样的资源被称为可压缩资源,这种可压缩资源不足的时候,Pod只会饥饿,不会退出

内存这样资源,是不可压缩资源,不可压缩资源不足的时候,Pod就会因OOM而被内核杀掉

Pod交由多个Container组成,CPU和内存资源的限额,要直接给予Container定义,Pod整体的资源配置,就交由这些Container配置累加得到

其中,Kubernetes的CPU的单位是CPU的个数,cpu=1就是一个1个CPU的含义,而具体是什么,vCPU还是CPU,就取决于宿主机的CPU实现方式,然后还可以设置CPU的个数为分数,比如CPU limits的值就是500m,就是500millicpu,就是0.5个CPU的意思,这样,就会分配一个CPU一半的计算能力

也可以直接写成CPU=0.5,但是毕竟不推荐,还是直接写为500m的写法,才是通用的CPU表示方式,对于内存,则是直接支持Ei, Pi, Ti,Gi,Mi,Ki 等级别进行划分

最后就是在上面声明的limits和request两种情况

对于limits,是在设置Cgroups限制的时候,进行设置的

对于request,是在kube-scheduler进行计算时候使用的

如果指定了request.cpu=250m时候,就会将Cgroups的cpu.shares的值设置为(250/1000)*1024.没设置则默认分配计算为1024,这就是完成了CPU的分配

如果指定了limits.cpu=500m,就相当于将Cgroups的cpu.cfs_quota_us设置为(500/1000)*100ms,而cpu.cfs_period_us始终为100ms,这样,Kubernetes设置为使用CPU的50%

而对于内存来说,也是如此,设置limits,就是设置Cgroups的memory.limit_in_bytes

这个limit和request的设计,参考了Borg论文中对于动态资源边界的定义,容器化作业在提交时候设置的资源边界,并不一定是调度系统所严格遵守的,而是在实际的场景中,大多数的作业使用的资源往往不会达到规定的限额

基于这种假设,Borg在作业提交后,会先减少资源配额,以便于容纳更多的作业,提交资源利用率,当作业资源使用量增大到一定的阈值时候,Borg会通过快速回复的过程,还原作业原始的资源配额,避免出现异常

这就是为何,Kubernetes在上面过程中,声明了request和limit的原因

然后呢,根据limit和request的划分的不同,会有着不同的Qos级别

如果一个Container既设置了request和limits,并且request和limits的值相等的时候,Pod就属于Guaranteed级别了,如下所示

apiVersion: v1

kind: Pod

metadata:

name: qos-demo

namespace: qos-example

spec:

containers:

– name: qos-demo-ctr

image: nginx

resources:

limits:

memory: “200Mi”

cpu: “700m”

requests:

memory: “200Mi”

cpu: “700m”

这样,这个Pod创建之后,qosClass字段就被Kubernetes设置为Guaranteed

如果值设置了limit没有request,则也会设置一个和limits相同的requests值,这也属于Guaranteed的情况

当这个Pod不满足Guaranteed的条件,其中有一个Container设置了不同的requests,那么这个Pod不会被分为Burstables类别

而一个Pod中的Container,既没有设置request,也没有设置limits,那么对应的Qos类别就是BestEffort

至于为何会有这三种Qos类别,其作用场景在于,当宿主机资源紧张的时候,kubelet对Pod进行Eviction时候使用到的

当Kubernetes所管理的宿主机上的不可压缩资源短缺的时候,就可能触发Eviction,比如内存,磁盘空间等

默认的触发Eviction阈值如下

memory.available<100Mi

nodefs.available<10%

nodefs.inodesFree<5%

imagefs.available<15%

当然是可以配比的

而且Eviction在kubernetes中分为了soft和hard两种模式,在soft模式中,可以为Eviction设置一段优雅时间,上面的设置了imagefs.available=2m,就意味着当imagefs不足阈值达到2分钟后,kubelet才会Eviction过程

Hard模式则是,Eviction过程在阈值达到后就会开始

然后Eviction发生了,Kubelet会挑选哪些Pod进行删除,就是根据的Qos类别

首当其冲的是BestEffort类别的Pod

其次是Burstable类别,并且饥饿的资源使用量已经超过了requestde jibie

最后才是Guaranteed类别,保证只有当Guaranteed类别的Pod使用量超过了limits的限制,宿主机本身处于Memory Pressure状态,才会进行Evicition操作

对于相同Qos类别的Pod来说,还有更加一步的优先级判断

而且,在QOS调用中,还有着cpuset的设置,就是可以通过设置将容器绑定在某几个特定的CPU核上,大幅的提升引用性能,毕竟不用切换上下文了

这也是,生产环境部署Pod时候常见的一种方式

我们只需要配置一下

将Pod设置为Guaranteed的Qos类型

然后将Pod的CPU资源的request和limits设置为一个相同的整数值即可

这样,就会被绑定到了独占的CPU核上,至于是哪个核上,是由kubelet分配的

那么总结一下,我们说了一下Kubernetes中关于资源定义的方式和资源模式的设计,然后Kubernetes中对Pod进行Eviction的具体策略和实践方式

所以,对于DaemonSet和一些重要的追寻稳定的Pod都设置为Guarnteed的Qos类型.

思考题

为何进入了MemoryPressure或者DiskPressure状态后,新的Pod就不会调度到这个宿主机上呢?

给宿主机打了污点标记

发表评论

邮箱地址不会被公开。 必填项已用*标注