QoS

虽然进行了资源限制,但是实际使用时依旧会造成节点资源不足,针对资源不足Kubernetes会通过重启或驱逐Pod释放资源,这会造成一些服务不可用。

什么是服务质量保证(QoS)

假设我们有一个Java进程,需要的CPU最低为1核,内存最低为2GB才能正常启动,并且需要10个副本才能支撑业务量。此时我们需要创建一个Deployment并设置副本为10、requests.cpu为1和requests.memory为2GB。创建该资源时,Scheduler会根据一系列算法将该Pod部署到合适的节点上,当然需要被调度节点最少有1核、2GB的空闲资源。

看似一个再简单不过的部署,如果在配置中未设置requests字段会如何呢?

如果未设置requests字段,那么Scheduler在调度时将不再检查Node节点上的资源是否满足该应用程序的最低需求,Scheduler会将副本随机部署至任意节点,包括已经没有资源的机器。如果部署到了一个没有资源的宿主机上,在该应用程序启动时可能会导致容器一直无法启用。因为应用程序在启动过程中会占用非常高的CPU,进而可能会导致宿主机以及宿主机上正在运行的Pod变为不可用,引起雪崩效应。所以设置合理的requests和limits是非常重要的事情!

设置了requests和limits就能万无一失吗?

答案当然是不可能。在使用Kubernetes部署时,应用的部署和更新都会经过一系列的调度策略将应用部署在最合适的节点上,但是随着时间的推移,当时“最优”的节点可能已经不再是最佳选择,因为在该服务器上别的应用或者其他管理员部署的应用可能忘记了配置资源限制,所以在日积月累的消耗中,宿主机一些不可压缩的资源(比如内存、磁盘)的使用率将达到最高峰。内存达到最高峰时会引起OOMKilled故障,此时Kubelet会根据某些策略重启上面的容器用来避免宿主机宕机引来的风险,而重启容器难免会出现服务中断,如果重启的是比较重要的业务应用,这将是一个非常不好的体验。

那么我们如何在系统资源不够的情况下尽量保证一些比较重要的Pod不被杀死呢?

可以用QoS来提高某些应用的服务质量,以保证宿主机资源不够时尽可能保证某些应用不被杀死。

Qos的三种级别

Kubernetes为我们提供了3种级别的服务质量,分别是:

  • Guaranteed最高服务质量,当宿主机内存不够时,会先杀死QoS为BestEffort和Burstable的Pod,如果内存还是不够,才会杀死QoS为Guaranteed的Pod。

  • Burstable:服务质量低于Guaranteed,当宿主机内存不够时,会先杀死QoS为BestEffort的Pod,如果内存还是不够,就会杀死QoS级别为Burstable的Pod,用来保证QoS质量为Guaranteed的Pod。

  • BestEffort:尽力而为,当宿主机内存不够时,首先杀死的就是该QoS的Pod,用以保证Burstable和Guaranteed级别的Pod正常运行。

实现QoS为Guaranteed的Pod

创建一个QoS为Guaranteed的Pod需要满足以下条件:

  • Pod中的每个容器必须指定limits.memory和requests.memory,并且两者需要相等。

  • Pod中的每个容器必须指定limits.cpu和limits.cpu,并且两者需要相等。

guaranteed-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: guaranteed-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.16-alpine
    resources:
      limits:
        memory: "128Mi"
        cpu: "500m"
      requests:
        memory: "128Mi"
        cpu: "500m"
$ kubectl create -f guaranteed-pod.yaml 
pod/guaranteed-pod created

$ kubectl describe pod guaranteed-pod | grep QoS
QoS Class:                   Guaranteed

注意:

如果容器指定了limits的cpu和memory配置,但是没有指定requests的cpu和memory配置,Kubernetes会自动添加和limits配置相同的requests配置。

实现QoS为Burstable的Pod

创建一个QoS为Burstable的Pod需要满足以下条件:

  • Pod不符合Guaranteed的配置要求。

  • Pod中至少有一个容器配置了requests.cpu或者requests.memory。

burstable-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: burstable-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.16-alpine
    resources:
      requests:
        memory: "128Mi"
        cpu: "500m"
$ kubectl describe pod burstable-pod | grep QoS
QoS Class:                   Burstable

实现QoS为BestEffort的Pod

创建一个QoS为BestEffort的Pod更为简单,Pod中的所有容器都没有设置requests和limits字段即可。

besteffort-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: burstable-pod
spec:
  containers:
  - name: nginx
    image: nginx:1.16-alpine
$ kubectl describe pod besteffort-pod | grep QoS
QoS Class:                   BestEffort

注意:

如果命名空间中存在如下的LimitRange:

$ kubectl describe limitrange cpu-mem-limit-range
Name:       cpu-mem-limit-range
Namespace:  default
Type        Resource  Min  Max  Default Request  Default Limit  Max Limit/Request Ratio
----        --------  ---  ---  ---------------  -------------  -----------------------
Container   cpu       -    -    500m             1              -
Container   memory    -    -    256Mi            512Mi          -

创建上述besteffort-pod,其QoS级别是Burstable:

$ kubectl describe pod besteffort-pod | grep QoS
QoS Class:                   Burstable

最后更新于