一、什么是QoS

虽然我们进行了资源限制,但是实际使用时依旧会造成节点资源不足,针对资源不足Kubernetes会通过重启或驱逐Pod释放资源,再重启时,难免会造成一些很重要的服务不可用。但实际情况可能是,如果重启或驱逐一些不重要的Pod可能会更好,而这种决策是通过QoS(Quality of Service,服务质量)决定的,所以在生产环境中,QoS是一个非常重要的环节。

服务质量类(Quality of Service class,QoS class)Kubernetes 在 Node 资源不足时使用 QoS 类来就驱逐 Pod 作出决定。

二、QoS出现背景

虽然我们可以给没有配置requests和limits的Pod添加默认值,也可以限制资源请求的范围,但是在使用Kubernetes部署时,应用的部署和更新都会经过一系列的调度策略将应用部署在最合适的节点上,但是随着时间的推移,当时“最优”的节点可能已经不再是最佳选择,因为在该服务器上别的应用或者其他管理员部署的应用可能忘记了配置资源限制,所以在日积月累的消耗中,宿主机一些不可压缩的资源(比如内存、磁盘)的使用率将达到最高峰。假如内存达到最高峰时会引起OOMKilled故障,此时Kubelet会根据某些策略重启上面的容器用来避免宿主机宕机引来的风险,但是重启容器难免会带来服务中断的现象,如果重启的是比较重要的业务应用,这将是一个非常不好的体验。QoS就应运而生,可以保证在系统资源不够的情况下尽量保证一些比较重要的Pod不被杀死。

三、QoS分类

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

  • Guaranteed:最高服务质量,当宿主机内存不够时,会先杀死QoS为BestEffort和Burstable的Pod,如果内存还是不够,才会杀死QoS为Guaranteed的Pod,该级别Pod的资源占用量一般比较明确,即requests字段的cpu和memory与limits字段的cpu和memory配置的一致。
  • Burstable:服务质量低于Guaranteed,当宿主机内存不够时,会先杀死QoS为BestEffort的Pod,如果内存还是不够,就会杀死QoS级别为Burstable的Pod,用来保证QoS质量为Guaranteed的Pod,该级别的Pod一般知道最小资源使用量,但是当机器资源充足时,还是想尽可能使用更多的资源,即limits字段的cpu和memory大于requests字段的cpu和memory的配置。
  • BestEffort:尽力而为,当宿主机内存不够时,首先杀死的就是该QoS的Pod,用以保证Burstable和Guaranteed级别的Pod正常运行。

实现不同级别的服务质量是根据requests和limits的配置决定的,在宿主机资源不够时会先杀死服务质量为BestEffort的Pod,然后杀死服务质量为Burstable的Pod,最后杀死服务质量为Guaranteed的Pod。所以在生产环境中比较重要的应用最好设置为Guaranteed,当然如果集群资源足够使用,可以都设置为Guaranteed。

下面总结一下,关于这3种级别的服务质量满足条件:

  • Guaranteed:
  • Pod中的每个容器必须指定limits.memory和requests.memory, 并且两者需要相等;
  • Pod中的每个容器必须指定limits.cpu和limits.memory,并且两者需要相等
  • Burstable:
  • Pod不符合Guaranteed的配置要求
  • Pod中至少有一个容器配置了requests.cpu或requests.memory
  • BestEffort:
  • 不设置resources参数

四、QoS如何使用

4.1 示例1:实现QoS为Guaranteed的Pod

1.定义一个yaml文件

[root@k8s-master01 study]# vim qos-guaranteed.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr
    image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2
    resources:
      limits:
        memory: "200Mi"
        cpu: "700m"
      requests:
        memory: "200Mi"
        cpu: "700m"

2.创建一个命名空间

[root@k8s-master01 study]# kubectl create ns qos-example

3.创建Pod

[root@k8s-master01 study]# kubectl create -f qos-guaranteed.yaml -n qos-example

4.查看pod

[root@k8s-master01 study]# kubectl get po -n qos-example
NAME       READY   STATUS    RESTARTS   AGE
qos-demo   1/1     Running   0          33s

5.将pod输出到yaml文件,观察到qosClass: Guaranteed

[root@k8s-master01 study]# kubectl get po -n qos-example qos-demo -oyaml
...
...
    started: true
    state:
      running:
        startedAt: "2022-12-11T07:47:56Z"
  hostIP: 192.168.100.35
  phase: Running
  podIP: 172.27.14.203
  podIPs:
  - ip: 172.27.14.203
  qosClass: Guaranteed
  startTime: "2022-12-11T07:47:55Z"
...
...

4.2 示例2:实现QoS为Burstable的Pod

1.定义一个yaml文件

[root@k8s-master01 study]# vim qos-burstable.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-2
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-2-ctr
    image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

2.创建一个命名空间

[root@k8s-master01 study]# kubectl create ns qos-example

3.创建Pod

[root@k8s-master01 study]# kubectl create -f qos-burstable.yaml  -n qos-example

4.查看pod

[root@k8s-master01 study]# kubectl get po -n qos-example

NAME         READY   STATUS    RESTARTS   AGE
qos-demo     1/1     Running   0          11m
qos-demo-2   1/1     Running   0          6s

5.将pod输出到yaml文件,观察到qosClass: Burstable

[root@k8s-master01 study]# kubectl get po -n qos-example qos-demo-2 -oyaml
...
...
...
    state:
      running:
        startedAt: "2022-12-11T07:59:20Z"
  hostIP: 192.168.100.34
  phase: Running
  podIP: 172.17.125.8
  podIPs:
  - ip: 172.17.125.8
  qosClass: Burstable
  startTime: "2022-12-11T07:59:19Z"

4.3 示例3:实现QoS为BestEffort的Pod

1.定义一个yaml文件

[root@k8s-master01 study]# vim qos-besteffort.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-3
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-3-ctr
    image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2

2.创建一个命名空间

[root@k8s-master01 study]# kubectl create ns qos-example

3.创建Pod

[root@k8s-master01 study]# kubectl create -f qos-besteffort.yaml   -n qos-example

4.查看pod

[root@k8s-master01 study]# kubectl get po -n qos-example

NAME         READY   STATUS    RESTARTS   AGE
qos-demo     1/1     Running   0          14m
qos-demo-2   1/1     Running   0          3m31s
qos-demo-3   1/1     Running   0          8s

5.将pod输出到yaml文件,观察到qosClass: BestEffort

[root@k8s-master01 study]# kubectl get po -n qos-example qos-demo-3 -oyaml
...
...
...
  - ip: 172.18.195.4
  qosClass: BestEffort
  startTime: "2022-12-11T08:02:42Z"