k8s Pod Qos

QOS

Qos(Quality of Service),k8s会根据Pod容器中指定的资源约束为每个Pod设置QoS类。k8s依赖这种分类来决定当Node上没有足够可用资源时要驱逐哪些 Pod

QoS
k8s 对你运行的 Pod 进行分类,并将每个 Pod 分配到特定的 QoS类中。 k8s 使用这种分类来影响不同 Pod 被处理的方式。k8s 基于 Pod 中容器的资源请求进行分类, 同时确定这些请求如何与资源限制相关。 这称为服务质量 (QoS) 类。 k8s 基于每个 Pod 中容器的资源请求和限制为 Pod 设置 QoSk8s 使用 QoS 类来决定从遇到节点压力的 Node 中驱逐哪些 Pod。可选的 QoS 类有 GuaranteedBurstableBestEffort。 当一个 Node 耗尽资源时,k8s 将首先驱逐在该 Node 上运行的 BestEffort Pod, 然后是 Burstable Pod,最后是 Guaranteed Pod。当这种驱逐是由于资源压力时, 只有超出资源请求的 Pod 才是被驱逐的候选对象。

Guaranteed

Guaranteed Pod 具有最严格的资源限制,并且最不可能面临驱逐。 在这些 Pod 超过其自身的限制或者没有可以从 Node 抢占的低优先级 Pod 之前, 这些 Pod 保证不会被杀死。这些 Pod 不可以获得超出其指定 limit 的资源。这些 Pod 也可以使用 static CPU 管理策略来使用独占的 CPU

Pod 被赋予 Guaranteed QoS 类的几个依据:

  • Pod 中的每个容器必须有内存 limit 和内存 request
  • 对于 Pod 中的每个容器,内存 limit 必须等于内存 request
  • Pod 中的每个容器必须有 CPU limitCPU request
  • 对于 Pod 中的每个容器,CPU limit 必须等于 CPU request
Burstable

Burstable Pod 有一些基于 request 的资源下限保证,但不需要特定的 limit。 如果未指定 limit,则默认为其 limit 等于 Node 容量,这允许 Pod 在资源可用时灵活地增加其资源。 在由于 Node 资源压力导致 Pod 被驱逐的情况下,只有在所有 BestEffort Pod 被驱逐后 这些 Pod 才会被驱逐。因为 Burstable Pod 可以包括没有资源 limit 或资源 request 的容器, 所以 Burstable Pod 可以尝试使用任意数量的节点资源。

Pod被赋予 Burstable QoS 类的几个依据:

  • Pod 不满足针对 QoS 类 Guaranteed 的判据。
  • Pod 中至少一个容器有内存或 CPUrequestlimit
BestEffort

BestEffort QoS 类中的 Pod 可以使用未专门分配给其他 QoS 类中的 Pod 的节点资源。 例如若你有一个节点有 16 核 CPU 可供 kubelet 使用,并且你将 4 核 CPU 分配给一个 Guaranteed Pod, 那么 BestEffort QoS 类中的 Pod 可以尝试任意使用剩余的 12 核 CPU。

如果节点遇到资源压力,kubelet 将优先驱逐 BestEffort Pod

如果 Pod 不满足 GuaranteedBurstable 的判据,则它的 QoS 类为 BestEffort。 换言之,只有当 Pod 中的所有容器没有内存 limit 或内存 request,也没有 CPU limitCPU request 时,Pod 才是 BestEffortPod 中的容器可以请求(除 CPU 或内存之外的) 其他资源并且仍然被归类为 BestEffort

以上来自k8s文档


Qos与cgroup的关系
创建不同Qos的pod

使用下面的yaml文件创建对应的`pod

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
apiVersion: v1
kind: Pod
metadata:
name: guaranteed
spec:
containers:
- name: app
image: hysyeah/my-curl:v1
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "64Mi"
cpu: "250m"
--
apiVersion: v1
kind: Pod
metadata:
name: burstable
spec:
containers:
- name: app
image: hysyeah/my-curl:v1
resources:
requests:
memory: "64Mi"
cpu: "250m"
---
apiVersion: v1
kind: Pod
metadata:
name: besteffort
spec:
containers:
- name: app
image: hysyeah/my-curl:v1

当我们apply这个yaml文件后,Pod会被调度到对应的Node,kubelet会将PodSpec中的内容传递给CRI,CRI再将这此内容翻译成
更底层的OCI JSON Spec描述容器创建的信息。

crictl inspect <containerID>查看对应的资源信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 0e5962a09e2d3的部分内容
// 包括了资源的限制信息及cgroupsPath
"linux": {
"resources": {
"devices": [
{
"allow": false,
"access": "rwm"
}
],
"memory": {
"limit": 67108864 // 64M
},
"cpu": {
"shares": 256,
"quota": 25000,
"period": 100000
}
},
"cgroupsPath": "/kubepods/pod21ef5ccc-a09d-4754-aa1e-a65820d572cc/0e5962a09e2d3840e4f6ae1a3750136ad578c3df026a8dd64b175f8e33570823",
}

创建完成后你可以查看对应podQos
k describe pod <pod-name>
image

查看系统中的cgroups
  1. 节点系统信息

    1
    2
    3
    4
    5
    6
    7
    8
    ✗ uname -a
    Linux hysyeah 5.15.0-72-generic #79~20.04.1-Ubuntu SMP Thu Apr 20 22:12:07 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux

    # cgroups版本
    # 对于 cgroup v2,输出为 cgroup2fs
    # 对于 cgroup v1,输出为 tmpfs
    ➜ stat -fc %T /sys/fs/cgroup/
    tmpfs
  2. 查看容器相关信息crictl ps,对应的PodIDContainerID下面我们会使用到
    image

  3. cgroups的目录为/sys/fs/cgroup,我们只关注cpumemory

    1
    2
    ➜  cgroup ls
    blkio cpu cpuacct cpu,cpuacct cpuset devices freezer hugetlb memory misc net_cls net_cls,net_prio net_prio perf_event pids rdma systemd unified

image
image

可以看到cpumemory目录下都有一个名为kubepods的目录,k8s相关的cgroups就是放在这个目录下的。
memory/kubepods为例:
其中QosburstablebesteffortPodcgroup信息分别放在目录burstable,besteffort下。Qosguaranteedpodcgroup信息放在>下的目录下。
image

查看burstable目录下的cgroups,有两个目录分别是containerpod对应的cgroups
image

posSpec中的resources与cgroup的映射关系
podSpec cgroup
limits.cpu cpu.cfs_period_us, cpu.cfs_quota_us, cpu.shares
limits.memory memory.limit_in_bytes

cpu.cfs_period_us: 表示cfs调度时间周期,默认值为100000us(100ms)
cpu.cfs_quota_us: 表示在一个调度周期内允许执行的时间。-1表示不限制
cpu.shares:表示cpu group对控制组之间的cpu分配比例
memory.limit_in_bytes: 使用的最大内存量
cpu.cfs_quota_us/cpu.cfs_period_us表示这个控制组允许使用的cpu最大值。
如上我们设置limit.cpu=250m,则cpu.cfs_quota_us=25000,cpu.cfs_period_us=100000。cpu.cfs_quota_us/cpu.cfs_period_us=0.25,也就是podSpec中的250m


REF:
1.https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-qos/
2.https://docs.kernel.org/admin-guide/cgroup-v1/memory.html