十三、pod容器资源限制

当你定义 Pod 时可以选择性地为每个 容器设定所需要的资源数量以及最大使用资源数量。 最常见的可设定资源是 CPU 和内存(RAM)大小;此外还有其他类型的资源。

当你为 Pod 中的 Container 指定了资源 请求 时(满足这个值Pod才会被调度到节点),调度器就利用该信息决定将 Pod 调度到哪个节点上。 当你还为 Container 指定了资源 约束 时(最大使用资源),kubelet 就可以确保运行的容器不会使用超出所设约束的资源。 kubelet 还会为容器预留所 请求 数量的系统资源,供其使用。

13.1 请求资源和最大约束资源

如果 Pod 运行所在的节点具有足够的可用资源,容器可能(且可以)使用超出对应资源 request 属性所设置的资源量。不过,容器不可以使用超出其资源 limit 属性所设置的资源量。

例如,如果你将容器的 memory 的请求量(request)设置为 256 MiB,而该容器所处的 Pod 被调度到一个具有 8 GiB 内存的节点上,并且该节点上没有其他 Pods 运行,那么该容器就可以尝试使用更多的内存(在没有设置limit的情况下)。

如果你将某容器的 memory 约束设置为 4 GiB,kubelet (和 容器运行时) 就会确保该约束生效。 容器运行时会禁止容器使用超出所设置资源约束的资源。 例如:当容器中进程尝试使用超出所允许内存量的资源时,系统内核会将尝试申请内存的进程终止, 并引发内存不足(OOM)错误。

约束值可以以被动方式来实现(系统会在发现违例时进行干预),或者通过强制生效的方式实现 (系统会避免容器用量超出约束值)。不同的容器运行时采用不同方式来实现相同的限制。

常用的字段

Pod 中的每个容器都可以指定以下的一个或者多个值:

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
  • spec.containers[].resources.limits.hugepages-
  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory
  • spec.containers[].resources.requests.hugepages-

尽管请求和限制值只能在单个容器上指定,我们仍可方便地计算出 Pod 的资源请求和约束。 Pod 对特定资源类型的请求/约束值是 Pod 中各容器对该类型资源的请求/约束值的总和

13.2 CPU和内存的含义

CPU的含义

CPU 资源的约束和请求以 cpu 为单位。

Kubernetes 中的一个 cpu 等于云平台上的 1 个 vCPU/核和裸机 Intel 处理器上的 **1 个超线程 **。

你也可以表达带小数 CPU 的请求。spec.containers[].resources.requests.cpu 为 0.5 的 Container 肯定能够获得请求 1 CPU 的容器的一半 CPU 资源。表达式 0.1 等价于表达式 100m, 可以看作 “100 millicpu”。有些人说成是“一百毫 cpu”,其实说的是同样的事情。 具有小数点(如 0.1)的请求由 API 转换为 100m;最大精度是 1m。 因此,或许你应该优先考虑使用 100m 的形式。

CPU 总是按绝对数量来请求的,不可以使用相对数量; 0.1 的 CPU 在单核、双核、48 核的机器上的意义是一样的

内存的含义

内存的约束和请求以字节为单位。你可以使用以下后缀之一以一般整数或定点整数形式来表示内存: E、P、T、G、M、K。你也可以使用对应的 2 的幂数:Ei、Pi、Ti、Gi、Mi、Ki。 例如,以下表达式所代表的是大致相同的值:

1
128974848、129e6、129M、123Mi

下面是个例子。

以下 Pod 有两个 Container。每个 Container 的请求为 0.25(250m) cpu 和 64MiB(226 字节)内存, 每个容器的资源约束为 0.5(500m) cpu 和 128MiB 内存。 你可以认为该 Pod 的资源请求为 0.5 cpu 和 128 MiB 内存,资源限制为 1 cpu 和 256MiB 内存。

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
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"

13.3 带资源限制的Pod如何调度与运行

带资源请求的 Pod 如何调度

当你创建一个 Pod 时,Kubernetes 调度程序将为 Pod 选择一个节点。 每个节点对每种资源类型都有一个容量上限:可为 Pod 提供的 CPU 和内存量。 调度程序确保对于每种资源类型,所调度的容器的资源请求的总和小于节点的容量。 请注意,尽管节点上的实际内存或 CPU 资源使用量非常低,如果容量检查失败, 调度程序仍会拒绝在该节点上放置 Pod。 当稍后节点上资源用量增加,例如到达请求率的每日峰值区间时,节点上也不会出现资源不足的问题。

带资源约束的 Pod 如何运行

当 kubelet 启动 Pod 中的 Container 时,它会将 CPU 和内存约束信息传递给容器运行时。

当使用 Docker 时:

  • spec.containers[].resources.requests.cpu 先被转换为可能是小数的基础值,再乘以 1024。 这个数值和 2 的较大者用作 docker run 命令中的 --cpu-shares 标志的值。

  • spec.containers[].resources.limits.cpu 先被转换为 millicore 值,再乘以 100。 其结果就是每 100 毫秒内容器可以使用的 CPU 时间总量。在此期间(100ms),容器所使用的 CPU 时间不会超过它被分配的时间。

    说明: 默认的配额(quota)周期为 100 毫秒。 CPU配额的最小精度为 1 毫秒。

  • spec.containers[].resources.limits.memory 被转换为整数值,作为 docker run 命令中的 --memory 参数值。

如果 Container 超过其内存限制,则可能会被终止。如果容器可重新启动,则与所有其他类型的 运行时失效一样,kubelet 将重新启动容器。

如果一个 Container 内存用量超过其内存请求值,那么当节点内存不足时,容器所处的 Pod 可能被逐出。

每个 Container 可能被允许也可能不被允许使用超过其 CPU 约束的处理时间。 但是,容器不会由于 CPU 使用率过高而被杀死。

要确定 Container 是否会由于资源约束而无法调度或被杀死,请参阅疑难解答 部分。、

13.9 QoS资源限制的分类

​ Guaranteed(最高优先级):Pod中每个容器同时设置CPU和内存的requests和limits,此类Pod当节点资源不够时优先保留,会kill那些优先级低的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
# cpu.limits=cpu.requests
# memory.limits=memory.request
# 示例
apiVersion: v1
kind: Pod
metadata:
name: pod-limit
spec:
containers:
- name: nginx-01
image: hub.nnv5.cn/test/myapp:v2
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "512Mi"

[root@k8s-master resources]# kubectl apply -f limit.yaml
pod/pod-limit created
[root@k8s-master resources]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-limit 1/1 Running 0 5s
[root@k8s-master resources]# kubectl describe pod pod-limit | grep -i qos
QoS Class: Guaranteed

​ Buranteed(中等优先级):Pod中至少有一个容器设置CPU或内存资源的requests属性或者request中的cpu和内存属性和limits中的属性不相等

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
38
39
40
41
# 未设置limits示例
[root@k8s-master resources]# vim limit-B.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-limit
spec:
containers:
- name: nginx-01
image: hub.nnv5.cn/test/myapp:v2
resources:
requests:
cpu: "200m"
memory: "256Mi"
[root@k8s-master resources]# kubectl apply -f limit-B.yaml
pod/pod-limit created
[root@k8s-master resources]# kubectl describe pod pod-limit | grep -i qos
QoS Class: Burstable

## requests和limits中不相等示例
[root@k8s-master resources]# cat limit-B.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-limit
spec:
containers:
- name: nginx-01
image: hub.nnv5.cn/test/myapp:v2
resources:
requests:
cpu: "200m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
[root@k8s-master resources]# kubectl apply -f limit-B.yaml
pod/pod-limit created
[root@k8s-master resources]# kubectl get pods ^C
[root@k8s-master resources]# kubectl describe pod pod-limit | grep -i qos
QoS Class: Burstable

​ BestEffort(最低优先级别):没有任何一个容器设置了requests与limits(当资源不够使用时,这类Pod将会被优先终止以便腾出资源确保其他两类的pod正常运行)。