容器服务

为什么容器要设置 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 特点

1. 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核。
2. CPU Shares 只有在资源竞争时才会发生。
只有 A、B 容器期望在相同时间运行时,才会使用您设置的 CPU Shares 值去分配 CPU 核数。
如果只有一个容器在运行,该容器可以用所有的 CPU。
如果同时有多个容器在运行,则通过设置的 CPU Shares 值去分配节点上可分配的 CPU 核数。
非运行中的容器即使配置 CPU Shares,也不会影响到运行中的容器关于 CPU time 的划分。
3. 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 还有更多的含义:
1. Request 是一个绝对值,不是相对值,保证一个容器的最小可用的资源量。
2. Request 用来给调度器做判断,寻找集群可剩余调度资源量大于当前 Pod Request 的节点中,最优的节点用来调度当前 Pod。
3. 在发生资源竞争时,会利用 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 默认单位:核;内存默认单位:字节。
当发生资源竞争时,Kubernetes 根据不同容器对 Request 的申请量的比例分配资源。