在kubernetes中,每个POD都有个QoS标记,通过这个Qos标记来对POD进行服务质量管理。QoS的英文全称为"Quality of Service",中文名为"服务质量",它取决于用户对服务质量的预期,也就是期望的服务质量。对于POD来说,服务质量体现在两个指标上,一个指标是CPU,另一个指标是内存。在实际运行过程中,当NODE节点上内存资源紧张的时候,kubernetes根据POD具有的不同QoS标记,采取不同的处理策略。
在Kubernetes中,POD的QoS服务质量一共有三个级别,如下图所示:
这三个QoS级别介绍,可以看下面表格:
QoS级别 |
QoS介绍 |
BestEffort |
POD中的所有容器都没有指定CPU和内存的requests和limits,那么这个POD的QoS就是BestEffort级别 |
Burstable |
POD中只要有一个容器,这个容器requests和limits的设置同其他容器设置的不一致,那么这个POD的QoS就是Burstable级别 |
Guaranteed |
POD中所有容器都必须统一设置了limits,并且设置参数都一致,如果有一个容器要设置requests,那么所有容器都要设置,并设置参数同limits一致,那么这个POD的QoS就是Guaranteed级别 |
为了更清楚的了解这三个QoS级别,下面我们举例说明。
QoS级别 |
QoS配置例子 |
BestEffort |
containers: name: foo resources: name: bar resources: |
Burstable |
containers: name: foo resources: limits: cpu: 10m memory: 1Gi requests: cpu: 10m memory: 1Gi
name: bar |
containers: name: foo resources: limits: memory: 1Gi
name: bar resources: limits: cpu: 100m |
|
containers: name: foo resources: requests: cpu: 10m memory: 1Gi
name: bar |
|
Guaranteed |
containers: name: foo resources: limits: cpu: 10m memory: 1Gi name: bar resources: limits: cpu: 100m memory: 100Mi |
containers: name: foo resources: limits: cpu: 10m memory: 1Gi requests: cpu: 10m memory: 1Gi
name: bar resources: limits: cpu: 100m memory: 100Mi requests: cpu: 10m memory: 1Gi |
QoS级别决定了kubernetes处理这些POD的方式,我们以内存资源为例:
1、当NODE节点上内存资源不够的时候,QoS级别是BestEffort的POD会最先被kill掉;当NODE节点上内存资源充足的时候,QoS级别是BestEffort的POD可以使用NODE节点上剩余的所有内存资源。
2、当NODE节点上内存资源不够的时候,如果QoS级别是BestEffort的POD已经都被kill掉了,那么会查找QoS级别是Burstable的POD,并且这些POD使用的内存已经超出了requests设置的内存值,这些被找到的POD会被kill掉;当NODE节点上内存资源充足的时候,QoS级别是Burstable的POD会按照requests和limits的设置来使用。
3、当NODE节点上内存资源不够的时候,如果QoS级别是BestEffort和Burstable的POD都已经被kill掉了,那么会查找QoS级别是Guaranteed的POD,并且这些POD使用的内存已经超出了limits设置的内存值,这些被找到的POD会被kill掉;当NODE节点上内存资源充足的时候,QoS级别是Burstable的POD会按照requests和limits的设置来使用。
从容器的角度出发,为了限制容器使用的CPU和内存,是通过cgroup来实现的,目前kubernetes的QoS只能管理CPU和内存,所以kubernetes现在也是通过对cgroup的配置来实现QoS管理的。
我们简单来介绍下cgroup:
1、来源:
cgroups(Control Groups)最初叫ProcessContainer,由Google工程师(Paul Menage和Rohit Seth)于2006年提出,后来因为Container有多重含义容易引起误解,就在2007年更名为Control Groups,并被整合进Linux内核。顾名思义就是把进程放到一个组里面统一加以控制。
2、官方定义:
cgroups是Linux内核提供的一种机制,这种机制可以根据特定的行为,把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。
3、作用:
资源限制(Resource Limitation):cgroups可以对进程组使用的资源总额进行限制。如设定应用运行时使用内存的上限,一旦超过这个配额就发出OOM(Out of Memory)。
优先级分配(Prioritization):通过分配的CPU时间片数量及硬盘IO带宽大小,实际上就相当于控制了进程运行的优先级。
资源统计(Accounting): cgroups可以统计系统的资源使用量,如CPU使用时长、内存用量等等,这个功能非常适用于计费。
进程控制(Control):cgroups可以对进程组执行挂起、恢复等操作。
4、特点:
cgroups的API以一个伪文件系统的方式实现,即用户可以通过文件操作实现cgroups的组织管理。
cgroups的组织管理操作单元可以细粒度到线程级别,用户态代码也可以针对系统分配的资源创建和销毁cgroups,从而实现资源再分配和管理。
所有资源管理的功能都以“ subsystem(子系统)”的方式实现,接口统一。
子进程创建之初与其父进程处于同一个cgroups的控制组。
5、本质:
本质上来说,cgroups是内核附加在程序上的一系列钩子(hooks),通过程序运行时对资源的调度触发相应的钩子以达到资源追踪和限制的目的。
6、cgroups术语
task(任务):cgroups的术语中,task就表示系统的一个进程。
cgroup(控制组):cgroups 中的资源控制都以cgroup为单位实现。cgroup表示按某种资源控制标准划分而成的任务组,包含一个或多个子系统。一个任务可以加入某个cgroup,也可以从某个cgroup迁移到另外一个cgroup。
subsystem(子系统):cgroups中的subsystem就是一个资源调度控制器(ResourceController)。比如CPU子系统可以控制CPU时间分配,内存子系统可以限制cgroup内存使用量。
hierarchy(层级树):hierarchy由一系列cgroup以一个树状结构排列而成,每个hierarchy通过绑定对应的subsystem进行资源调度。hierarchy中的cgroup节点可以包含零或多个子节点,子节点继承父节点的属性。整个系统可以有多个hierarchy。
在kubernetes中,我们可以看看POD配置中的requests和limits参数是如何同cgroup建立关联关系,进而实现对POD的资源QoS管理的。
QoS级别 |
QoS配置例子 |
cgroup对应 |
Guaranteed |
kind: Pod metadata: name: Pod1 spec: containers: name: foo resources: limits: cpu: 10m memory: 1Gi name: bar resources: limits: cpu: 100m memory: 2Gi |
/Pod1/cpu.quota = 110m /Pod1/cpu.shares = 110m /Pod2/cpu.quota = 20m /Pod2/cpu.shares = 20m /Pod1/memory.limit_in_bytes = 3Gi /Pod2/memory.limit_in_bytes = 2Gi |
kind: Pod metadata: name: Pod2 spec: containers: name: foo resources: limits: cpu: 20m memory: 2Gi |
||
Burstable |
kind: Pod metadata: name: Pod3 spec: containers: name: foo resources: limits: cpu: 50m memory: 2Gi requests: cpu: 20m memory: 1Gi name: bar resources: limits: cpu: 100m memory: 1Gi |
/Bu/cpu.shares = 30m /Bu/Pod3/cpu.quota = 150m /Bu/Pod3/cpu.shares = 20m /Bu/Pod4/cpu.quota = 20m /Bu/Pod4/cpu.shares = 10m /Bu/memory.limit_in_bytes = Allocatable - 5Gi /Bu/Pod3/memory.limit_in_bytes = 3Gi /Bu/Pod4/memory.limit_in_bytes = 2Gi |
|
kind: Pod metadata: name: Pod4 spec: containers: name: foo resources: limits: cpu: 20m memory: 2Gi requests: cpu: 10m memory: 1Gi |
|
BestEffort |
kind: Pod metadata: name: Pod5 spec: containers: name: foo resources: name: bar resources: |
/BE/cpu.shares = 2 /BE/cpu.quota= not set /BE/memory.limit_in_bytes = Allocatable - 7Gi /BE/Pod5/memory.limit_in_bytes = no limit |
我们知道了cgroups里面有hierarchy(层级树)的概念,那么我们来看在kubernetes里面是如何把POD放在hierarchy(层级树)上面的:
对于kubernetes来说,通过cgroup就可以给POD设置QoS级别,当资源不够使用时,先kill优先级低的POD,在实际使用时,是通过OOM(Out of Memory)分数值来实现的,OOM分数值从0到1000。OOM分数值是根据OOM_ADJ参数计算出来的,对于Guaranteed级别的POD,OOM_ADJ参数设置成了-998,对于BestEffort级别的POD,OOM_ADJ参数设置成了1000,对于Burstable级别的POD,OOM_ADJ参数取值从2到999,对于kube保留的资源,比如kubelet,OOM_ADJ参数设置成了-999。OOM_ADJ参数设置的越大,通过OOM_ADJ参数计算出来的OOM分数越高,OOM分数越高,这个POD的优先级就越低,在出现资源竞争的时候,就越早被kill掉,对于OOM_ADJ参数是-999的代表kubernetes永远不会因为OOM而被kill掉。如下图所示:
来源:oschina
链接:https://my.oschina.net/u/866802/blog/1797092