本文介绍几种在K8S中限制资源使用的几种方法。

资源类型

在K8S中可以对两类资源进行限制:cpu和内存。

CPU的单位有:

  • 正实数,代表分配几颗CPU,可以是小数点,比如0.5代表0.5颗CPU,意思是一 颗CPU的一半时间。2代表两颗CPU。
  • 正整数m,也代表1000m=1,所以500m等价于0.5

内存的单位:

  • 正整数,直接的数字代表Byte
  • kKKi,Kilobyte
  • mMMi,Megabyte
  • gGGi,Gigabyte
  • tTTi,Terabyte
  • pPPi,Petabyte

方法一:在Pod Container Spec中设定资源限制

在K8S中,对于资源的设定是落在Pod里的Container上的,主要有两类,limits控制上限,requests控制下限。其位置在:

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory

举例:

apiVersion: v1 kind: Pod metadata: name: frontend spec: containers: - name: ... image: ... resources: requests: memory: "64Mi" cpu: "250m" limits: memory: "128Mi" cpu: "500m"

方法二:在Namespace中限定

方法一虽然很好,但是其不是强制性的,因此很容易出现因忘记设定limits/request,导致Host资源使用过度的情形,因此我们需要一种全局性的资源限制设定,以防止这种情况发生。K8S通过在Namespace设定LimitRange来达成这一目的。

配置默认request/limit

如果配置里默认的request/limit,那么当Pod Spec没有设定request/limit的时候,会使用这个配置,有效避免无限使用资源的情况。

配置位置在:

  • spec.limits[].default.cpu,default limit
  • spec.limits[].default.memory,同上
  • spec.limits[].defaultRequest.cpu,default request
  • spec.limits[].defaultRequest.memory,同上

例子:

apiVersion: v1 kind: LimitRange metadata: name: <name> spec: limits: - default: memory: 512Mi cpu: 1 defaultRequest: memory: 256Mi cpu: 0.5 type: Container

配置request/limit的约束

我们还可以在K8S里对request/limit进行以下限定:

  • 某资源的request必须>=某值
  • 某资源的limit必须<=某值

这样的话就能有效避免Pod Spec中乱设limit导致资源耗尽的情况,或者乱设request导致Pod无法得到足够资源的情况。

配置位置在:

  • spec.limits[].max.cpulimit必须<=某值
  • spec.limits[].max.memory,同上
  • spec.limits[].min.cpurequest必须>=某值
  • spec.limits[].min.memory,同上

例子:

apiVersion: v1 
kind: LimitRange
metadata: name: <name>
spec:
  limits:
  - max:
    memory: 1Gi
    cpu: 800m
   min:
    memory: 500Mi
    cpu: 200m   type: Container

在关于kubernetes资源限制的这个由两部分组成的系列文章的第一篇文章中,我讨论了如何使用ResourceRequirements对象来设置容器中容器的内存限制,以及容器运行时和linux控制组如何实现这些限制。我还谈到了请求之间的区别,用于在调度时通知调度程序pod的需求,以及限制,用于在主机系统处于内存压力时帮助内核强制执行使用限制。在这篇文章中,我想继续详细查看cpu时间请求和限制。阅读完第一篇文章并不是从这篇文章中获取价值的先决条件,但我建议你在某些时候阅读它们,以便全面了解工程师和集群管理员可以使用的控件。

CPU限制

正如我在第一篇文章中提到的,cpu限制比内存限制更复杂,原因将在下面说明。好消息是cpu限制是由我们刚才看到的相同cgroups机制控制的,所以所有相同的内省思想和工具都适用,我们可以只关注差异。让我们首先将cpu限制添加回上次查看的示例资源对象:

单位后缀m代表“千分之一核心”,因此该资源对象指定容器进程需要50/1000的核心(5%)并且允许最多使用100/1000核心(10%)。同样,2000m将是两个完整核心,也可以指定为2或2.0。让我们创建一个只有cpu请求的pod,看看它是如何在docker和cgroup级别配置的:

我们可以看到kubernetes配置了50m cpu请求:

我们还可以看到docker配置了具有相同限制的容器:

为什么51,而不是50?cpu控制组和docker都将核划分为1024个共享,而kubernetes将其划分为1000. docker如何将此请求应用于容器进程?与设置内存限制导致docker配置进程的内存cgroup的方式相同,设置cpu限制会导致它配置cpu,cpuacct cgroup:

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

你可能会惊讶地发现设置cpu请求会将值传播到cgroup,因为在上一篇文章中我们看到设置内存请求没有。底线是关于内存软限制的内核行为对kubernetes不是很有用,因为设置cpu.shares很有用。我将在下面详细讨论为什么。那么当我们设置cpu限制时会发生什么?我们来看看:

现在我们还可以在kubernetes pod资源对象中看到限制:

并在docker容器配置中:

如上所述,cpu请求存储在HostConfig.CpuShares属性中。但是,cpu限制不太明显。它由两个值表示:HostConfig.CpuPeriod和HostConfig.CpuQuota。这些docker容器配置属性映射到进程的cpu、cpuacct cgroup的两个附加属性:cpu.cfs_period_us和cpu.cfs_quota_us。我们来看看那些:

正如预期的那样,这些值设置为与docker容器配置中指定的值相同。但是这两个属性的值是如何从我们的pod中的100m cpu限制设置得出的,它们如何实现该限制?答案在于cpu请求和cpu限制是使用两个独立的控制系统实现的。请求使用cpu共享系统,两者中较早的一个。Cpu共享将每个核划分为1024个切片,并保证每个进程将获得这些切片的比例份额。如果有1024个切片,并且两个进程中的每一个都将cpu.shares设置为512,那么它们将分别获得大约一半的可用时间。但是,cpu共享系统无法强制执行上限。如果一个进程不使用其共享,则另一个进程可以自由使用。

大约在2010年,谷歌和其他人注意到这可能会导致问题。作为回应,增加了第二个功能更强大的系统:cpu带宽控制。带宽控制系统定义一个周期,通常为1/10秒,或100000微秒,以及一个配额,表示允许进程在cpu上运行的那个周期内的最大切片数。在这个例子中,我们要求我们的pod上的cpu限制为100m。这是100/1000的核,或100000微秒的CPU时间中的10000。因此,我们的限制请求转换为在进程的cpu,cpuacct cgroup上设置cpu.cfs_period_us = 100000和cpu.cfs_quota_us = 10000。顺便说一下,这些名称中的cfs代表Completely Fair Scheduler,它是默认的linux cpu调度程序。还有一个实时调度程序,它有自己相应的配额值。

所以我们已经看到在kubernetes中设置cpu请求最终会设置cpu.shares cgroup属性,并且通过设置cpu.cfs_period_us和cpu.cfs_quota_us来设置cpu限制可以使用不同的系统。与内存限制一样,请求主要对调度程序有用,调度程序使用它来查找至少具有多个可用cpu共享的节点。与内存请求不同,设置cpu请求还会在cgroup上设置一个属性,以帮助内核实际将该数量的共享分配给进程。限制也与内存区别对待。超出内存限制使你的容器进程成为oom-killing的候选者,而你的进程基本上不能超过设置的cpu配额,并且永远不会因为尝试使用比分配的更多的CPU时间而被驱逐。系统会在调度程序中强制执行配额,以便进程在限制时受到限制。

如果你未在容器上设置这些属性,或将它们设置为不准确的值,会发生什么?与内存一样,如果设置限制但不设置请求,kubernetes会将请求默认为限制。如果你非常了解工作负载所需的CPU时间,那么这可能会很好。设置一个没有限制的请求怎么样?在这种情况下,kubernetes能够准确地安排你的pod,并且内核将确保它至少获得所请求的共享数量,但是你的进程将不会被阻止使用超过所请求的cpu数量,这将被盗来自其他进程的cpu共享(如果可用)。既不设置请求也不设置限制是最糟糕的情况:调度程序不知道容器需要什么,并且进程对cpu共享的使用是无限的,这可能会对节点产生负面影响。这是我想要谈论的最后一件事的好消息:确保命名空间中的默认限制。

默认限制

鉴于我们刚刚讨论过关于忽略资源限制对pod容器的负面影响的所有内容,你可能认为能够设置默认值会很好,因此允许进入群集的每个pod都至少设置了一些限制。Kubernetes允许我们使用LimitRange v1 api对象在每个命名空间的基础上执行此操作。要建立默认限制,请在要将其应用于的命名空间中创建LimitRange对象。这是一个例子:

这里的命名可能有点令人困惑,所以让我们简单地把它拆掉。default key低于限制表示每个资源的默认限制。在这种情况下,任何允许没有内存限制的命名空间的pod都将被分配100Mi的限制。任何没有cpu限制的pod都将被分配100m的限制。defaultRequest键用于资源请求。如果在没有内存请求的情况下创建pod,则会为其分配默认请求50Mi,如果没有cpu请求,则默认值为50m。max和min键有点不同:基本上如果设置了pod,如果设置了违反这些边界的请求或限制,则不会允许pod进入命名空间。我没有找到这些的用途,但也许你有,如果是这样发表评论,让我们知道你对他们做了什么。

LimitRange中规定的默认值由LimitRanger插件应用于pod,这是一个kubernetes许可控制器。入场控制器是插件,在api接受对象之后但在创建pod之前有机会修改podSpecs。对于LimitRanger,它会查看每个pod,如果它没有指定命名空间中存在默认设置的给定请求或限制,则它将应用该默认值。通过检查pod元数据中的注释,你可以看到LimitRanger已在你的pod上设置了默认值。这是LimitRanger应用100m的默认cpu请求的示例:

这包含了对kubernetes资源限制的看法。我希望这个信息对你有所帮助。如果你有兴趣阅读有关使用资源限制和默认值,linux cgroups或内存管理的更多信息,我已经提供了一些指向下面这些主题的更详细信息的链接。

理解k8s资源限制系列(二):cpu time的更多相关文章

  1. 深入理解JAVA I/O系列二:字节流详解

    流的概念 JAVA程序通过流来完成输入/输出.流是生产或消费信息的抽象,流通过JAVA的输入输出与物理设备链接,尽管与它们链接的物理设备不尽相同,所有流的行为具有相同的方式.这样就意味一个输入流能够抽 ...

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

    写在前面 在上一篇关于Kubernetes资源限制的文章我们讨论了如何通过ResourceRequirements设置Pod中容器内存限制,以及容器运行时是如何利用Linux Cgroups实现这些限 ...

  3. [知识库分享系列] 二、.NET(ASP.NET)

    最近时间又有了新的想法,当我用新的眼光在整理一些很老的知识库时,发现很多东西都已经过时,或者是很基础很零碎的知识点.如果分享出去大家不看倒好,更担心的是会误人子弟,但为了保证此系列的完整,还是选择分享 ...

  4. Wireshark入门与进阶系列(二)

    摘自http://blog.csdn.net/howeverpf/article/details/40743705 Wireshark入门与进阶系列(二) “君子生非异也,善假于物也”---荀子 本文 ...

  5. 混部之殇-论云原生资源隔离技术之CPU隔离(一)

    作者 蒋彪,腾讯云高级工程师,10+年专注于操作系统相关技术,Linux内核资深发烧友.目前负责腾讯云原生OS的研发,以及OS/虚拟化的性能优化工作. 导语 混部,通常指在离线混部(也有离在线混部之说 ...

  6. 深入理解mysql之BDB系列(1)---BDB相关基础知识

        深入理解mysql之BDB系列(1) ---BDB相关基础知识 作者:杨万富   一:BDB体系结构 1.1.BDB体系结构 BDB总体的体系结构如图1.1所看到的,包括五个子系统(见图1.1 ...

  7. sed修炼系列(二):sed武功心法(info sed翻译+注解)

    sed系列文章: sed修炼系列(一):花拳绣腿之入门篇sed修炼系列(二):武功心法(info sed翻译+注解)sed修炼系列(三):sed高级应用之实现窗口滑动技术sed修炼系列(四):sed中 ...

  8. Storm系列二: Storm拓扑设计

    Storm系列二: Storm拓扑设计 在本篇中,我们就来根据一个案例,看看如何去设计一个拓扑, 如何分解问题以适应Storm架构,同时对Storm拓扑内部的并行机制会有一个基本的了解. 本章代码都在 ...

  9. struts2官方 中文教程 系列二:Hello World项目

    先贴个本帖的地址,免得其它网站被爬去了struts2入门系列二之Hello World  即 http://www.cnblogs.com/linghaoxinpian/p/6898779.html ...

随机推荐

  1. 全网最深分析SpringBoot MVC自动配置失效的原因

    前言 本来没有计划这一篇文章的,只是在看完SpringBoot核心原理后,突然想到之前开发中遇到的MVC自动失效的问题,虽然网上有很多文章以及官方文档都说明了原因,但还是想亲自看一看,本以为很简单的事 ...

  2. 在Ubuntu 16.04上编译OpenJDK8的源代码

    本文将详细介绍在Ubuntu16.04上对OpenJDK8进行编译. 1.准备编译环境 使用的操作系统为Ubuntu16.04,如果读者没有安装Ubuntu,可以在Windows上使用虚拟机的方式进行 ...

  3. Pycharm连接MySQL后出现不出现数据库或表,出现其他文件的问题

    在使用pycharm连接MySQL,配置完成,测试连接通过之后,还是不能显示数据库中的表,出现了许多像armscii8_bin.armscii8_general_ci和ascii_bin等的文件. 解 ...

  4. 2020年,web前端还好找工作吗?

    好不好找是个相对概念,如果你要跟几年前相比,那么一定是「相对不好找」.原因所学的知识过时 用 Vue 模仿一个饿了么就能找工作的时代一去不复返. 但是为什么现在一堆大厂喊着招聘难呢? 那是因为候选人技 ...

  5. No mapping found for HTTP request with URI [/***] in DispatcherServlet with name 'dispatcherServlet'

    相信不少Springboot初学者和我一样,都遇到上边这个提示,明明路径都是对的,但就是找不到对于的页面而404了,这也困扰我很长一段时间,我也是不得其解,百度上也鲜有合理回答,因为以前使用的时候,明 ...

  6. (私人收藏)精美PPT模板

    精美PPT模板 https://pan.baidu.com/s/1vsRnX5h7t3MZ7qdrFvuI1wsucr

  7. HDU5961 传递

    传递 因为文化课复习实在捉急qwq,题解就一切从简了qwq 简单说一说 上来一看这道题没看出来突破点在哪... 去HDU上看原题,发现原题是带样例的图解的,然鹅还是没找到思路(太菜了吧) 没办法看了一 ...

  8. POJ 1852 Ants(贪心)

    POJ 1852 Ants 题目大意 有n只蚂蚁在木棍上爬行,每只蚂蚁的速度都是每秒1单位长度,现在给你所有蚂蚁初始的位置(蚂蚁运动方向未定),蚂蚁相遇会掉头反向运动,让你求出所有蚂蚁都·掉下木棍的最 ...

  9. python—模块optparse的用法

    1.什么是optparse: 在工作中我们经常要制定运行脚本的一些参数,因为有些东西是随着我么需求要改变的,所以在为们写程序的时候就一定不能把写死,这样我们就要设置参数 optparse用于处理命令行 ...

  10. vue重置data里的值

    this.$options.data() 这个可以获取原始的data值,this.$data 获取当前状态下的data,拷贝重新赋值一下就行了. Object.assign(this.$data, t ...