在k8s上,可由容器或pod请求或消费的计算资源时指cpu和内存,这也是目前仅有的受支持的两种类型。相比较来说,cpu属于可压缩资源,即资源额度可按需收缩,而内存则是不可压缩型资源,对其执行收缩操作可能会导致某种程度的问题。
目前来说,资源隔离尚且属于容器级别,cpu和内存资源的配置需要在pod中的容器上运行,每种资源均可由request属性定义其请求的确保可用值,即容器运行可能用不到这些额度的资源,但用到的时候必须要确保有如此多的资源可用,而limits属性则用于吸纳子资源可用的最大值,即硬限制。通常把资源配置称作pod资源的请求和限制,只不过它是pod内所有容器上某种类型资源的请求和限制的总和。
在k8s系统上,1个单位的cpu相当于虚拟机上的1颗cpu(vcpu)或物理机上的一个超线程或逻辑cpu,它支持分数计量方式,一个核心相当于1000个微核心,因此500m相当于是0.5个核心,内存的计量方式与日常使用方式相同,默认单位是字节,也可以使用E、P、T、G、M和K作为单位后缀。
一、资源需求
自主式pod要求为stress容器确保128M的内存及五分之一个cpu核心资源可用,它运行stress-ng镜像启动一个进程进行内存性能压力测试,满载测试时它也会尽可能多地占用cpu资源,另外再启动一个专用的cpu压力测试进程。stress-ng是一个多功能系统压力测试工具,master/worker模型,master为主进程,负责生成和控制子进程,worker是负责执行各类特定测试的子进程。
集群中的每个节点都拥有定量的cpu和内存资源,调度pod时,仅那些被请求资源的余量可容纳当前调度的pod的请求量的节点才可作为目标节点。也就是说,k8s的调度器会根据容器的requests属性中定义的资源需求量来判定仅哪些节点可接受运行相关的pod资源,而对于一个节点的资源来说,每运行一个pod对象,其requestes中定义的请求量都要被预留,直到被所有pod对象瓜分完毕为止。
二、资源限制
容器的资源需求仅能达到为其保证可用的最少资源量的目的,它并不会限制容器的可用资源上限,因此对因应用程序自身存在bug等多种原因而导致的系统资源被长期占用的情况则无计可施,这就需要通过limits属性定义资源的最大可用量。资源分配时,可压缩型资源cpu的控制阈可自由调节,容器进程无法获得超出其cpu配额的可用时间。不过,如果进程申请分配超出其limits属性定义的硬限制的内存资源时,它将被OOM killer杀死。不过,随后可能会被其控制进程所重启。例如,容器进程的pod对象会被杀死并重启(重启策略为always或onfailure时),或者是容器进程的子进程被其父进程所重启。
与requests不同的是,limits并不会影响pod的调度结果,也就是说,一个节点上的说有pod对象的limits数量之和可以大于节点所拥有的资源量,即支持资源的过载使用。不过,这么一来一旦资源耗尽,尤其是内存资源耗尽,则必然会有容器因OOMKilled而终止。另外,k8s仅会确保pod能够获得他们请求的cpu时间额度,他们能否获得额外的cpu时间,则取决于其他正在运行的作业对cpu资源的占用情况。例如,对于总数为1000m的cpu来说,容器a请求使用200m,容器b请求使用500m,在不超出它们各自的最大限额的前提下,余下的300m在双方都需要时会以2:5的方式进行配置。
三、容器的可见资源
于容器中运行top等命令观察资源可用量信息时,即便定义了requests和limits属性,虽然其可用资源受限于此两个属性的定义,但容器中可见的资源量依然是节点级别的可用总量。
四、pod的服务质量类别
k8s允许节点资源对limits的过载使用,这意味着节点无法同时满足其上的所有pod对象以资源满载的方式运行。于是,在内存资源紧缺时,应该以何种次序先后终止哪些pod对象?k8s无法自行对此做出决策,它需要借助于pod对象的优先级完成判定。根据pod对象的requests和limits属性,k8s将pod对象归类到BestEffort、Burstable和Guaranteed三个服务质量类别下,具体如下:
Guaranteed:每个容器都为cpu资源设置了具有相同值的requests和limits属性,以及每个容器都为内存资源设置了具有相同值的requests和limits属性的pod资源会自动归属于此类别,这类pod资源具有最高优先级.
Burstable:至少有一个容器设置了cpu或内存资源的requests属性,但不满足Guaranteed类别要求的pod资源将自动归属此类别,它们具有中等优先级。
BestEffort:未为任何一个容器设置requests和limits属性的pod资源将自动归属于此类别,它们的优先级为最低级别。
内存资源紧缺时,BestEfford类别的容器将首当其冲地终止,因为系统不为其提供任何级别的资源保证,但换来的好处是,它们能够在可用时做到尽可能多地占用资源。若已然不存在BestEfford类别的容器,则接下来是有着中等优先级的Burstable类别的pod被终止。Guaranteed类别的容器拥有最高优先级,它们不会被杀死,除非其内存资源需求超限,或者OOM时没有其他更低优先级的pod资源存在。
每个运行状态的容器都有其OOM得分,得分越高越会被优先杀死。OOM得分主要根据两个维度进行计算:由QoS类别继承而来的默认分值和容器的可用内存资源比例。同等类别的pod资源的默认分值相同。同等级别优先级的pod资源在OOM时,与自身requests属性相比,其内存占用比例最大的pod对象将被首先杀死。需要特别说明的是,OOM是内存耗尽时的处理机制,它们与可压缩型资源cpu无关,因此cpu资源的需求无法得到保证时,pod仅仅是暂时获取不到相应的资源而已。