深入理解Kubernetes资源限制:CPU

写在前面

在上一篇关于Kubernetes资源限制的文章我们讨论了如何通过ResourceRequirements设置Pod中容器内存限制,以及容器

运行时是如何利用Linux Cgroups实现这些限制的。也分析了requests是用来通知调度器Pod所需资源需求和limits是在宿主

机遇到内存压力时帮助内核限制资源二者的区别。


在本文中,我会继续深入探讨CPU时间的requests和limits。你是否阅读过第一篇文章并不会影响本文的学习,但是我建议你

两篇文章都读一读,从而得到工程师或者集群管理员视角的集群控制全景。



CPU时间

正如我在第一篇文章中指出,限制CPU时间要比限制内存限制更加复杂,好消息是限制CPU也是根据我们前面所了解到的

cgroups机制控制的,与限制内存的原理是通用的,我们只需要关注一些细节即可。我们从向前文的例子里添加CPU时间限

制开始:

resources:

requests:

memory: 50Mi

cpu: 50m

limits:

memory: 100Mi

cpu: 100m


单位后缀m表示“千分之一个核心”,所以这个资源对象定义了容器进程需要50/1000的核心(5%),并且最多使用100/100

0的核心(10%)。类似的,2000m表示2颗完整的核心,当然也可以用2或者2.0来表示。让我们创建一个只拥有CPU

 requests的Pod,然后看看Docker是如何配置cgroups的:


$ kubectl run limit-test --image=busybox --requests “cpu=50m” --command – /bin/sh -c “while true; do sleep 

2; done”


deployment.apps “limit-test” created


我们能够看到Kubernetes已经配置了50m的CPU requests:


$ kubectl get pods limit-test-5b4c495556-p2xkr -o=jsonpath=’{.spec.containers[0].resources}’


[cpu:50m]]


我们也可以看到Docker配置了同样的limits:


$ docker ps | grep busy | cut -d’ ’ -f1


f2321226620e


$ docker inspect f2321226620e --format ‘{{.HostConfig.CpuShares}}’


51


为什么是51而不是50?CPU cgroup和Docker都把一个核心划分为1024份,而Kubernetes则划分为1000份。

那么Docker如何把它应用到容器进程上?设置内存限制会让Docker来配置进程的memory cgroup,同样设置CPU限制会

让它配置cpu, cpuacct cgroup。


$ ps ax | grep /bin/sh


60554 ? Ss 0:00 /bin/sh -c while true; do sleep 2; done


$ sudo cat /proc/60554/cgroup



4:cpu,cpuacct:/kubepods/burstable/pode12b33b1-db07-11e8-b1e1-42010a800070/3be263e7a8372b12d2f8f8f

9b4251f110b79c2a3bb9e6857b2f1473e640e8e75


ls -l /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pode12b33b1-db07-11e8-b1e1-42010a800070/3be263e

7a8372b12d2f8f8f9b4251f110b79c2a3bb9e6857b2f1473e640e8e75


total 0


drwxr-xr-x 2 root root 0 Oct 28 23:19 .


drwxr-xr-x 4 root root 0 Oct 28 23:19 …



-rw-r–r-- 1 root root 0 Oct 28 23:19 cpu.shares


Docker的HostConfig.CpuShares容器属性映射到了cgroup的cpu.shares上,所以让我们看看:


$ sudo cat /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/podb5c03ddf-db10-11e8-b1e1-42010a800070/6

4b5f1b636dafe6635ddd321c5b36854a8add51931c7117025a694281fb11444/cpu.shares


51


你可能会惊奇地发现设置一个CPU请求会把这个值发送到cgroup去,而上篇文章中设置内存却并非如此。下面这行内核对内

存软限制的行为对Kubernetes来说没什么用处,而设置了cpu.shares则是有用的。我等会会对此做出解释。那么当我们设

置cpu限制时发生了什么?让我们一起找找看:


$ kubectl run limit-test --image=busybox --requests “cpu=50m” --limits “cpu=100m” --command – /bin/sh 

-c “while true; do sleep 2; done”


deployment.apps “limit-test” created


现在我们回过头来看看Kubernetes Pod资源对象的限制:


$ kubectl get pods limit-test-5b4fb64549-qpd4n -o=jsonpath=’{.spec.containers[0].resources}’


map[limits:map[cpu:100m] requests:map[cpu:50m]]


在Docker容器配置里:


$ docker ps | grep busy | cut -d’ ’ -f1


f2321226620e


$ docker inspect 472abbce32a5 --format ‘{{.HostConfig.CpuShares}} {{.HostConfig.CpuQuota}} {{.HostConfig.Cp

uPeriod}}’


51 10000 100000


正如我们所见,CPU请求存放在HostConfig.CpuShares属性里。CPU限制,尽管不是那么明显,它由

HostConfig.CpuPeriod和HostConfig.CpuQuota两个值表示,这些Docker容器配置映射为进程的cpu, cpuacct cgroup的

两个属性:cpu.cfs_period_us和cpu.cfs_quota_us。让我们仔细看看:


$ sudo cat /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pod2f1b50b6-db13-11e8-b1e1-42010a800070/f08

45c65c3073e0b7b0b95ce0c1eb27f69d12b1fe2382b50096c4b59e78cdf71/cpu.cfs_period_us


100000


$ sudo cat /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pod2f1b50b6-db13-11e8-b1e1-42010a800070/f084

5c65c3073e0b7b0b95ce0c1eb27f69d12b1fe2382b50096c4b59e78cdf71/cpu.cfs_quota_us


10000


如我们所料这两个配置会同样配置到Docker容器配置里。但是这些值是怎么从Pod的100m CPU限制里转换过来,并且是

怎么实现的呢?原来CPU requests和CPU limits是由两套不同的cgroup分别进行控制的。Requests使用CPU分片系统,是

二者中出现较早的一个。Cpu分片是将每个核心划分为1024份,并且保证每个进程会接收到一定比例的CPU分片。如果只

有1024片而这两个进程都设置cpu.shares为512,那么这两个进程会各自得到一半的CPU时间。CPU分片系统并不能指定

上界,也就是说如果一个进程没有使用它的这一份,其它进程是可以使用的。


在2010年左右Google和一些公司注意到了这个可能存在的问题。进而合并了一个更加强大的秒级响应的系统:CPU带宽控

制。带宽控制系统定义了一个通常是1/10秒的周期,或者100000微秒,以及一个表示周期里一个进程可以使用的最大分片数

配额。在这个例子里,我们为我们的Pod申请了100mCPU,它等价于100/1000的核心,或者10000/100000毫秒的CPU时

间。所以我们的CPU requests被翻译为设置这个进程的cpu,cpuacct的配置为cpu.cfs_period_us=100000并且

c pu.cfs_quota_us=10000。cfs表示完全公平调度,它是Linux默认的CPU调度器。同时还有一个响应quota值的实

时调度器 。



我们为Kubernetes设置CPU requests实际上是设置了cpu.shares cgroup属性,设置CPU limits配置了另一个子系统的

cpu.cfs_period_us和cpu.cfs_quota_us属性。就像内存requests对调度器的意义一样,CPU requests会让调度器选择至

少拥有那么多可用CPU分片的节点。不同于内存requests,设置CPU requests也会给cgroup设置相应的属性,帮助内核

实际给进程分配一样数量的CPU核心分片。Limits的处理也与内存不一样。超出内存limits会让你的容器进程成为oom-kill的

选项,但是你的进程基本上不可能超出设置的cpu配额,并且永远不会因为试着使用更多CPU而被驱逐。系统在调度器那里

加强了配额的使用,所以进程在到达limits后只会被限流。


如果你并未为你的容器设置这些属性,或者给他们设置了不准确的值会怎么样?作为内存,如果你设置了limits但并未指

定requests,Kubernetes会默认让request指向limit。如果你对你的应用需要多少CPU时间很清楚的话这没问题。那么如果

设置requests而不设置limits呢?在这个场景里Kubernetes仍然可以精确地调度你的Pod,内核也会保证它能得到需要的最

少资源配额。但是不会限制你的进程只能使用requested数量的资源,它可能会偷取别的进程的分片。不设置requests和

limits是最坏的情况,调度器不知道容器需要多少资源,进程的CPU分片也是无限的,这也许会对节点带来不利的影响。这引出了我想要说的最后一件事情:为每个namespace设置默认的的资源限制。


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/69908804/viewspace-2638397/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/69908804/viewspace-2638397/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值