为什么容器要设置 Request/Limit?
容器在运行时通常需要消耗 CPU/内存资源,假设没有任何配置的情况下,容器能使用的资源上限为当前所在的节点可被分配的资源量。
- 一台节点通常会运行很多容器。
假设一个节点上只有一个容器,那么这个容器在没有完全消耗节点资源的时间里,节点上空闲的资源被浪费了。现代一台普通的个人电脑通常可以运行数百个进程,同样的,一台节点通常会运行很多容器,但这引发了另外一个问题:容器之间可能抢夺资源,而节点本身的资源却是固定的。 - 需要使用 Limit 控制容器资源使用上限。
Kubernetes 的世界里,通过 Limit 来限定一个容器能使用的资源量上限,如果容器申请的资源量大于 Limit,它就会被压制用量甚至被驱逐到其它节点上。 - 需要使用 Request 保证容器资源使用的下限。
只设置 Limit 来控制容器资源使用上限就足够了吗?设想:如果一个10核的节点上运行了100个容器,但每个容器至少需要1核才能正常启动和运行,这时节点上的所有容器都无法正常运行。因此,Kubernetes 使用 Request 来保证容器最少的资源供给量。
总的来说,Kuberentes 使用 Request 和 Limit 来保证和限制一个容器使用的 CPU/内存的资源量。
CPU 和内存的单位是什么?
CPU
CPU 默认单位:核。您也可以使用带小数的 CPU 资源量。当您定义一个容器 CPU Request 为0.5时,所请求的 CPU 是请求1.0核 CPU 时的一半。同时,0.5等价于500m,可以看作 “500 millicpu”,读作“五百毫核”。
内存
内存默认单位:字节。您也可以使用普通的整数,或者带有 数量单位 后缀来表示内存。例如,以下表达式所代表的是大致相同的值:
128974848、129e6、129M、128974848000m、123Mi
注意:请注意后缀的大小写。例如,如果请求400m临时存储,实际上所请求的值是0.4字节。同理,如果申请400Mi字节(400Mi)或者400M字节,实际上所请求的值是0.4字节。
如何理解 Request/Limit?
Kubernetes 里的 Request/Limit 是通过 CPU Share 和 CPU Quota 技术实现的。
CPU Share
假设一个机器上运行多个容器,多个容器是如何分配资源的?您需要了解 CPU Shares 的概念。
CPU Shares 是属于一项 Linux Control Groups(cgroup)的特性,CPU Shares 控制容器中的进程可以使用的 CPU time。
CPU time 是 CPU 用于处理计算机程序或操作系统的指令的时间量,不是实际日常生活中的时间概念。例如进程进入中断、挂起、休眠等行为时,CPU time 不会增加,但进程恢复运行后 CPU time 会从中断前的时间点继续增加。
CPU Shares 特点
- CPU Shares 是相对的概念,不是绝对的含义。
容器的 CPU Shares 是用于在不同容器之间调度 CPU time 的相对值。单独看 CPU Shares 的数字本身没有任何意义。例如,将一个容器 A 的 CPU Shares 设置为512,并不会提供有关容器将获得多少 CPU time 的信息。如果此时将另一个容器 B 的 CPU Shares 设置为1024,意味着 B 容器将获得两倍于 A 容器的 CPU time。也就是说,它仍然没有提供有关每个容器将获得的实际 CPU time 的信息,只有它们之间的相对量。如果 A、B 同时运行在一个3核的设备上,理论上每个时刻将分别获得1核和2核的 CPU。如果运行在6核的设备上,则分别获得2核和4核。如果运行在一个0.3核的设备上,则变成了0.1核和0.2核。 - CPU Shares 只有在资源竞争时才会发生。
- 只有 A、B 容器期望在相同时间运行时,才会使用您设置的 CPU Shares 值去分配 CPU 核数。
- 如果只有一个容器在运行,该容器可以用所有的 CPU。
- 如果同时有多个容器在运行,则通过设置的 CPU Shares 值去分配节点上可分配的 CPU 核数。
- 非运行中的容器即使配置 CPU Shares,也不会影响到运行中的容器关于 CPU time 的划分。
- CPU Shares 设计的目的在于最大化 CPU 资源的利用率。
- 任何容器,不管 CPU Shares 值是多少,都有可能用到一台节点上的所有 CPU 资源。
- 在 CPU 发生竞争时,可以通过 CPU Shares 值来判断每个容器到底该获得多少 CPU time。
CPU Quota
CPU Quota 是用来限制容器的资源使用上限,即使一个节点资源还有剩余量,但容器依旧无法使用超过 CPU Quota 的数值。
Kubernetes 中的 CPU Share
Kubernetes 的 Request/Limit 是由 CPU Share 和 CPU Quota 来实现的。但 Request 还有更多的含义:
- Request 是一个绝对值,不是相对值,保证一个容器的最小可用的资源量。
- Request 用来给调度器做判断,寻找集群可剩余调度资源量大于当前 Pod Request 的节点中,最优的节点用来调度当前 Pod。
- 在发生资源竞争时,会利用 CPU Share 的相对值概念,分配 CPU。
没有 Request 的 Pod
没有 Request 的 Pod 可以调度到任意节点,因为任意节点的剩余可调度资源都满足该 Pod 要求。但是在发生竞争时,它将不会获得任何的资源,此时 Pod 可能会无限期地缺乏资源。
实际应用
在终端里创建一个可以交互的 busybox Pod:
kubectl run -i --tty --rm busybox \
--image=busybox \
--restart=Never \
--requests='cpu=50m,memory=50Mi' -- sh
在交互栏里使用如下命令让该 Pod 可以用满当前节点上空闲的 CPU 和内存:
while true; do true; done
dd if=/dev/zero of=/dev/shm/fill bs=1k count=1024k
在另一终端里查看当前 Pod 的资源用量
kubectl top pods
NAME CPU(cores) MEMORY(bytes)
busybox 460m 65Mi
可以看出,当前 busybox Pod 的 CPU 和内存的资源用量都大于 Request。但理论上因为 busybox 运行的是无限循环的程序,应该会把所有的 CPU 都消耗完才对,为什么只消耗了460m?因为此时集群中还有其他的 Pod 和进程,它们都会通过 CPU Share 彼此竞争集群中的 CPU 资源。
总结
- Kubernetes 用 Request 保证容器对资源的最小用量。
- Kubernetes 用 Limit 限制容器对资源的最大用量。
- 输入数值的时候,要注意默认单位:CPU 默认单位:核;内存默认单位:字节。
- 当发生资源竞争时,Kuberentes 根据不同容器对 Request 的申请量的比例分配资源。