关于K8s中资源服务质量管理Resource Qos(超售超用)的一些笔记

简介: 写在前面分享一些 K8s中资源服务质量管理Resource Qos 的笔记博文内容涉及:K8s Qos 简单介绍资源配置的特点: 节点的超用,可压缩/不可压缩,完全可靠性等介绍QoS Classes 介绍三种 Qos 服务质量等级 Pod 定义的 Demo理解不足小伙伴帮忙指正

写在前面


  • 分享一些 K8s中资源服务质量管理Resource Qos 的笔记
  • 博文内容涉及:

    • K8s Qos 简单介绍
    • 资源配置的特点: 节点的超用可压缩/不可压缩,完全可靠性等介绍
    • QoS Classes 介绍
    • 三种 Qos 服务质量等级 Pod 定义的 Demo
  • 理解不足小伙伴帮忙指正

精神的寓所是我们的,不是阴曹地府,不是天上星辰,这两者都是活在我们之中的精神所制作的。 ----《作为意志和表象的事件》


一些名词解释

Qos : Qos 最先是在网络链路中提出的,QoS(Quality of Service)即服务质量。在有限的带宽资源下,QoS 为各种业务分配带宽,为业务提供端到端的服务质量保证。例如,语音、视频和重要的数据应用在网络设备中可以通过配置 QoS 优先得到服务。可以单纯的理解为 服务质量保证、控制、管理

服务质量管理 Qos服务质量协议(SLA)以及服务质量指标(SLI)、服务质量目标(SLO) 都涉及到了 服务质量,但是是不同的, Qos 更多的是对行为的描述, 而 SLA 等是标准,可以这样理解,期望通过 Qos 的管理来观测 SLI 达到 SLO ,从而符合 SLA。关于服务质量目标更多,小伙伴可以看看 《SRE Google 运维解密》 第四章 的部分,这里不多介绍。

K8s Qos 简介

Kubernetes 可以根据 Pod 的 Requests 和 Limits 配置来实现针对 Pod 的不同级别的资源服务质量控制(QoS),之前看到有 小伙伴讲 QoS 才是 Google K8s 的精华所在。

容器中 Requests 是 Kubernetes 调度时能为容器提供的完全可保障的资源量(最低保障),而 Limits 是系统允许容器运行时可能使用的资源量的上限(最高上限)。Pod 级别的资源配置是通过计算 Pod 内所有容器的资源配置的总和得出来的。

资源配置特点

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

  • 如果 Pod 配置的 Requests 值等于 Limits 值,那么该 Pod 可以获得的资源是完全可靠的。这里的完全可靠单纯可以理解不可变,不会随着 Node 的资源情况发生波动
  • 如果 Pod 的 Requests 值小于 Limits 值,那么该 Pod 获得的资源可分成两部分:

    • 完全可靠 的资源,资源量的大小等于 Requests 值,申请的最少资源,pod任何时候都要有这么多
    • 不可靠的 资源,资源量最大等于 Limits 与 Requests 的差额,这份不可靠的资源能够申请到多少,取决于当时主机上容器可用资源的余量。

通过这种机制,Kubernetes 可以实现节点资源的 超售(Over Subscription),对应的 Pod 可以实现 超用(Over Committed)

节点资源的 Over Subscription

比如在 CPU 完全充足的情况下,某机器共有 32GiB内存可提供给容器使用,容器配置为 Requests 值 1GiB,Limits 值为 2GiB,那么在该机器上最多可以同时运行 32个容器,每个容器最多可以使用 2GiB内存,如果这些容器的 内存使用峰值能错开,那么所有容器都可以正常运行。

超售机制能有效提高资源的利用率,同时不会影响容器申请的完全可靠资源的可靠性。

Kubernetes 根据Pod配置的Requests值来调度Pod,Pod 在成功调度之后会得到 Requests 值定义的资源来运行;

如果 Pod 所在机器上的资源有空余,则 Pod 可以申请更多的资源,最多不能超过 Limits 的值。

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

Requests 和 Limits 针对不同计算资源类型的限制机制的差异。这种差异主要取决于计算资源类型是 可压缩资源还是不可压缩资源。这里的压缩即如果资源超出 Cgroup 的限制后的状态,可压缩的资源pod 还可以存活,不可压缩的资源 pod 会被 Kill

可压缩资源

Kubernetes 目前支持的可压缩资源是 CPU。 Pod 可以得到 Pod 的 Requests 配置的 CPU 使用量,而能否使用超过 Requests 值的部分取决于系统的负载和调度。空闲 CPU 资源按照容器 Requests 值的比例分配。即 节点中超过 requests 的资源按照 申请资源的比例分配,如果 Pod 使用了超过在 Limits 中配置的 CPU 用量,那么 cgroups 会对 Pod 中的容器的 CPU 使用进行限流(Throttled)

不可压缩资源

Kubernetes 目前支持的不可压缩资源是内存。Pod 可以得到在 Requests 中配置的内存。如果 Pod 使用的内存量小于它的 Requests 的配置,那么这个 Pod 可以正常运行(除非出现操作系统级别的内存不足等严重问题);如果 Pod 使用的内存量超过了它的 Requests 的配置,那么这个 Pod 有可能被 Kubernetes 杀掉,如果 Pod 使用的内存量超过了它的 Limits 设置,那么操作系统内核会杀掉 Pod 所有容器的所有进程中使用内存最多的一个,直到内存不超过 Limits 为止。

比如 Pod A 使用了超过 Requests 而不到 Limits 的内存量,此时同一机器上另外一个 Pod B 之前只使用了远少于自己的 Requests 值的内存,此时程序压力增大,PodB 向系统申请的总量不超过自己的 Requests 值的内存,那么 Kubernetes 可能会直接杀掉 PodA;另外一种情况是 PodA 使用了超过 Requests 而不到 Limits 的内存量,此时 Kubernetes 将一个新的 Pod 调度到这台机器上,新的 Pod 需要使用内存,而只有 PodA 使用了超过了自己的 Requests 值的内存,那么 Kubernetes 也可能会杀掉 Pod A 来释放内存资源。

对调度策略的影响

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

服务质量等级(QoS Classes)

在一个超用(Over Committed,容器Limits总和大于系统容量上限)系统中,由于容器负载的波动可能导致操作系统的资源不足,最终可能导致部分容器被杀掉。

在这种情况下,我们当然会希望优先杀掉那些不太重要的容器,那么如何衡量重要程度呢?Kubernetes将容器划分成3个QoS等级,这三种优先级依次递减:

  • Guaranteed(完全可靠的)
  • Burstable(弹性波动、较可靠的)
  • BestEffort(尽力而为、不太可靠的)

当前的 QoS级别 直接由 Requests 和 Limits 来定义。在Kubernetes中容器的QoS级别等于容器所在Pod的QoS级别,而Kubernetes的资源配置定义了Pod的三种QoS级别,如下所述。

创建一个 QoS 类为 Guaranteed 的 Pod

对于 QoS 类为 Guaranteed 的 Pod:

  • Pod 中的每个容器都必须指定内存限制和内存请求。
  • 对于 Pod 中的每个容器,内存限制必须等于内存请求。
  • Pod 中的每个容器都必须指定 CPU 限制和 CPU 请求。
  • 对于 Pod 中的每个容器,CPU 限制必须等于 CPU 请求。
  • 这些限制同样适用于初始化容器和应用程序容器。

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

在下面这两个例子中定义的Pod QoS级别就是Guaranteed:

┌──[root@vms81.liruilongs.github.io]-[/]
└─$cat qos-pod.yaml
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"

创建后可以看到 qosClass 级别为: Guaranteed

┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl create namespace qos-example
namespace/qos-example created
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl  apply -f qos-pod.yaml
pod/qos-demo created
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .status.qosClass
"Guaranteed"

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

┌──[root@vms81.liruilongs.github.io]-[/]
└─$cat qos-pod.yaml
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"

创建之后发现一样

┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl  apply -f qos-pod.yaml
pod/qos-demo configured
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .status.qosClass
"Guaranteed"
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .spec.containers[0].resources
{
  "limits": {
    "cpu": "700m",
    "memory": "200Mi"
  },
  "requests": {
    "cpu": "700m",
    "memory": "200Mi"
  }
}
┌──[root@vms81.liruilongs.github.io]-[/]
└─$

创建一个 QoS 类为 BestEffort 的 Pod

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

┌──[root@vms81.liruilongs.github.io]-[/]
└─$cat qos-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr
    image: nginx
    resources:

容器没有设置内存和 CPU 限制或请求。

┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl  apply -f qos-pod.yaml
pod/qos-demo created
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .spec.containers[0].resources
{}
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .status.qosClass
"BestEffort"
┌──[root@vms81.liruilongs.github.io]-[/]
└─$

创建一个 QoS 类为 Burstable 的 Pod

当一个 Pod 既不为 Guaranteed 级别,也不为 BestEffort 级别时,该 Pod 的 QoS 级别就是Burstable。Burstable级别的Pod包括两种情况。

如果满足下面条件,将会指定 Pod 的 QoS 类为 Burstable:

Pod 不符合 Guaranteed QoS 类的标准。即Pod中的一部分容器在一种或多种资源类型的资源配置中定义了Requests值和Limits值(都不为0),且Requests值小于Limits值;

┌──[root@vms81.liruilongs.github.io]-[/]
└─$cat qos-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-ctr
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

Kubernetes 为 Pod 配置的 QoS 类为 Burstable

┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl  apply -f qos-pod.yaml
pod/qos-demo created
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .spec.containers[0].resources
{
  "limits": {
    "memory": "200Mi"
  },
  "requests": {
    "memory": "100Mi"
  }
}
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .status.qosClass
"Burstable"
┌──[root@vms81.liruilongs.github.io]-[/]
└─$

Pod 中至少一个容器具有内存或 CPU 的请求或限制。Pod中的一部分容器未定义资源配置(Requests和Limits都未定义)。注意:在容器未定义Limits时,Limits值默认等于节点资源容量的上限。

┌──[root@vms81.liruilongs.github.io]-[/]
└─$cat qos-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: qos-demo
  namespace: qos-example
spec:
  containers:
  - name: qos-demo-1
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"
  - name: qos-demo-2
    image: nginx

创建一个包含两个容器的 Pod

┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl  apply -f qos-pod.yaml
pod/qos-demo created

查看对于的资源配置和 Qos 等级,Pod 配置的 QoS 类为 Burstable

┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .spec.containers[0].resources
{
  "limits": {
    "memory": "200Mi"
  },
  "requests": {
    "memory": "100Mi"
  }
}
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .spec.containers[1].resources
{}
┌──[root@vms81.liruilongs.github.io]-[/]
└─$kubectl get pods -n qos-example qos-demo -o json | jq  .status.qosClass
"Burstable"
┌──[root@vms81.liruilongs.github.io]-[/]
└─$

Kubernetes QoS的工作特点

Pod的CPU Requests无法得到满足(比如节点的系统级任务占用过多的CPU导致无法分配足够的CPU给容器使用)时,容器得到的CPU会被压缩限流。

由于内存是不可压缩的资源,所以针对内存资源紧缺的情况,会按照以下逻辑进行处理。

  • BestEffort Pod的优先级最低,在这类Pod中运行的进程会在系统内存紧缺时被第一优先杀掉。当然,从另外一个角度来看,BestEffort Pod由于没有设置资源Limits,所以在资源充足时,它们可以充分使用所有的闲置资源。
  • Burstable Pod的优先级居中,这类Pod初始时会分配较少的可靠资源,但可以按需申请更多的资源。当然,如果整个系统内存紧缺,又没有BestEffort容器可以被杀掉以释放资源,那么这类Pod中的进程可能会被杀掉。
  • Guaranteed Pod的优先级最高,而且一般情况下这类Pod只要不超过其资源Limits的限制就不会被杀掉。当然,如果整个系统内存紧缺,又没有其他更低优先级的容器可以被杀掉以释放资源,那么这类Pod中的进程也可能会被杀掉。

内存不够 触发 OOM 会被 Cgroup 的 OOM Killer 杀掉,K8s 的打分机制是独立于节点级别的打分机制的,不同 Qos 级别的 OOM 打分规则也不同,考虑版本问题,这里不多介绍,感兴趣小伙可以下去了解下。

博文参考


《Kubernetes 权威指南 第四版 》

《SRE Google 运维解密》

https://info.support.huawei.com/info-finder/encyclopedia/zh/QoS.html

https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/quality-service-pod/

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
4月前
|
Kubernetes 监控 调度
在K8S中,DaemonSet类型资源特性?
在K8S中,DaemonSet类型资源特性?
|
2月前
|
JSON 运维 Kubernetes
|
4月前
|
存储 Kubernetes 数据中心
在K8S中,同⼀个Pod内不同容器哪些资源是共用的,哪些资源是隔离的?
在K8S中,同⼀个Pod内不同容器哪些资源是共用的,哪些资源是隔离的?
|
4月前
|
Kubernetes 网络性能优化 调度
在K8S中,Kubernets资源限制是如何配置的,是否根据Qos?
在K8S中,Kubernets资源限制是如何配置的,是否根据Qos?
|
4月前
|
边缘计算 人工智能 Kubernetes
边缘计算问题之理解 Kubernetes 节点资源的四层分配结构如何解决
边缘计算问题之理解 Kubernetes 节点资源的四层分配结构如何解决
41 1
|
4月前
|
Kubernetes Linux 调度
在k8S中,Pod如何实现对节点的资源控制?
在k8S中,Pod如何实现对节点的资源控制?
|
4月前
|
存储 Kubernetes API
|
4月前
|
Kubernetes 监控 API
在K8S中,RS资源如何实现升级和回滚?
在K8S中,RS资源如何实现升级和回滚?
|
4月前
|
存储 Kubernetes 监控
在K8S中,Resource Quotas是什么?如何做资源管理的?
在K8S中,Resource Quotas是什么?如何做资源管理的?
|
4月前
|
Kubernetes 网络协议 应用服务中间件
在K8S中,SVC资源是否支持在K8S集群外部访问?
在K8S中,SVC资源是否支持在K8S集群外部访问?