什么是资源
在 Kubernetes 中,有两个基础但是非常重要的概念:Node 和 Pod。Node 即节点,是对集群资源的抽象;Pod 是对容器的封装,是应用运行的实体。Node 提供资源,而 Pod 使用资源,这里的资源分为计算(CPU、Memory、GPU)、存储(Disk、SSD)、网络(Network Bandwidth、IP、Ports)。这些资源提供了应用运行的基础,正确理解这些资源以及集群调度如何使用这些资源,对于大规模的 Kubernetes 集群来说至关重要,不仅能保证应用的稳定性,也可以提高资源的利用率。
Kubernetes 资源模型
在 Kubernetes 里,Pod 是最小的原子调度单位。这也就意味着,所有跟调度和资源管理相关的属性都应该是属于 Pod 对象的字段。而这其中最重要的部分,就是 Pod 的CPU 和内存配置
在 Kubernetes 中,像 CPU 这样的资源被称作“可压缩资源”(compressible resources)。它的典型特点是,当可压缩资源不足时,比如 CPU 时间片,Pod 只会“饥饿”,但不会退出。而像内存这样的资源,则被称作“不可压缩资源(incompressible resources)。当不可压缩资源不足时,也就无法继续申请资源,Pod 就会因为 OOM(Out-Of-Memory)被内核杀死。
CPU 的使用时间是可压缩的,换句话说它本身无状态,申请资源很快,也能快速正常回收;而内存和磁盘资源是不可压缩的,因为它是有状态的(内存里面保存的数据),申请资源很慢(需要计算和分配内存块的空间),并且回收可能失败(被占用的内存一般不可回收)。
请求和限制(requests & limits)
请求和限制是 Kubernetes 用于控制 CPU 和内存等资源的机制。
resources:
requests:
cpu: 50m
memory: 50Mi
limits:
cpu: 100m
memory: 100Mi
- requests:定义了对应容器需要的最小资源量。请求是保证容器能够得到的资源。 如果容器请求资源,Kubernetes会将其调度到可以为其提供该资源的节点上。
- limits:定义了这个容器最大可以消耗的资源上限,防止过量消耗资源导致资源短缺甚至宕机。特别的,设置为 0 或者不设置 limit 表示对使用的资源不做限制。值得一提的是,当设置 limits 而没有设置 requests 时,Kubernetes 默认令 requests 等于 limits。
请求和限制基于单个容器。Pod 中的每个容器都有自己的限制和请求,但由于 Pod 总是被认为是一个组,因此您需要将组内每个容器的限制和请求加在一起以获取 Pod 的聚合值。
资源类型
CPU
CPU 可分配的是使用时间,也就是操作系统管理的时间片。CPU 资源以核数标识,一核 CPU 相对于云服务商的 1 vCPU/Core 或者物理服务器的一个超线程核,也就是操作系统 /proc/cpuinfo
中列出来的核数。
因为对资源进行了池化和虚拟化,因此 Kubernetes 允许配置非整数个的核数。如果您的容器需要运行两核(K8S不保证独占两个物理CPU核心,而是保证相当于两个CPU核的时间片),那么您将设置值2000m
或者 2
。 如果您的容器只需要1/4
的核心,那么您将设置一个250m
的值。其中后缀 m
表示千分之一的意思。
内存
内存比较容易理解,是通过字节(bytes)大小指定的。如果直接一个数字,后面没有任何单位,表示这么多字节的内存;数字后面还可以跟着单位, 支持的单位有 E
、P
、T
、G
、M
、K
,前者分别是后者的 1000
倍大小的关系,此外还支持 Ei
、Pi
、Ti
、Gi
、Mi
、Ki
,其对应的倍数关系是 2^10 = 1024
。比如要使用 100M 内存的话,直接写成 100Mi
即可。此外,E
和 EB
等价,即省略字节的单位 B
。
目前 Kubernetes 支持对 CPU/Memory/GPU 三种资源的使用,Kubernetes 计划未来支持更多的资源类型。
服务质量等级(QoS)
Requests 和 Limits 的配置除了表明资源情况和限制资源使用之外,还有一个隐藏的作用:它决定了 Pod 的 QoS 等级。
QoS(Quality of Service),大部分译为“服务质量等级”,又译作“服务质量保证”,是作用在 Pod 上的一个配置。
使用 kubectl get pod -o yaml
可以看到 pod 的配置输出中有 qosClass
一项。 QoS 不是通过一个配置项来配置的,而是当 Kubernetes 创建一个 Pod 时,它会通过Pod CPU /内存的 limits
与 requests
值的大小给这个 Pod 分配一个以下 QoS 等级:
- Guaranteed:Pod 里的每个容器都必须有内存和 CPU 限制和请求,而且值必须相等。
- Burstable:Pod 里至少有一个容器有内存或者 CPU 请求且不满足 Guarantee 等级的要求,即内存和 CPU 的值设置的不同。
- BestEffort:容器必须没有任何内存或者 CPU 的限制或请求。
在请求和限制一节中我们提到:如果 Pod 没有配置 Limits ,那么它可以使用节点上任意多的可用资源。这类 Pod 能灵活使用资源,但这也导致它不稳定且危险,对于这类 Pod 我们一定要在它占用过多资源导致节点资源紧张时处理掉。优先处理这类 Pod,而不是处理资源使用处于自己请求范围内的 Pod 是非常合理的想法,而这就是 Pod QoS 的含义:根据 Pod 的资源请求把 Pod 分成不同的重要性等级。
Kubernetes 会根据 Pod 的 QoS 等级,主要用于以下两个场景:
- 调度场景:调度算法会根据不同的服务质量等级确定可以将 Pod 调度到哪些节点上。
- 回收场景:当资源不足的时候,Kubernetes 会优先 kill 掉服务质量等级低的 Pod。
资源配额(Resouce Quota)
前面讲到的资源管理和调度可以认为 kubernetes 把这个集群的资源整合起来,组成一个资源池,每个应用(pod)会自动从整个池中分配资源来使用。默认情况下只要集群还有可用的资源,应用就能使用,并没有限制。kubernetes 本身考虑到了多用户和多租户的场景,提出了 namespace 的概念来对集群做一个简单的隔离。
基于 namespace,kubernetes 还能够对资源进行隔离和限制,这就是 resource quota 的概念,翻译成资源配额,它限制了某个 namespace 可以使用的资源总额度。这里的资源包括 cpu、memory 的总量,也包括 kubernetes 自身对象(比如 pod、services 等)的数量。通过 resource quota,kubernetes 可以防止某个 namespace 下的用户不加限制地使用超过期望的资源,比如说不对资源进行评估就大量申请 16核 CPU 32G内存的 pod。
下面是一个资源配额的实例,它限制了 namespace 只能使用 20核 CPU 和 1G 内存,并且能创建 10 个 pod、20个 rc、5个 service,可能适用于某个测试场景。
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota
spec:
hard:
cpu: "20"
memory: 1Gi
pods: "10"
replicationcontrollers: "20"
resourcequotas: "1"
services: "5"
resource quota 能够配置的选项还很多,比如 GPU、存储、configmaps、persistentvolumeclaims 等等,更多信息可以参考官方的文档。
Resource quota 要解决的问题和使用都相对独立和简单,但是它也有一个限制:那就是它不能根据集群资源动态伸缩。一旦配置之后,resource quota 就不会改变,即使集群增加了节点,整体资源增多也没有用。kubernetes 现在没有解决这个问题,但是用户可以通过编写一个 controller 的方式来自己实现。
Pod 优先级 (Priority)
除了 QoS,Pod 还可以有优先级。 优先级表示一个 Pod 相对于其他 Pod 的重要性。 如果一个 Pod 无法被调度,调度程序会尝试抢占(驱逐)较低优先级的 Pod, 以使悬决 Pod 可以被调度。使用 Pod 优先级的方式如下:
- 新增一个或多个 PriorityClass。
- 创建 Pod,并将其
[priorityClassName](<https://kubernetes.io/zh/docs/concept