一个计算机技术爱好者与学习者

0%

好好学K8S:K8S中的Request和Limit

1. Pod和容器的资源设置

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

当我们为 Pod 中的 Container 指定了资源 request(请求) 时, kube-scheduler 就利用该信息决定将 Pod 调度到哪个节点上。
当我们为 Container 指定了资源 limit(限制) 时,kubelet 就可以确保运行的容器不会使用超出所设限制的资源。
kubelet 还会为容器预留所 request(请求) 数量的系统资源,供其使用。

参考文档:

2. K8S中的资源单位

2.1. CPU资源单位

CPU 资源的限制和请求以 cpu 为单位,资源清单中关键字是 cpu 。
在 Kubernetes 中,1个CPU核等于1个逻辑核,1个逻辑核 等于 1个物理CPU核 或者 1个虚拟核 ,取决于节点是一台物理主机还是运行在某物理主机上的虚拟机。

我们也可以表达带小数 CPU 的请求。 当我们定义一个容器,将其 spec.containers[].resources.requests.cpu 设置为 0.5 时, 我们所请求的 CPU 是我们请求 1.0 CPU 时的一半。 对于 CPU 资源单位,数量 表达式 0.1 等价于表达式 100m,可以看作 100 millicpu。 有些人说成是一百毫核,其实说的是同样的事情。

CPU 资源总是设置为资源的绝对数量而非相对数量值。 例如,无论容器运行在单核、双核或者 48-核的机器上,500m CPU 表示的是大约相同的计算能力。

2.2. 内存资源单位

内存的限制和请求以字节为单位,资源清单中关键字是 memory 。
我们可以使用普通的整数,或者带有以下 数量后缀 的定点数字来表示内存:E、P、T、G、M、k。
我们也可以使用对应的 2 的幂数:Ei、Pi、Ti、Gi、Mi、Ki。
例如,以下表达式所代表的是大致相同的值:

1
128974848、129e6、129M、128974848000m、123Mi

请注意后缀的大小写。如果我们请求 400m 临时存储,实际上所请求的是 0.4 字节。 如果有人这样设定资源请求或限制,可能他的实际想法是申请 400Mi 字节(400Mi) 或者 400M 字节。

2.3. PVC存储单位

PVC存储单位和内存资源的的单位相同,资源清单中的关键字是 storage 。

2.4. 本地临时性存储单位

本地临时性存储的单位和内存资源的单位相同,资源清单中关键字是 ephemeral-storage 。

本地临时性存储说明:
本地临时性存储,以Pod中的用户角度来看,就是系统盘。
节点可以具有本地的临时性存储,由本地挂接的可写入设备或者有时也用 RAM 来提供支持。
临时(Ephemeral)意味着对所存储的数据不提供长期可用性的保证。

Pods 通常可以使用临时性本地存储来实现缓冲区、保存日志等功能。 kubelet 可以为使用本地临时存储的 Pods 提供这种存储空间,允许后者使用 emptyDir 类型的卷将其挂载到容器中。

kubelet 也使用此类存储来保存节点层面的容器日志、 容器镜像文件以及运行中容器的可写入层。

详情参考文档本地临时存储

2.5. GPU资源单位

K8S中,在调度使用GPU资源时,使用不同的 Kubernets Device Plugin,GPU单位也是不同的。

参考文档:

3. 资源设置方式

3.1. 资源设置方式概述

资源设置有三种方式:
1、在Container中设置
在Container中设置资源需求是最常用的方式,其中request是容器可以使用到的最小资源,limit是宿主机资源充足的情况下容器可以使用到的最大资源

2、使用LimitRange限制
使用 LimitRange 可以设置某个命名空间的 request 与 limit 默认值,也可设定 request 与 limit 的最大值与最小值。

3、使用ResourceQuota限制
当多个用户或团队共享具有固定节点数目的集群时,人们会担心有人使用超过其基于公平原则所分配到的资源量。资源配额是帮助管理员解决这一问题的工具。
使用 ResourceQuota 可以对某个命名空间的资源消耗总量提供限制。它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命名空间中的 Pod 可以使用的计算资源的总上限。

3.2. 在Container中设置

3.2.1. 设置CPU和内存

在Container中设置CPU和内容,示例如下:

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
---
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"

上面的 Pod 有两个容器。每个容器的请求为 0.25 CPU 和 64MiB(226 字节)内存, 每个容器的资源限制为 0.5 CPU 和 128MiB 内存。 我们可以认为该 Pod 的资源请求为 0.5 CPU 和 128 MiB 内存,资源限制为 1 CPU 和 256MiB 内存。

3.2.2. 设置本地临时存储

在Container中设置本地临时存储,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
name: testpod
spec:
containers:
- image: alpine:3.7.3
name: testpod
resources:
requests:
ephemeral-storage: 1Gi
limits:
ephemeral-storage: 1Gi
command: ["/bin/sh", "-c"]
args:
- tail -f /dev/null
status: {}

3.3. 使用LimitRange限制

使用LimitRange,设置Request和Limit默认值和范围,示例如下:

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
apiVersion: v1
kind: LimitRange
metadata:
name: cpu-resource-constraint
namespace: default
spec:
requests:
- default: # 此处定义默认限制值
cpu: 500m
defaultRequest: # 此处定义默认请求值
cpu: 500m
max: # max 和 min 定义限制范围
cpu: "1"
min:
cpu: 100m
type: Container
limits:
- default: # 此处定义默认限制值
cpu: 500m
defaultRequest: # 此处定义默认请求值
cpu: 500m
max: # max 和 min 定义限制范围
cpu: "1"
min:
cpu: 100m
type: Container

注意:使用LimiteRange,目前是不支持限制本地临时存储的。

3.4. 使用ResourceQuota限制

3.4.1. 限制CPU和内存

使用ResourceQuota,限制default namespace下所有pod的request cpu总和不超过1,request memory总和不超过2G,limit cpu总和不超过2,limit memory总和不超过2G,示例如下:

1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: ResourceQuota
metadata:
name: cpu-memory-quota
namespace: default
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi

3.4.2. 限制本地临时存储

使用ResourceQuota,也可以限制磁盘的用量。
限制default namespace下所有pod的数据写入总和不能超过1G,示例如下:

1
2
3
4
5
6
7
8
9
apiVersion: v1
kind: ResourceQuota
metadata:
name: diskquota
namespace: default
spec:
hard:
requests.ephemeral-storage: 1Gi
limits.ephemeral-storage: 1Gi

4. 怎样设置合理的Request和Limit?

4.1. 建议设置Request

Request 的值并不代表给容器实际分配的资源大小,而是用于提供给调度器。调度器会检测每个节点可用于分配的资源(节点可分配资源 = 节点资源总额 - 已调度到节点上的 Pod 内容器 request 之和),同时记录每个节点已经被分配的资源(节点上所有 Pod 中定义的容器 request 之和)。如发现节点剩余的可分配资源已小于当前需被调度的 Pod 的 request,则该 Pod 就不会被调度到此节点。反之,则会被调度到此节点。

如果不配置 request,调度器就无法感知节点资源使用情况,无法做出合理的调度决策,可能会造成调度不合理,引起节点状态混乱。建议给所有容器设置 request,使调度器可感知节点资源情况,以便做出合理的调度决策。集群的节点资源能够被合理的分配使用,避免因资源分配不均而导致发生故障。

4.2. 重要应用Request等于Limit

在Kubernetes中,request和limit之间的差异决定了容器的QoS类别。

  • 如果 request == limit,则容器属于Guaranteed QoS类别。
  • 如果 request < limit,则容器属于Burstable QoS类别。
  • 如果没有设置request和limit,则容器属于BestEffort QoS类别。

不同的QoS类别有不同的调度和驱逐策略。
节点资源不足时,会触发自动驱逐和删除,优先删除BestEffort容器,其次是Burstable容器,最后是Guaranteed容器。
同时,request和limit之间的差值越大,Burstable类型的容器被驱逐的风险就越高。

对于生产环境中关键的服务,推荐设置 request == limit ,即Guaranteed QoS类别,以保证在节点故障时关键服务不易被驱逐导致线上业务受到影响。

4.3. 提高资源利用率

如果应用设置了较高的 request 值,而实际占用资源远小于设定值,会导致节点整体的资源利用率较低。除对时延非常敏感的业务外,敏感的业务本身并不期望节点利用率过高,影响网络包收发速度。
建议对非核心,并且资源非长期占用的应用,适当减少 request 以提高资源利用率。如果我们的服务支持水平扩容,那么除 CPU 密集型应用外,单副本的 request 值通常可设置为不大于1核。例如,coredns 设置为0.1核,即100m即可。

4.4. 避免Request和Limit值过大

如果我们的服务使用单副本或少量副本,且 request 及 limit 的值设置过大,使服务可分配到足够多的资源去支撑业务。那么某个副本发生故障时,可能会给业务带来较大影响。
当 Pod 所在节点发生故障时,由于 request 值过大,且集群内资源分配的较为碎片化,其余节点无足够可分配资源满足该 Pod 的 request,那么该 Pod 无法实现漂移,无法自愈,会加重对业务的影响。
建议尽量减小 request 及 limit,通过增加副本的方式对我们的服务支撑能力进行水平扩容,使系统更加灵活可靠。

  • 本文作者: 好好学习的郝
  • 原文链接: https://www.voidking.com/dev-k8s-request-limit/
  • 版权声明: 本文采用 BY-NC-SA 许可协议,转载请注明出处!源站会即时更新知识点并修正错误,欢迎访问~
  • 微信公众号同步更新,欢迎关注~