资源请求和资源限制

可用于分配的资源包括CPU和内存,其中CPU属于可压缩资源,内存属于不可压缩资源。资源请求和资源限制分别对应requests和limits,区别在于,资源请求从容器角度看是向系统申请使用一定量的资源,即使超出也是可以接受的(受实际资源限制),资源限制从系统角度是最高可以使用一定量的资源。或者理解为requests为系统确保某个资源对象分配的最少资源,limits为系统允许使用的最大资源,两者可以结合使用,即划定资源使用范围。

kubernetes上的一颗CPU对应虚拟机的一个虚拟CPU核心或物理机上的一个CPU核心(包括Intel的超线程),对应1000个微核心(millicore),比如 500m对应0.5个CPU资源。内存计量方式和平时计量方式相同,即K、M、G、T等

资源需求

资源需求对应的为spec.containers.resources.requests,下面是一个示例:

apiVersion: v1
kind: Pod
metadata:
  name: resource-request
spec:
  containers:
  - name: requests
    image: ikubernetes/stress-ng
    command: ["/usr/bin/stress-ng", "-m 1", "-c 1", "-metrics-brief"]
    resources:
      requests:
        cpu: "500m"
        memory: "128M"

创建资源之后并运行。然后使用kubectl exec resource-request -- top查看资源占用,会发现实际使用的资源比指定的资源要高。这也就是之前说的请求资源可以超限使用。或者可以理解为系统必须给指定资源对象保证最少的可用资源,实际使用中,未指定requests的资源可能在主机资源紧张时被压缩至无法运行。

资源限制

对应spec.containers.resources.limits,参考下面的示例:

apiVersion: v1
kind: Pod
metadata:
  name: limits
spec:
  containers:
  - name: limits-demo
    image: saadali/simmemleak
    resources:
      requests:
        cpu: "500m"
        memory: "128M"
      limits:
        cpu: "500m"
        memory: "128M"

创建并运行资源之后可以发现,在设定了资源限制之后,如果请求的资源超出限制值会被OOMKILL。

容器可见资源

如果我们在设定了资源限制的Pod中使用如top命令查看,会发现资源可用信息依然是节点界别的。这在某些应用中会有一些问题,典型的如Java程序和nginx。

在Pod中运行Java应用程序时,若未使用“-Xmx”选项指定JVM的堆内存可用总量,它默认会设置为主机内存总量的一个空间比例(如30%),这会导致容器中的应用程序申请内存资源时将会达到上限而转为OOMKilled。另外,即便使用了“-Xmx”选项设置其堆内存上限,但它对于非堆内存的可用空间不会产生任何限制作用,结果是仍然存在达到容器内存资源上限的可能性。

于Pod中运行的nginx应用,在配置参数worker_processes的值为“auto”时,主进程会创建与Pod中能够访问到的CPU核心数相同数量的worker进程。若Pod的实际可用CPU核心远低于主机级别的数量时,那么这种设置在较大的并发访问负荷下会导致严重的资源竞争,并将带来更多的内存资源消耗。一个较为妥当的解决方案是使用Downward API将limits定义的资源量暴露给容器,这一点将在后面的章节中予以介绍。

服务质量类别

Kubernetes允许节点资源对limits的过载使用,这意味着节点无法同时满足其上的所有Pod对象以资源满载的方式运行。于是,在内存资源紧缺时,应该以何种次序先后终止哪些Pod对象?Kubernetes无法自行对此做出决策,它需要借助于Pod对象的优先级完成判定。根据Pod对象的requests和limits属性,Kubernetes将Pod对象归类到BestEffort、Burstable和Guaranteed三个服务质量(Quality of Service,QoS)类别下,具体说明如下。

  • Guaranteed:每个容器都为CPU资源设置了具有相同值的requests和limits属性,以及每个容器都为内存资源设置了具有相同值的requests和limits属性的Pod资源会自动归属于此类别,这类Pod资源具有最高优先级。
  • Burstable:至少有一个容器设置了CPU或内存资源的requests属性,但不满足Guaranteed类别要求的Pod资源将自动归属于此类别,它们具有中等优先级。
  • BestEffort:未为任何一个容器设置requests或limits属性的Pod资源将自动归属于此类别,它们的优先级为最低级别。

内存资源紧缺时,BestEffort类别的容器将首当其冲地被终止,因为系统不为其提供任何级别的资源保证,但换来的好处是,它们能够在可用时做到尽可能多地占用资源。若已然不存任何BestEffort类别的容器,则接下来是有着中等优先级的Burstable类别的Pod被终止。Guaranteed类别的容器拥有最高优先级,它们不会被杀死,除非其内存资源需求超限,或者OOM时没有其他更低优先级的Pod资源存在。

也就是说在资源不足的时候,Kubernetes对于Pod的中止顺序是BestEffort → Burstable → Guaranteed

每个运行状态容器都有其OOM得分,得分越高越会被优先杀死。OOM得分主要根据两个纬度进行计算:由QoS类别继承而来的默认分值和容器的可用内存资源比例。同等类别的Pod资源的默认分值相同,同等级别优先级的Pod资源在OOM时,与自身的requests属性相比,其内存占用比例最大的Pod对象将被首先杀死。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!