写在前面
- 分享一些 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/