k8s学习-服务质量等级(Qos)

给 Pod 配置服务质量等级

Posted by Xiaolei.liang on December 25, 2019 本文总阅读量

前言

开始之前需要有一个k8s集群,使用一下方式:

QoS简介和等级划分

OsS等级

当 Kubernetes 创建一个 Pod 时,它就会给这个 Pod 分配一个 QoS 等级:

  • Guaranteed
  • Burstable
  • BestEffort

创建namespace

kubectl create namespace qos-example

创建一个 Pod 并分配 QoS 等级为 Guaranteed

Pod 分配 QoS 等级为 Guaranteed:

  • 容器中必须都要有内存的limit和req,而且limit值和req值相同
  • 容器中必须都要有cpu的limit和req,而且limit值和req值相同

以下是一个创建pod的配置文件:qos-pod.yaml,其中内存200MB,cpu 700 millicpu:

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"

创建pod:kubectl create -f qos-pod.yaml

查看pod的详细信息:kubectl get pod qos-demo -o qos-example -o yaml | grep qosClass,输出:qosClass: Guaranteed

注意: 如果一个容器配置了内存限制,但是没有配置内存申请,那 Kubernetes 会自动给容器分配一个符合内存限制的请求。 类似的,如果容器有 CPU 限制,但是没有 CPU 申请,Kubernetes 也会自动分配一个符合限制的请求。

删除pod: kubectl delete -f qos-pod.yaml

创建一个 Pod 并分配 QoS 等级为 Burstable

当出现下面的情况时,则是一个 Pod 被分配了 QoS 等级为 Burstable :

  • Pod 里至少有一个容器有内存或者 CPU 请求
  • 该 Pod 不满足 QoS 等级 Guaranteed 的要求

这是 Pod 的配置文件,里面有一个容器。这个容器配置了200MB的内存限制和100MB的内存申请。

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"

创建一个 Pod 并分配 QoS 等级为 BestEffort

要给一个 Pod 配置 BestEffort 的 QoS 等级, Pod 里的容器必须没有任何内存或者 CPU 的限制或请求。

下面是一个 Pod 的配置文件,包含一个容器。这个容器没有内存或者 CPU 的限制或者请求:

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

创建一个拥有两个容器的 Pod

这是一个含有两个容器的 Pod 的配置文件,其中一个容器指定了内存申请为 200MB ,另外一个没有任何申请或限制。

apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-4
  namespace: qos-example
spec:
  containers:

  - name: qos-demo-4-ctr-1
    image: nginx
    resources:
      requests:
        memory: "200Mi"

  - name: qos-demo-4-ctr-2
    image: redis

注意到这个 Pod 满足了 QoS 等级 Burstable 的要求. 就是说,它不满足 Guaranteed 的要求,而且其中一个容器有内存请求。

资源限制分析

资源类型

Kubernetes做为目前主流的容器集群管理平台,需要整体统筹平台资源使用情况、公平合理的将资源分配给相关pod容器使用,并且要保证容器生命周期内有足够的资源来保证其运行。 与此同时,由于资源发放的独占性,即资源已经分配给了某容器,同样的资源不会在分配给其他容器,对于资源利用率相对较低的容器来说,占用资源却没有实际使用(比如CPU、内存)造成了严重的资源浪费,Kubernetes需从优先级与公平性等角度提高资源的利用率。为了实现资源被有效调度和分配的同时提高资源利用率,Kubernetes针对不同服务质量的预期,通过QoS(Quality of Service)来对pod进行服务质量管理,提供了个采用requests和limits两种类型对资源进行分配和使用限制。对于一个pod来说,服务质量体现在两个为2个具体的指标: CPU与内存。实际过程中,当NODE节点上内存资源紧张时,kubernetes会根据预先设置的不同QoS类别进行相应处理。

资源限制原因

如果未做过节点 nodeSelector,亲和性(node affinity)或pod亲和、反亲和性(pod affinity/anti-affinity)等Pod高级调度策略设置,我们没有办法指定服务部署到指定机器上,如此可能会造成cpu或内存等密集型的pod同时分配到相同Node,造成资源竞争。另一方面,如果未对资源进行限制,一些关键的服务可能会因为资源竞争因OOM(Out of Memory)等原因被kill掉,或者被限制CPU使用。

资源需求(Requests)和限制( Limits)

对于每一个资源,container可以指定具体的资源需求(requests)和限制(limits),requests申请范围是0到node节点的最大配置,而limits申请范围是requests到无限,即0 <= requests <=Node Allocatable, requests <= limits <= Infinity。 对于CPU,如果pod中服务使用CPU超过设置的limits,pod不会被kill掉但会被限制。如果没有设置limits,pod可以使用全部空闲的cpu资源。 对于内存,当一个pod使用内存超过了设置的limits,pod中container的进程会被kernel因OOM kill掉。当container因为OOM被kill掉时,系统倾向于在其原所在的机器上重启该container或本机或其他重新创建一个pod。

可压缩资源与不可压缩资源

Kubernetes根据资源能否伸缩进行分类,划分为可压缩资源和不可以压缩资源2种。CPU资源是目前支持的一种可压缩资源,而内存资源和磁盘资源为目前所支持的不可压缩资源。

QoS优先级

3种QoS优先级从有低到高(从左向右):

Best-Effort pods -> Burstable pods -> Guaranteed pods

静态pod

在Kubernetes中有一种DaemonSet类型pod,此类型pod可以常驻某个Node运行,由该Node上kubelet服务直接管理而无需api server介入。静态pod也无需关联任何RC,完全由kubelet服务来监控,当kubelet发现静态pod停止时,kubelet会重新启动静态pod。

资源回收策略

当kubernetes集群中某个节点上可用资源比较小时,kubernetes提供了资源回收策略保证被调度到该节点pod服务正常运行。当节点上的内存或者CPU资源耗尽时,可能会造成该节点上正在运行的pod服务不稳定。Kubernetes通过kubelet来进行回收策略控制,保证节点上pod在节点资源比较小时可以稳定运行。

可压缩资源:CPU

在压缩资源部分已经提到CPU属于可压缩资源,当pod使用超过设置的limits值,pod中进程使用cpu会被限制,但不会被kill。

不可压缩资源:内存

Kubernetes通过cgroup给pod设置QoS级别,当资源不足时先kill优先级低的pod,在实际使用过程中,通过OOM分数值来实现,OOM分数值从0-1000。

OOM分数值根据OOM_ADJ参数计算得出,对于Guaranteed级别的pod,OOM_ADJ参数设置成了-998,对于BestEffort级别的pod,OOM_ADJ参数设置成了1000,对于Burstable级别的POD,OOM_ADJ参数取值从2到999。对于kuberntes保留资源,比如kubelet,docker,OOM_ADJ参数设置成了-999,表示不会被OOM kill掉。OOM_ADJ参数设置的越大,通过OOM_ADJ参数计算出来OOM分数越高,表明该pod优先级就越低,当出现资源竞争时会越早被kill掉,对于OOM_ADJ参数是-999的表示kubernetes永远不会因为OOM而被kill掉。

QoS pods被kill掉场景与顺序

  • Best-Effort 类型的pods:系统用完了全部内存时,该类型pods会最先被kill掉。
  • Burstable类型pods:系统用完了全部内存,且没有Best-Effort container可以被kill时,该类型pods会被kill掉。
  • Guaranteed pods:系统用完了全部内存、且没有Burstable与Best-Effort container可以被kill,该类型的pods会被kill掉。

注:如果pod进程因使用超过预先设定的limites而非Node资源紧张情况,系统倾向于在其原所在的机器上重启该container或本机或其他重新创建一个pod。

使用建议

  • 如果资源充足,可将QoS pods类型均设置为Guaranteed。用计算资源换业务性能和稳定性,减少排查问题时间和成本。
  • 如果想更好的提高资源利用率,业务服务可以设置为Guaranteed,而其他服务根据重要程度可分别设置为Burstable或Best-Effort,例如filebeat。

已知问题

不支持swap,当前的QoS策略假设swap已被禁止。

总结

当resources只写了limits的时候,会给自动加上requests;如果只写了requests的话,则limits不会增加。其中,requests用作调度,limits用作资源限制。

参考