概述
docker提供对CPU资源的限制,主要基于cgroup的cpuset来实现;到v1.13版本后,主要演化成以下几个参数。
- –cpus 指定容器所需的cpu核数;其实现方式只是指定的对应cpu核心数相对的资源总量,容器可能会在多个核心上运行,可能涉及到上下文切换的消耗;
- –cpu-shares 指定多个容器抢占有限的资源时能够分配到cpu资源的权重;需要搭配着其他两个命令一起使用,单纯使用该命令,或在没有资源抢占的情况下使用该命令没有意义;
- –cpuset-cpus 指定容器绑定到具体哪些cpu核上运行;资源隔离相对较好,但也可能存在多个容器同时被绑定到同一个核上的情况。 宿主机上有4core:
1 | # cat /proc/cpuinfo | grep processor | wc -l |
–cpu-shares参数
该选项用来设置CPU权重,它的默认值为1024。我们可以把它设置为1表示很低的权重,但是设置为0将表示使用默认值1024。它提供对抢占资源时,cpu的分配份额。
在只有一个进程使用资源时,cpu-shares没有意义,资源直接被容器消耗完。
1 | # docker run --rm --cpu-shares=512 -it progrium/stress -c 4 |
–cpus参数
指定容器使用的cpu数,在资源够分配时,它对资源使用总量的限制较准确;当资源不够出现超卖时,其无法保障能够获取到对应的CPU资源数。
资源足够时
1 | # docker run --rm --cpus=1 -it progrium/stress -c 4 |
结果显示,此时指定cpus的结果,相当于分配了1个core给stress运行。
超卖资源时
无–cpu-shares
以下命令相当于指定了6 core CPU,此时超过了我们宿主机的cpu core总数4。
1 | # docker run --rm --cpus=4 -it progrium/stress -c 4 |
有–cpu-shares(貌似效果也不好)
1 | # docker run --rm --cpus=2 --cpu-shares=512 -it progrium/stress -c 4 |
–cpuset-cpus参数
该参数用来绑定容器使用的CPU core,对资源的限制较精确,但是需要外部维护绑定关系。当有多个容器都绑定到同一个core上时,需要借助–cpu-shares来分配份额。
资源抢占时
当不指定份额时,会平均分配资源:
1 | # docker run --rm --cpuset-cpus=0 -it progrium/stress -c 1 |
有–cpu-shares
1 | # docker run --rm --cpuset-cpus=0 --cpu-shares=512 -it progrium/stress -c 1 |
–cpu-period & –cpu-quota
docker提供–cpu-period、–cpu-quota两个参数控制容器可以分配到的CPU时钟周期。
--cpu-period
用来指定容器对CPU的使用要在多长时间内做一次重新分配;
--cpu-quota
用来指定在这个周期内,最多可以有多少时间用来跑这个容器。跟–cpu-shares不同的是这种配置是指定一个绝对值,而且没有弹性在里面,容器对CPU资源的使用绝对不会超过配置的值。
–cpu-period和–cpu-quota的单位为微秒(μs)。–cpu-period的最小值为1000微秒,最大值为1秒(10^6 μs),默认值为0.1秒(100000 μs)。–cpu-quota的值默认为-1,表示不做控制。
举个例子,如果容器进程需要每1秒使用单个CPU的0.2秒时间,可以将–cpu-period设置为1000000(即1秒),–cpu-quota设置为200000(0.2秒)。当然,在多核情况下,如果允许容器进程需要完全占用两个CPU,则可以将–cpu-period设置为100000(即0.1秒),–cpu-quota设置为200000(0.2秒)。
K8S 代码实现
request 被转化为 —cpu-share 参数
- 如果request=0 && limit !=0, —cpu-shares=limit;
- 如果 request != 0, —cpu-shares=request.
limit 被转化为 –cpu-quota 参数
- –cpu-preiod被强制设置为100毫秒;
- –cpu-quota = Limit * 100毫秒,但是最小为1毫秒.
在kubelet创建container的时候,kuberuntime_container.go
中的类kubeGenericRuntimeManager会调用generateContainerConfig
来生成创建container的配置文件(从k8s yaml中指定对resources的配置转化而来)。
绝大多数的参数在不同操作系统之间都是一样的,但是对资源的限制这块,Linux和Windows有自己不同的参数。因此该类会继续调用 applyPlatformSpecificContainerConfig
方法, 最终到 generateLinuxContainerConfig
来为linux系统转化参数,具体如下:
1 | // applyPlatformSpecificContainerConfig applies platform specific configurations to runtimeapi.ContainerConfig. |