kubernetes资源限制
资源需求与限制
在kubernetes上,可由容器或pod请求与消费的资源主要是指CPU和内存,它可统称为计算资源,另外一种资源是事关可用存储卷空间的存储资源。相较而言,CPU属于可压缩资源,即资源额度可按需弹性变化,而内存则是不可压缩型资源,对其执行压缩操作可能会导致某种程度的问题,例如进程崩溃等。目前资源隔离仍属于容器级别,CPU和内存资源的配置主要在pod对象中的容器上进行,并且每个资源存在需求和限制两种类型。为了表述方便,人们通常把资源配置称为pod资源的需求和限制,只不过它是指pod内所有容器上的某种类型资源的请求与限制总和。
- 资源需求:定义需要系统预留给该容器使用的资源最小可用值,容器运行时可能用不到这些额度的资源,但用到时必须确保有相应数量的资源可用。
- 资源限制:定义该容器可以申请使用的资源最大可用值,超出该额度的资源使用请求将被拒绝;显然,该限制需要大于等于requests的值,但系统在某项资源紧张时,会从容器回收超出requests值的那部分。
在kubernetes系统上,1个单位的CPU相当于虚拟机上的1颗虚拟CPU(vCPU)或物理机上的一个超线程,它支持分数计量方式,一个核心(1 core)相当于1000个微核心(millicores,简称为m),因此500m相当于是0.5个核心,即1/2个核心。内存的计量方式与日常使用方式相同,默认单位是字节,也可以使用E、P、T、G、M和K为单位后缀,或Ei、Pi、Ti、Gi、Mi和Ki形式单位后缀。
没有指定内存限制
如果你没有为一个容器指定内存限制,则自动遵循以下情况之一:
容器可无限制地使用内存。容器可以使用其所在节点所有的可用内存, 进而可能导致该节点调用 OOM Killer。 此外,如果发生 OOM Kill,没有资源限制的容器将被杀掉的可行性更大。
运行的容器所在命名空间有默认的内存限制,那么该容器会被自动分配默认限制。 可用使用 LimitRange 来指定默认的内存限制。
容器资源需求
apiVersion: v1
kind: Pod
metadata:
name: ...
spec:
containers:
- name: ...
image: ...
resources:
requests:
memory: "128Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "400m"
上面配置清单中,容器请求使用的CPU资源大小为200m,这意味着一个CPU核心足以确保其以期望的最快方式运行。另外,配置清单中期望使用的内存大小为128MiB,不过其运行时未必真的会用到这么多。考虑到内存为非压缩型资源,当超出时存在因OOM被杀死的可能性,于是请求值是其理想中使用的内存空间上限。
对于压缩型的资源CPU来说,若为定义容器的资源请求用量,以确保其最小可用资源量,该pod占用的CPU资源可能会被其它pod对象压缩至极低的水平,甚至到该pod对象无法被调度运行的境地。而对于非压缩型内存资源来说,资源紧缺情形下可能导致相关的容器进程被杀死。因此kubernetes系统上运行关键型业务相关的pod时,必须使用requests属性为容器明确定义资源需求。当然,我们也可以为pod对象定义较高的优先级来改变这种局面。
集群中的每个节点都拥有定量的CPU和内存资源,调度器将pod绑定值节点时,仅计算资源余量可满足该pod对象需求量的节点才能作为该pod运行的可用目标节点。也就是说,kubernetes的调度器会根据容器的requests属性定义的资源需求量来判定那些节点可接收并运行相关的pod对象,而对于一个节点的资源来说,每运行一个pod对象,该pod对象上所有容器requests属性定义的请求量都要给与预留,直到节点被绑定的所有pod对象瓜分完毕为止。
容器资源限制
容器为保证其可用的最少资源量,并不限制可用资源上限,因此对应于程序自身Bug等多种原因导致的系统资源被长时间占用无计可施,这就需要通过资源限制功能为容器定义资源的最大可用量。一旦定义资源限制,分配资源时,可压缩型资源CPU的控制阀可自由调节,容器进程也就无法获得超出其CPU配额的可用值。但是,若进程申请使用超出limits属性定义的内存资源时,该进程将可能被杀死。不过,该进程随后仍可能会被其控制器进程重启,例如,当pod对象的重启策略为Always或OnFailure时,或者容器进程存在其监视和管理功能的父进程等。
apiVersion: v1
kind: Pod
metadata:
name: ...
labels:
app: ...
spec:
containers:
- name: ...
image: ...
imagePullPolicy: IfNotPresent
resources:
requests:
memory: "64Mi"
cpu: "1"
limits:
memory: "64Mi"
cpu: "1"
与资源需求不同的是,资源限制并不影响pod对象的调度结果,即一个节点上的所有pod对象的资源限制数量之和可以大于节点拥有的资源量,即支持资源的过载使用。不过这么一来,一旦资源耗尽,几乎必然地会有容器因OOMKilled而终止。
另外值的说明的是,kubernetes仅会确保pod对象获得它们请求的CPU时间额度,它们能否取得额外的CPU时间,则取决于其它正在运行作业的CPU资源占用情况。例如对于总数为1000m的CPU资源来说,容器A请求使用300m,容器B请求使用200m,在不超它们各自最大限额的前提下,则余下的500m在双方都需要时会以300:200的方式进行配置。
容器可见资源
在容器中运行top等命令观察资源可用量信息时,容器受资源受限于requests和limits属性中的定义,但容器中可见资源量依然是节点级别的可用量。
~# kubectl exec nginx -- cat /proc/meminfo |grep ^MemTotal
MemTotal: 7955548 kB
~# kubectl exec nginx -- cat /proc/cpuinfo |grep -c ^processor
4
命令结果显示其可用内存资源总量为7955548 kB,CPU核心数为4个,这是节点级的资源数量,而非由容器的limits属性所定义的资源数量。其实这不仅让查看命令的显示结果看起来有些奇怪,也会给有些容器应用的配置带来不小的负面影响。
较为典型的是在pod中运行java应用程序时,若未使用-Xmx选项指定JVM的堆内存可用总量,则会默认设置为主机内存总量的一个空间比例,这会导致容器中的应用程序申请内存资源时很快达到上限,而转为OOMKilled状态。另外,即时使用了-Xmx选项设置其堆内存上限,但该设置对非堆内存的可用空间不产生任何限制作用,仍然存在达到容器内存资源上限的可能性。
另外一个典型代表是在pod中运行Nignx应用时,其配置参数worker_processes的值设置为auto,则会创建与可见CPU核心数量等同的worker进程数,若容器的CPU可用资源量远小于节点所需资源量时,这种设置在较大的访问负荷下会产生严重的资源竞争,并且会带来更多的内存资源消耗。一种较为妥当的解决方案是使用Downward API将limits定义的资源量暴露给容器。
Pod服务质量类别
kubernetes允许节点的Pod对象过载使用资源,这意味着节点无法同时满足绑定其上的Pod对象以资源满载的方式运行。因而在内存资源紧缺的情况下,应该以何种次序终止那些pod对象就变成了问题。事实上,kubernetes无法自行对此做出决策,它需要借助于pod对象的服务质量和优先级等完成判定。根据pod对象的requests和limits属性,kubernetes把pod对象的归类到BestEffort、Burstable和Guaranteed这3个服务质量类别(Quality of Service,QoS)类别下。
- Guaranteed:pod对象为其每个容器都设置了CPU资源需求和资源限制,且二者具有相同值;同时为每个容器都设置了内存资源需求和内存限制,且二者具有相同值。这类pod对象具有最高级别服务质量。
- Burstable:至少有一个容器设置了CPU或内存资源的requests属性,但不满足Guaranteed类别的设定需求,这类pod对象具有中等级别服务质量。
- BestEffort:不为任何一个容器设置requests和limits属性,这类pod对象可获得的服务质量为最低级别。
一旦内存资源紧缺,BestEffort类别的容器将首当其中地被终止,因为系统不为其提供任何级别的资源保证,但换来的好处是,它们能够做到仅可能多地占用资源。若此时系统上不存在任何BestEffort类别的容器,则接下来将轮到Burstable类别的pod被终止。Guaranteed类别的容器拥有最高优先级,它们不会被杀死,除非其内存资源需求超限,或者OOM时没有其它更低优先级的pod对象存在。
每个运行状态的容器都有其OOM评分,评分越高越优先被杀死。OOM评分主要根据两个维度进行计算:由服务质量类别继承而来的默认分值,以及容器的可用内存资源比例,而同等类别的pod对象的默认值相同。Guaranteed类别pod资源的Adjust分值为-998,而BestEffort类别的默认分值为1000,Burstable类别的pod资源的Adjust分值经由相应的算法计算得出。因此,同等级别优先级的pod资源在OOM时,与自身的requests属性相比,其内存占用比例最大的pod对象将先被杀死。
OOM是内存耗尽时的处理机制,与可压缩型资源CPU无关,因此CPU资源的需求无法得到保证时,pod对象仅仅是暂时获取不到相应的资源来运行而已。
限制范围
默认情况下, Kubernetes 集群上的容器运行使用的计算资源没有限制。 使用 Kubernetes 资源配额, 管理员(也称为 集群操作者)可以在一个指定的命名空间内限制集群资源的使用与创建。 在命名空间中,一个 Pod 最多能够使用命名空间的资源配额所定义的 CPU 和内存用量。 作为集群操作者或命名空间级的管理员,你可能也会担心如何确保一个 Pod 不会垄断命名空间内所有可用的资源。
LimitRange 是限制命名空间内可为每个适用的对象类别 (例如 Pod 或 PersistentVolumeClaim) 指定的资源分配量(限制和请求)的策略对象。
一个 LimitRange(限制范围) 对象提供的限制能够做到:
在一个命名空间中实施对每个 Pod 或 Container 最小和最大的资源使用量的限制。
在一个命名空间中实施对每个 PersistentVolumeClaim 能申请的最小和最大的存储空间大小的限制。
在一个命名空间中实施对一种资源的申请值和限制值的比值的控制。
设置一个命名空间中对计算资源的默认申请/限制值,并且自动的在运行时注入到多个 Container 中。
当某命名空间中有一个 LimitRange 对象时,将在该命名空间中实施 LimitRange 限制。
LimitRange 的名称必须是合法的 DNS 子域名。
资源限制和请求的约束
管理员在一个命名空间内创建一个 LimitRange 对象。
用户在此命名空间内创建(或尝试创建) Pod 和 PersistentVolumeClaim 等对象。
首先,LimitRanger 准入控制器对所有没有设置计算资源需求的所有 Pod(及其容器)设置默认请求值与限制值。
其次,LimitRange 跟踪其使用量以保证没有超出命名空间中存在的任意 LimitRange 所定义的最小、最大资源使用量以及使用量比值。
若尝试创建或更新的对象(Pod 和 PersistentVolumeClaim)违反了 LimitRange 的约束, 向 API 服务器的请求会失败,并返回 HTTP 状态码 403 Forbidden 以及描述哪一项约束被违反的消息。 # kubectl get deployments deployment-name -n ns -o json
若你在命名空间中添加 LimitRange 启用了对 cpu 和 memory 等计算相关资源的限制, 你必须指定这些值的请求使用量与限制使用量。否则,系统将会拒绝创建 Pod。
LimitRange 的验证仅在 Pod 准入阶段进行,不对正在运行的 Pod 进行验证。 如果你添加或修改 LimitRange,命名空间中已存在的 Pod 将继续不变。
如果命名空间中存在两个或更多 LimitRange 对象,应用哪个默认值是不确定的。
limit-range.yaml
apiversion: v1
kind: LimitRange
metadata:
name: limitrange-demoapp
namespace: demoapp
spec:
limits:
- type: Container #限制的资源类型
max:
cpu: "2" #限制单个容器的最大CPU
memory: "2Gi" #限制单个容器的最大内存
min:
cpu: "500m" #限制单个容器的最小CPU
memory: "512Mi" #限制单个容器的最小内存
default:
cpu: "500m" #默认单个容器的CPU限制
memory: "512Mi" #默认单个容器的内存限制
defaultRequest:
cpu: "500m" #默认单个容器的CPU创建请求
memory: "512Mi" #默认单个容器的内存创建请求
maxLimitRequestRatio:
cpu: 2 #限制CPU Limit/request比值最大为2
memory: 2 #限制内存 Limit/request比值最大为1.5
- type: Pod
max:
cpu: "4" #限制单个Pod的最大CPU
memory: "4Gi" #限制单个Pod最大内存
- type: PersistentVolumeClaim
max:
storage: 50Gi #限制 PVC最大的 requests.storage
min:
storage: 30Gi #限制 PVC最小的 requests.storage
资源配额
当多个用户或团队共享具有固定节点数目的集群时,人们会担心有人使用超过其基于公平原则所分配到的资源量。
资源配额是帮助管理员解决这一问题的工具。
资源配额,通过 ResourceQuota 对象来定义,对每个命名空间的资源消耗总量提供限制。 它可以限制命名空间中某种类型的对象的总数目上限,也可以限制命名空间中的 Pod 可以使用的计算资源的总上限。
资源配额的工作方式如下:
不同的团队可以在不同的命名空间下工作。这可以通过 RBAC 强制执行。
集群管理员可以为每个命名空间创建一个或多个 ResourceQuota 对象。
当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会跟踪集群的资源使用情况, 以确保使用的资源用量不超过 ResourceQuota 中定义的硬性资源限额。
如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN), 并在消息中给出有可能违反的约束。
如果命名空间下的计算资源 (如 cpu 和 memory)的配额被启用, 则用户必须为这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。 提示: 可使用 LimitRanger 准入控制器来为没有设置计算资源需求的 Pod 设置默认值。
说明:
对于 cpu 和 memory 资源:ResourceQuota 强制该命名空间中的每个(新)Pod 为该资源设置限制。 如果你在命名空间中为 cpu 和 memory 实施资源配额, 你或其他客户端必须为你提交的每个新 Pod 指定该资源的 requests 或 limits。 否则,控制平面可能会拒绝接纳该 Pod。
对于其他资源:ResourceQuota 可以工作,并且会忽略命名空间中的 Pod,而无需为该资源设置限制或请求。 这意味着,如果资源配额限制了此命名空间的临时存储,则可以创建没有限制/请求临时存储的新 Pod。 你可以使用限制范围自动设置对这些资源的默认请求。
启用资源配额
资源配额的支持在很多 Kubernetes 版本中是默认启用的。 当 API 服务器 的命令行标志 --enable-admission-plugins= 中包含 ResourceQuota 时, 资源配额会被启用。
当命名空间中存在一个 ResourceQuota 对象时,对于该命名空间而言,资源配额就是开启的。
计算资源配额
用户可以对给定命名空间下的可被请求的 计算资源 总量进行限制。
配额机制所支持的资源类型:
资源名称 | 描述 |
---|---|
limits.cpu |
所有非终止状态的 Pod,其 CPU 限额总量不能超过该值。 |
limits.memory |
所有非终止状态的 Pod,其内存限额总量不能超过该值。 |
requests.cpu |
所有非终止状态的 Pod,其 CPU 需求总量不能超过该值。 |
requests.memory |
所有非终止状态的 Pod,其内存需求总量不能超过该值。 |
hugepages-<size> |
对于所有非终止状态的 Pod,针对指定尺寸的巨页请求总数不能超过此值。 |
cpu |
与 requests.cpu 相同。 |
memory |
与 requests.memory 相同。 |
扩展资源的资源配额
除上述资源外,在 Kubernetes 1.10 版本中,还添加了对 扩展资源 的支持。
由于扩展资源不可超量分配,因此没有必要在配额中为同一扩展资源同时指定 requests 和 limits。 对于扩展资源而言,目前仅允许使用前缀为 requests. 的配额项。
以 GPU 拓展资源为例,如果资源名称为 nvidia.com/gpu,并且要将命名空间中请求的 GPU 资源总数限制为 4,则可以如下定义配额:
requests.nvidia.com/gpu: 4
存储资源配额
资源名称 | 描述 |
---|---|
requests.storage |
所有 PVC,存储资源的需求总量不能超过该值。 |
persistentvolumeclaims |
在该命名空间中所允许的 PVC 总量。 |
<storage-class-name>.storageclass.storage.k8s.io/requests.storage |
在所有与 <storage-class-name> 相关的持久卷申领中,存储请求的总和不能超过该值。 |
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims |
在与 storage-class-name 相关的所有持久卷申领中,命名空间中可以存在的PVC总数。 |
requests.ephemeral-storage |
在命名空间的所有 Pod 中,本地临时存储请求的总和不能超过此值。 |
limits.ephemeral-storage |
在命名空间的所有 Pod 中,本地临时存储限制值的总和不能超过此值。 |
ephemeral-storage |
与 requests.ephemeral-storage 相同。 |
说明:
如果所使用的是 CRI 容器运行时,容器日志会被计入临时存储配额。 这可能会导致存储配额耗尽的 Pods 被意外地驱逐出节点。
示例
例如,如果一个操作人员针对 gold 存储类型与 bronze 存储类型设置配额, 操作人员可以定义如下配额:
gold.storageclass.storage.k8s.io/requests.storage: 500Gi
bronze.storageclass.storage.k8s.io/requests.storage: 100Gi
配额作用域
每个配额都有一组相关的 scope(作用域),配额只会对作用域内的资源生效。 配额机制仅统计所列举的作用域的交集中的资源用量。
当一个作用域被添加到配额中后,它会对作用域相关的资源数量作限制。 如配额中指定了允许(作用域)集合之外的资源,会导致验证错误。
作用域 | 描述 |
---|---|
Terminating |
匹配所有 spec.activeDeadlineSeconds 不小于 0 的 Pod。 |
NotTerminating |
匹配所有 spec.activeDeadlineSeconds 是 nil 的 Pod。 |
BestEffort |
匹配所有 Qos 是 BestEffort 的 Pod。 |
NotBestEffort |
匹配所有 Qos 不是 BestEffort 的 Pod。 |
PriorityClass |
匹配所有引用了所指定的优先级类的 Pods。 |
CrossNamespacePodAffinity |
匹配那些设置了跨名字空间(反)亲和性条件 的 Pod。 |
BestEffort 作用域限制配额跟踪以下资源:
pods
Terminating、NotTerminating、NotBestEffort 和 PriorityClass 这些作用域限制配额跟踪以下资源:
pods
cpu
memory
requests.cpu
requests.memory
limits.cpu
limits.memory
需要注意的是,你不可以在同一个配额对象中同时设置 Terminating 和 NotTerminating 作用域,你也不可以在同一个配额中同时设置 BestEffort 和 NotBestEffort 作用域。
scopeSelector 支持在 operator 字段中使用以下值:
In
NotIn
Exists
DoesNotExist
定义 scopeSelector 时,如果使用以下值之一作为 scopeName 的值,则对应的 operator 只能是 Exists。
Terminating
NotTerminating
BestEffort
NotBestEffort
如果 operator 是 In 或 NotIn 之一,则 values 字段必须至少包含一个值。 例如:
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- middle
如果 operator 为 Exists 或 DoesNotExist,则不可以设置 values 字段。
基于优先级类(PriorityClass)来设置资源配额
Pod 可以创建为特定的优先级。 通过使用配额规约中的 scopeSelector 字段,用户可以根据 Pod 的优先级控制其系统资源消耗。
仅当配额规范中的 scopeSelector 字段选择到某 Pod 时,配额机制才会匹配和计量 Pod 的资源消耗。
如果配额对象通过 scopeSelector 字段设置其作用域为优先级类, 则配额对象只能跟踪以下资源:
pods
cpu
memory
ephemeral-storage
limits.cpu
limits.memory
limits.ephemeral-storage
requests.cpu
requests.memory
requests.ephemeral-storage
quota.yml
本示例创建一个配额对象,并将其与具有特定优先级的 Pod 进行匹配。 该示例的工作方式如下:
集群中的 Pod 可取三个优先级类之一,即 "low"、"medium"、"high"。
为每个优先级创建一个配额对象。
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium
spec:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator: In
scopeName: PriorityClass
values: ["low"]
high-priority-pod.yml
创建优先级为 "high" 的 Pod。
apiVersion: v1
kind: Pod
metadata:
name: high-priority
spec:
containers:
- name: high-priority
image: ubuntu
command: ["/bin/sh"]
args: ["-c", "while true; do echo hello; sleep 10;done"]
resources:
requests:
memory: "10Gi"
cpu: "500m"
limits:
memory: "10Gi"
cpu: "500m"
priorityClassName: high
跨名称空间的 Pod 亲和性配额
集群运维人员可以使用 CrossNamespacePodAffinity 配额作用域来限制哪个名字空间中可以存在包含跨名字空间亲和性规则的 Pod。 更为具体一点,此作用域用来配置哪些 Pod 可以在其 Pod 亲和性规则中设置 namespaces 或 namespaceSelector 字段。
禁止用户使用跨名字空间的亲和性规则可能是一种被需要的能力, 因为带有反亲和性约束的 Pod 可能会阻止所有其他名字空间的 Pod 被调度到某失效域中。
使用此作用域操作符可以避免某些名字空间(例如下面例子中的 foo-ns)运行特别的 Pod, 这类 Pod 使用跨名字空间的 Pod 亲和性约束,在该名字空间中创建了作用域为 CrossNamespaceAffinity 的、硬性约束为 0 的资源配额对象。
apiVersion: v1
kind: ResourceQuota
metadata:
name: disable-cross-namespace-affinity
namespace: foo-ns
spec:
hard:
pods: "0"
scopeSelector:
matchExpressions:
- scopeName: CrossNamespaceAffinity
如果集群运维人员希望默认禁止使用 namespaces 和 namespaceSelector, 而仅仅允许在特定名字空间中这样做,他们可以将 CrossNamespaceAffinity 作为一个被约束的资源。方法是为 kube-apiserver 设置标志 --admission-control-config-file
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: "ResourceQuota"
configuration:
apiVersion: apiserver.config.k8s.io/v1
kind: ResourceQuotaConfiguration
limitedResources:
- resource: pods
matchScopes:
- scopeName: CrossNamespaceAffinity
基于上面的配置,只有名字空间中包含作用域为 CrossNamespaceAffinity 且硬性约束大于或等于使用 namespaces 和 namespaceSelector 字段的 Pod 个数时,才可以在该名字空间中继续创建在其 Pod 亲和性规则中设置 namespaces 或 namespaceSelector 的新 Pod。
请求与限制的比较
分配计算资源时,每个容器可以为 CPU 或内存指定请求和约束。 配额可以针对二者之一进行设置。
如果配额中指定了 requests.cpu 或 requests.memory 的值,则它要求每个容器都显式给出对这些资源的请求。 同理,如果配额中指定了 limits.cpu 或 limits.memory 的值,那么它要求每个容器都显式设定对应资源的限制。
设置配额
compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-resources
namespace: myspace
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
requests.nvidia.com/gpu: 4
object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: object-counts
namespace: myspace
spec:
hard:
configmaps: "10"
persistentvolumeclaims: "4"
pods: "4"
replicationcontrollers: "20"
secrets: "10"
services: "10"
services.loadbalancers: "2"
查看配额
# kubectl get quota --namespace=myspace
NAME AGE
compute-resources 30s
object-counts 32s
# kubectl describe quota compute-resources --namespace=myspace
Name: compute-resources
Namespace: myspace
Resource Used Hard
-------- ---- ----
limits.cpu 0 2
limits.memory 0 2Gi
requests.cpu 0 1
requests.memory 0 1Gi
requests.nvidia.com/gpu 0 4
# kubectl describe quota object-counts --namespace=myspace
Name: object-counts
Namespace: myspace
Resource Used Hard
-------- ---- ----
configmaps 0 10
persistentvolumeclaims 0 4
pods 0 4
replicationcontrollers 0 20
secrets 1 10
services 0 10
services.loadbalancers 0 2
调整分配给容器的 CPU 和内存资源
调整容器资源限制说明
特性状态: Kubernetes v1.27 [alpha]
如何在不重启 Pod 或其容器的情况下调整分配给运行中 Pod 容器的 CPU 和内存资源。 Kubernetes 节点会基于 Pod 的 requests 为 Pod 分配资源, 并基于 Pod 的容器中指定的 limits 限制 Pod 的资源使用。
对于原地调整 Pod 资源而言:
针对 CPU 和内存资源的容器的 requests 和 limits 是可变更的。
Pod 状态中 containerStatuses 的 allocatedResources 字段反映了分配给 Pod 容器的资源。
Pod 状态中 containerStatuses 的 resources 字段反映了如同容器运行时所报告的、针对正运行的容器配置的实际资源 requests 和 limits。
Pod 状态中 resize 字段显示上次请求待处理的调整状态。此字段可以具有以下值:
Proposed:此值表示请求调整已被确认,并且请求已被验证和记录。
InProgress:此值表示节点已接受调整请求,并正在将其应用于 Pod 的容器。
Deferred:此值意味着在此时无法批准请求的调整,节点将继续重试。 当其他 Pod 退出并释放节点资源时,调整可能会被真正实施。
Infeasible:此值是一种信号,表示节点无法承接所请求的调整值。 如果所请求的调整超过节点可分配给 Pod 的最大资源,则可能会发生这种情况。
容器资源限制调整策略
调整策略允许更精细地控制 Pod 中的容器如何针对 CPU 和内存资源进行调整。 例如,容器的应用程序可以处理 CPU 资源的调整而不必重启, 但是调整内存可能需要应用程序重启,因此容器也必须重启。
为了实现这一点,容器规约允许用户指定 resizePolicy。 针对调整 CPU 和内存可以设置以下重启策略:
NotRequired:在运行时调整容器的资源。
RestartContainer:重启容器并在重启后应用新资源。
如果未指定 resizePolicy[*].restartPolicy,则默认为 NotRequired。
说明:
如果 Pod 的 restartPolicy 为 Never,则 Pod 中所有容器的调整重启策略必须被设置为 NotRequired。
示例
下面的示例显示了一个 Pod,其中 CPU 可以在不重启容器的情况下进行调整,但是内存调整需要重启容器。
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-5
namespace: qos-example
spec:
containers:
- name: qos-demo-ctr-5
image: nginx
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: RestartContainer
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
更新 Pod 的资源
现在对 Pod 的 Container 执行 patch 命令,将容器的 CPU 请求和限制均设置为 800m:
# kubectl -n qos-example patch pod qos-demo-5 --patch '{"spec":{"containers":[{"name":"qos-demo-ctr-5", "resources":{"requests":{"cpu":"800m"}, "limits":{"cpu":"800m"}}}]}}'
保存pod配置信息
# kubectl get pod qos-demo-5 --output=yaml --namespace=qos-example
资源配额示例
创建命名空间
# kubectl create namespace quota-mem-cpu-example
quota-mem-cpu.yaml
ResourceQuota 在命名空间中设置了如下要求:
在该命名空间中的每个 Pod 的所有容器都必须要有内存请求和限制,以及 CPU 请求和限制。
在该命名空间中所有 Pod 的内存请求总和不能超过 1 GiB。
在该命名空间中所有 Pod 的内存限制总和不能超过 2 GiB。
在该命名空间中所有 Pod 的 CPU 请求总和不能超过 1 cpu。
在该命名空间中所有 Pod 的 CPU 限制总和不能超过 2 cpu。
apiVersion: v1
kind: ResourceQuota
metadata:
name: mem-cpu-demo
namespace: quota-mem-cpu-example
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
创建 ResourceQuota
# kubectl apply -f quota-mem-cpu.yaml
查看 ResourceQuota 详情
# kubectl get resourcequota mem-cpu-demo --namespace=quota-mem-cpu-example --output=yaml
quota-mem-cpu-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: quota-mem-cpu-demo
spec:
containers:
- name: quota-mem-cpu-demo-ctr
image: nginx
resources:
limits:
memory: "800Mi"
cpu: "800m"
requests:
memory: "600Mi"
cpu: "400m"
创建 Pod
# kubectl apply -f quota-mem-cpu-pod.yaml --namespace=quota-mem-cpu-example
查看 ResourceQuota 使用情况
# kubectl get resourcequota mem-cpu-demo --namespace=quota-mem-cpu-example --output=yaml
status:
hard:
limits.cpu: "2"
limits.memory: 2Gi
requests.cpu: "1"
requests.memory: 1Gi
used:
limits.cpu: 800m
limits.memory: 800Mi
requests.cpu: 400m
requests.memory: 600Mi
输出结果显示了配额以及有多少配额已经被使用。你可以看到 Pod 的内存和 CPU 请求值及限制值没有超过配额。
为容器和 Pod 分配内存资源示例
创建一个拥有一个容器的 Pod。 容器将会请求 100 MiB 内存,并且内存会被限制在 200 MiB 以内。
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
requests:
memory: "100Mi"
limits:
memory: "200Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
为容器和 Pods 分配 CPU 资源示例
创建一个具有一个容器的 Pod。容器将会请求 0.5 个 CPU,而且最多限制使用 1 个 CPU。
apiVersion: v1
kind: Pod
metadata:
name: cpu-demo
namespace: cpu-example
spec:
containers:
- name: cpu-demo-ctr
image: vish/stress
resources:
limits:
cpu: "1"
requests:
cpu: "0.5"
args:
- -cpus
- "2"
配置文件的 args 部分提供了容器启动时的参数。 -cpus "2" 参数告诉容器尝试使用 2 个 CPU。
参考文档
https://kubernetes.io/zh-cn/docs/concepts/policy/limit-range/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)