资源类型

Kubernetes 里,Pod 是最小的原子调度单位。这也就意味着,所有跟调度和资源管理相关的属性都应该是属于 Pod 对象的字段。

在k8s中,像CPU这样的资源被称为“可压缩资源”,即资源不足的时候会饥饿但是不会退出。而内存这样的资源被称为“不可压缩资源”,即资源不足的话Pod就会被内核kill掉。

k8s中Pod的内存和CPU资源还要分为requests和limits两种情况。

  • 调度的时候按照requests。
  • 真正设置cgroups的时候按照limits。 也就是调度的时候按需使用资源,避免浪费,但是其可以使用的最大资源还是按照limits来的。用户在提交 Pod 时,可以声明一个相对较小的 requests 值供调度器使用,而 Kubernetes 真正设置给容器 Cgroups 的,则是相对较大的 limits 值

QoS

根据limit和request的设置方式的不同,k8s会将Pod划分至不同的QoS级别当中。

Guarantee

当limits和request都被设置,并且两者的值相同的时候,这个Pod就属于Guarantee类别。但是需要注意,当设置了limits而没有设置request的时候,k8s会自动为其设置于limits相同的requests,所以可以这样认为。只要每一个容器都设置了limits或者同时设置了相同的limits和requests,这个Pod就是Guarantee级别的。如下:

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"

Burstable级别

首先不满足Guarantee级别,但是至少有一个容器设置了requests,那么就是Burstable级别的。例如下面的Pod,limits和requests设置并不相同

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-2
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-2-ctr
    image: nginx
    resources:
      limits
        memory: "200Mi"
      requests:
        memory: "100Mi"

BestEffort级别

即没有设置limits,也没有设置requests,那么这个Pod就是BestEffort级别。

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-3
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-3-ctr
    image: nginx

资源回收

上面介绍的三种QoS级别,就是k8s在资源紧张的时候进行Eviction(资源回收)会用到的。 当宿主机上的不可压缩资源紧张的时候就可能触发Eviction,例如内存,磁盘空间,容器运行时镜像存储空间等等。

例如,k8s的默认Eviction默认阈值:

memory.available<100Mi
nodefs.available<10%
nodefs.inodesFree<5%
imagefs.available<15%

当然触发条件也是可以配置的。

Eviction分为Soft和Hard两种模式。它们的区别就在于,Soft模式允许设置优雅时间,就是触发之后等待这段时间再进行Eviction。而Hard模式则是在达到阈值之后立即就执行了。

当宿主机的 Eviction 阈值达到后,就会进入 MemoryPressure 或者 DiskPressure 状态,从而避免新的 Pod 被调度到这台宿主机上

是前面介绍的三种QoS其实就是Eviction时候的优先级。最先被回收的就是BestEffort级别的资源,然后是Burstable,最后才是Guarantee级别。可以这样理解,对Pod的资源限制越多,说明越希望这个Pod能够保证运行,所以越晚被回收。

==DaemonSet的Pod强烈推荐设置为Guarantee,不然就算被回收也会被立即创建出来,没有意义==。

设置cpuset

容器可以通过设置cpuset绑定在固定的cpu核上,这样就避免了进城上下文的切换,大大提高了容器里应用的性能。

同样的,设置cpuset也是生产环境里部署在线类型的Pod的时候非常常用的方式。

设置的方式也非常简单,就是Pod要求是Guarantee级别的,如下:

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "2"
      requests:
        memory: "200Mi"
        cpu: "2"

这样这个Pod就会被绑定到2个固定的CPU核上,具体是哪两个核是由kubelet分配的。