写在前面

上一篇关于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/1000的核心(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/3be263e7a8372b12d2f8f8f9b4251f110b79c2a3bb9e6857b2f1473e640e8e75

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

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/64b5f1b636dafe6635ddd321c5b36854a8add51931c7117025a694281fb11444/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 472a**e32a5 --format '{{.HostConfig.CpuShares}} {{.HostConfig.CpuQuota}} {{.HostConfig.CpuPeriod}}'

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/f0845c65c3073e0b7b0b95ce0c1eb27f69d12b1fe2382b50096c4b59e78cdf71/cpu.cfs_period_us

100000

$ sudo cat /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pod2f1b50b6-db13-11e8-b1e1-42010a800070/f0845c65c3073e0b7b0b95ce0c1eb27f69d12b1fe2382b50096c4b59e78cdf71/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和一些公司注意到了这个可能存在的问题(https://ai.google/research/pubs/pub36669)。进而合并了一个更加强大的秒级响应的系统:CPU带宽控制。带宽控制系统定义了一个通常是1/10秒的周期,或者100000微秒,以及一个表示周期里一个进程可以使用的最大分片数配额。在这个例子里,我们为我们的Pod申请了100mCPU,它等价于100/1000的核心,或者10000/100000毫秒的CPU时间。所以我们的CPU requests被翻译为设置这个进程的cpu,cpuacct的配置为cpu.cfs_period_us=100000并且cpu.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设置默认的的资源限制。

默认限制

在了解到不为Pod配置资源限制会有一些负面效应后,你可能会想到给它们设置默认值,所以每个提交到集群的Pod都会有一个默认设置。Kubernetes允许我们这么做:基于Namespace,使用v1版本的LimitRange API对象实现。你可以通过在你想限制的Namespace里创建LimitRange对象来建立默认资源限制。示例如下:

apiVersion: v1 

kind: LimitRange 

metadata: 

    name: default-limit 

spec: 

    limits: 

    - default: 

        memory: 100Mi 

        cpu: 100m 

      defaultRequest: 

        memory: 50Mi 

        cpu: 50m 

    - max: 

        memory: 512Mi 

        cpu: 500m 

    - min: 

        memory: 50Mi  

        cpu: 50m 

      type: Container

这里的命名可能会有些迷惑,让我们把它拆分开看看。limits下的default键代表了每种资源的默认limits。在这个场景里,指定Namespace里的任何没有配置内存限制的Pod都会被设置一个默认100Mi的limits,任何没有CPU限制的Pod会被设置一个默认100m的limits。defaultRequest键表示资源requests。如果创建了一个Pod没有指定内存requests的Pod,它会被自动分配默认50Mi的内存,以及如果没有指定CPU requests的话,会被默认分配默认50m的CPU。max和min键则有些不同:基本上如果一个Pod的requests或limits超过了这两种规定的上下界,这个Pod就无法提交通过创建。我目前还没有找到这种用法的场景,但是你可能会用到,所以如果有的话请你留言告诉我们你用它解决了什么问题。

默认的LimitRange设置通过LimitRange插件应用到Pod上,这个插件存在于Kubernetes Admission Controller里。Admission Controller是可能会在对象被API接收之后,实际创建之前修改它定义的插件集合。在LimitRange场景里,它会检查每个Pod,如果它没有指明requests和limits,并且Namespace设置里设置了默认值,它就会把这个默认值应用到Pod上。你会发现LimitRanger通过检查Pod metadata的annotations里来设置默认值。

深入理解Kubernetes资源限制:CPU的更多相关文章

  1. 深入理解 Kubernetes 资源限制:CPU

    原文地址:https://www.yangcs.net/posts/understanding-resource-limits-in-kubernetes-cpu-time/ 在关于 Kubernet ...

  2. 深入理解Kubernetes资源限制:内存

    写在前面 当我开始大范围使用Kubernetes的时候,我开始考虑一个我做实验时没有遇到的问题:当集群里的节点没有足够资源的时候,Pod会卡在Pending状态.你是没有办法给节点增加CPU或者内存的 ...

  3. 理解k8s资源限制系列(二):cpu time

    本文介绍几种在K8S中限制资源使用的几种方法. 资源类型 在K8S中可以对两类资源进行限制:cpu和内存. CPU的单位有: 正实数,代表分配几颗CPU,可以是小数点,比如0.5代表0.5颗CPU,意 ...

  4. Kubernetes K8S之CPU和内存资源限制详解

    Kubernetes K8S之CPU和内存资源限制详解 Pod资源限制 备注:CPU单位换算:100m CPU,100 milliCPU 和 0.1 CPU 都相同:精度不能超过 1m.1000m C ...

  5. 新手学习FFmpeg - 如何编写Kubernetes资源文件

    Kubernetes API的使用方式 Kubernetes API属于声明式API编程, 它和常用的命令式编程有一些区别. 通俗的说,命令式编程是第一人称,我要做什么,我要怎么做. 操作系统最喜欢这 ...

  6. [Kubernetes]资源模型与资源管理

    作为 Kubernetes 的资源管理与调度部分的基础,需要从它的资源模型说起. 资源管理模型的设计 我们知道,在 Kubernetes 里面, Pod 是最小的原子调度单位,这就意味着,所有和调度和 ...

  7. [置顶] kubernetes资源类型--持久化存储Persistent Volume和Persistent Volume Claim

    概念 存储管理跟计算管理是两个不同的问题.理解每个存储系统是一件复杂的事情,特别是对于普通用户来说,有时并不需要关心各种存储实现,只希望能够安全可靠地存储数据. 为了简化对存储调度,K8S对存储的供应 ...

  8. Kubernetes资源与对象简述

    资料 k8s基本对象概念 背景 资源和对象   Kubernetes 中的所有内容都被抽象为"资源",如 Pod.Service.Node 等都是资源."对象" ...

  9. Kubernetes as Database: 使用kubesql查询kubernetes资源

    写在前面 kubectl虽然查询单个的kubernetes资源或者列表都已经比较方便,但是进行更为多个资源的联合查询(比如pod和node),以及查询结果的二次处理方面却是kubectl无法胜任的.所 ...

随机推荐

  1. halcon学习_字符识别1

    实例图片 大体步骤:1.读取图片                   2.图像预处理(阈值分割,提取标签部分,缩小处理区域)                  3.将标签区域的最小外接矩形,从原图中剪 ...

  2. golang 切片扩容, 时间复杂度

    在切片扩容时,如果原来的底层数组足够大,能放的下 append 的数据,就不会新建底层数组.而如果不够的话,则会分配一个新的数组.也因此是 O(n) 的时间复杂度

  3. 批量添加删除Windows server DNS服务 恶意域名 * A记录 指向 127.0.0.1(2019年6月5日更新)

    下载链接:https://pan.baidu.com/s/1OUHyvnIfXYF0PdiT-VRyHw  密码:7gjj 注意!本解决方案在本地的Windows server服务器上把恶意域名指向1 ...

  4. Python练手项目:20行爬取全王者全英雄皮肤

    引言    王者荣耀大家都玩过吧,没玩过的也应该听说过,作为时下最火的手机MOBA游戏,咳咳,好像跑题了.我们今天的重点是爬取王者荣耀所有英雄的所有皮肤,而且仅仅使用20行Python代码即可完成. ...

  5. tp3.2判断修改成功

    save方法的返回值是影响的记录数,如果返回false则表示更新出错,因此一定要用恒等来判断是否更新失败. 一开始用这种判断, if (!$edit_flag && $edit_fla ...

  6. Azure经典虚拟机(Windows)如何监测单个磁盘的使用空间

    Azure云平台创建经典虚拟机(Windows)后,发现仪表板的监测项下默认是没有针对磁盘空间进行检测的指标的 本地机器安装Windows Azure Powershell模块,并通过如下命令登陆并查 ...

  7. [转帖]CentOS 8 都发布了,你还不会用 nftables?

    CentOS 8 都发布了,你还不会用 nftables? https://www.cnblogs.com/ryanyangcs/p/11611730.html 改天学习一下 原文链接:CentOS ...

  8. wordpress5.0+中 Notice: Undefined index: HTTP_REFERER 问题解决

    都说现在搭网站很简单了,但真遇到问题了还真不一定能解决. 这次搭建的网站是用的wordpress版本5.0.4,以为操作和以前的低版本一样,结果做出来还是遇到问题了. 网站搭好后,首页总在顶端出现一行 ...

  9. 基于requests模块的代理

    1.什么是代理? ​ 代理:将网络请求发送给代理服务器,通过代理服务器做中介,将请求转发给目标服务器并将响应返回,从而完成网络通信. 2.为什么使用代理? ​ 使用爬虫抓取批量资源时,在短时间内会对服 ...

  10. 【计算几何】The Queen’s Super-circular Patio

    The Queen’s Super-circular Patio 题目描述 The queen wishes to build a patio paved with of a circular cen ...