Resource QoS:资源服务质量管理

        在Kubernetes的QoS体系中,需要保证高可靠性的Pod可以申请可靠资源,而一些非高可靠性的Pod可以申请可靠性低或者不可靠的资源,在之前我们说到了容器的资源配置为分为Requests和Limits,其中Requests是Kubernetes调度时能为容器提供的安全、可保障的资源量(最低保障),而Limits是系统允许容器运行时可以使用的资源量的上限(最高上限)。Pod级别的资源配置是通过计算Pod内所有容器的资源配置的总和得出来

        Kubernetes中Pod的Requests和Limits资源配置有如下特点:

        1.如果Pod配置的Requests值等于Limits值,那么该Pod可以获得的资源是完全可靠的
        2.如果Pod配置的Requests值小于Limits值,那么该Pod获得的资源可分为两部分:

                完全可靠的资源,资源量的大小等于Requests值;

                不可靠的资源,资源量的最大值等于Limits值减去Requests值,这份不可靠的资源能申请到多少,取决于当时主机上容器可用资源的大小。

        通过这种机制,Kubernetes可以实现节点资源的超售 (Over Subscription) ,比如在CPU完全充足的情况下,某机器共有32GiB内存可供容器使用, 容器配置为Requests值1GiB、Limits值2GiB,那么在该机器上最多可以同时运行32个容器,每个容器最多可以使用2GiB内存,如果这些容器的内存使用峰值能错开,那么所有容器都可以正常运行。

1.Requests和Limits对不同计算资源类型的限制机制

        容器的资源配置满足以下两个条件:

                Requests<=节点可用资源

                Requests<=Limits

        Kubernetes根据Pod配置的Requests值来调度Pod, Pod在成功调度之后会得到Requests值定义的资源来运行;如果Pod所在机器上的资源有空余,则Pod 可以申请更多的资源,最多不能超过 Limits的值。
       

        1.1 可压缩资源

                Kubernetes目前支持的可压缩资源是CPU。

                Pod可以得到Requests配置的CPU使用量,而能否使用超过Requests值的部分取决于系统的负载和调度。

                空闲的CPU资源按照容器Requests值的比例分配 。举例说明:容器A的CPU配置为Requests 1 Limits 10, 容器B的CPU配置为Request 2 Limits 8, A 和 B 同时运行在一个节点上,初始状态下容器的可用CPU为3cores, 那么A和B恰好得到在其Requests中定义的CPU用量,即1CPU 和2CPU。如果A和B都需要更多的CPU资源,而恰好此时系统上的其他任务又释放了1.5CPU,那么这1.5CPU将按照A和B的Requests值比例1:2分配给A和B,最终A可以使用1.5CPU,B可以使用3CPU。

                如果Pod的CPU用量超过了在Limits值中的CPU用量,则那么cgroups会对Pod中容器的CPU用量进行限流(Throttled)。

        1.2 不可压缩资源

                Kubernetes目前支持的不可压缩资源是内存。

                Pod可以得到在Requests中配置的内存。如果Pod的内存用量小于它的Requests的配置,那么这个 Pod 可以正常运行(除非出现操作系统级别内存不足等严重问题);如果Pod的内存用量超过了它的Requests配置,那么这个Pod有可能被Kubernetes“杀掉":比如Pod A使用了超过 Requests而不到Limits的内存址,此时同一机器上另一个Pod B之前只使用了远少于自己的 Requests值的内存,此时程序压力增大,Pod B向系统申请的总量不超过自己的Requests值的内存,那么Kubemetes可能会直接“杀掉”Pod A;另外一种情况是Pod A使用了超过Requests而不到 Limits的内存,此时Kubemetes将一个新的Pod调度到这台机器上,新的Pod需要使用内存,而只有Pod A使用了超过了自己的Requests值的内存,那么Kubemetes 也可能会 “ 杀掉 “Pod A 来释放内存资源。        

                如果Pod的内存用量超过了它的Limits设置,那么操作系统内核会“杀掉 “Pod所有容器的所有进程中内存使用量最多的一个,直到内存不超过Limits时为止。

2.对调度策略的影响

        Kubernetes的kube-scheduler通过计算Pod中所有容器的Requests的总和来决定对Pod的调度。

        不管是CPU还是内存,Kubemetes调度器和kubelet都会确保节点上所有Pod的Requests总和不会超过在该节点上可分配给容器使用的资源容量上限。

3.服务质量等级(QoS Classes)

        在一个超用(Over Committed,容器Limits总和大于系统容量上限)系统中,容器负载的波动可能导致操作系统的资源不足,最终导致部分容器被“杀掉"。在这种情况下,我们当然会希望优先“杀掉“那些不太重要的容器,那么如何衡量重要程度呢?Kubernetes将容器划分成3个QoS等级: Guaranteed(完全可靠的)、Burstable(弹性波动、较可靠的)和BestEffort(尽力而为、不太可靠的),这三种优先级依次递减,如下图:

        从理论上来说,QoS级别应该作为一个单独的参数来提供 API, 并由用户对Pod进行配置,这种配置应该与Requests和Limits无关。但在当前版本的Kubernetes设计中,为了简化模式及避免引入太多的复杂性,QoS级别直接由Requests和Limits定义。在Kubernetes中,容器的QoS级别等于容器所在Pod的QoS级别,而Kubernetes的资源配置定义了Pod的三种QoS级别,如下所述:

        1).Guaranteed
                如果Pod中的所有容器对所有资源类型都定义了Limits和Requests, 并且所有容器的Limits值都和Requests值相等(且都不为0),那么该Pod的QoS级别就是Guaranteed 。

注意:在这种情况下,容器可以不定义Requests, 因为Requests值在未定义时默认等于Limits

例如:

#1.编辑yaml文件
[root@k8s-master qos_test]# cat qos-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: default
spec:
  containers:
  - name: qos-demo-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "700m"
      requests:
        memory: "200Mi"
        cpu: "700m"

#2.创建pod
[root@k8s-master qos_test]# kubectl create -f qos-pod.yaml 
pod/qos-demo created
#3.查看QOS类型
[root@k8s-master qos_test]# kubectl describe po qos-demo |grep "QoS Class"
QoS Class:                   Guaranteed

        2).BestEffort
                如果Pod中所有容器都未定义资源配置(Requests和Limits都未定义),那么该Pod的QoS级别就是BestEffort,例如:

#1.编辑yaml文件
[root@k8s-master qos_test]# cat qos-pod-2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-2
  namespace: default
spec:
  containers:
  - name: qos-demo-2-ctr
    image: nginx

#2.创建pod
[root@k8s-master qos_test]# kubectl create -f qos-pod-2.yaml 
pod/qos-demo-2 created
#3.查看QOS类型
[root@k8s-master qos_test]# kubectl describe po qos-demo |grep "QoS Class"
QoS Class:                   BestEffort

        3).Burstable

                当一个Pod既不为Guaranteed级别,也不为BestEffort级别时,该Pod的QoS级别就是Burstable。Burstable级别的Pod涉及两种情况。第1种情况:Pod中的一部分容器在一种或多种资源类型的资源配置中定义了Requests值和Limits值(都不为0),且Requests值小于Limits值;第2种情况:Pod中的一部分容器未定义资源配置 (Requests和Limits都未定义)。注意:在容器未定义Limits时,Limits值默认等于节点资源容量的上限。例如:

        

#1.编辑yaml文件
[root@k8s-master qos_test]# cat qos-pod-3.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo-3
  namespace: default
spec:
  containers:
  - name: qos-demo-3-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

#2.创建pod
[root@k8s-master qos_test]# kubectl create -f qos-pod-3.yaml 
pod/qos-demo-3 created

#3.查看QOS类型
[root@k8s-master qos_test]# kubectl describe po qos-demo |grep "QoS Class"
QoS Class:                   Burstable

4.Kubernetes QoS的工作特点

        在Pod的CPU Requests无法得到满足(比如节点的系统级任务占用过多的CPU导致无法分足够的CPU给容器使用)时,容器得到的CPU会被压缩限流。由于内存是不可压缩资源,所以针对内存资源紧缺的时候会按照下面逻辑来处理:

        (1)BestEffort Pod的优先级最低,在这类Pod中运行的进程会在系统内存紧缺时被第一优先“杀掉"。当然,从另一个角度来看,BestEffort Pod由于没有设置资源Limits,所以在资源充足时 , 它们可以充分使用所有闲过资源。

        (2)Burstable Pod的优先级居中,这类Pod在初始时会被分配较少的可靠资源,但可以按需申请更多的资源。当然,如果整个系统内存紧缺,又没有BestEffort容器可以被杀掉以释放资源,那么这类Pod中的进程可能被“杀掉"。

        (3)Guaranteed Pod 的优先级最高,而且一般情况下这类Pod只要不超过其资源Limits的限制就不会被“杀掉"。当然,如果整个系统内存紧缺,又没有其他更低优先级的容器可以被“杀掉“以释放资源,那么这类 Pod 中的进程也可能会被“杀掉"。

5.OOM计分规则

        在Kubernetes中,OOM积分越高,node资源紧缺时越容易被“kill”,不同QoS的OOM积分规则如下图:

从上图中看到BestEffort默认是1000,被kill优先级最高,Guaranteed优先级是最低的,Burstable有个算法,总的来说就是占用资源高的优先级高。

注:在Kubernetes中,我们也可以定义PriorityClass来决定Pod的重要性,PriorityClass表示该Pod的重要性,后面我们会讲到。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐