此文档中的信息可能已过时

此文档的更新日期比原文晚,因此其中的信息可能已过时。如果能阅读英文,请查看英文版本以获取最新信息: Resource Quotas

资源配额

当多个用户或团队共享具有固定节点数目的集群时,人们会担心有人使用超过其基于公平原则所分配到的资源量。

资源配额是帮助管理员解决这一问题的工具。

资源配额,由 ResourceQuota 对象定义, 提供了限制每个命名空间的资源总消耗的约束。 资源配额还可以限制在命名空间中可以创建的对象数量(按 API 类型计算), 以及该命名空间中存在的 API 对象可能消耗的基础设施资源的总量。

注意:

不同的资源争用,或者资源配额的更改不会影响已经创建的资源。

Kubernetes ResourceQuota 的工作原理

ResourceQuota 的工作方式如下:

  • 不同团队在不同的命名空间中工作。 这种分离可以通过 RBAC 或任何其他鉴权机制来强制执行。

  • 集群管理员为每个命名空间创建至少一个 ResourceQuota。

    • 为了确保强制执行不被解除,集群管理员还应限制对删除或更新此 ResourceQuota 的访问; 例如,通过定义一个验证准入策略来实现这点。
  • 当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会跟踪集群的资源使用情况, 以确保使用的资源用量不超过 ResourceQuota 中定义的硬性资源限额。

    你可以对 ResourceQuota 应用一个范围,以限制其适用的地方。

  • 如果创建或更新资源违反了配额约束,控制平面将使用 HTTP 状态码 403 Forbidden 拒绝该请求。错误信息包括解释将要违反的约束的说明。

  • 如果在命名空间中为诸如 cpumemory资源启用了配额, 用户在定义 Pod 时必须指定这些值的请求或限制;否则,配额系统可能会拒绝 Pod 创建。

    资源配额演练展示了一个如何避免此问题的示例。

说明:

你通常不会直接创建 Pod;例如,你更常创建一个工作负载管理对象, 如 Deployment。 如果你创建了一个尝试使用超出可用资源的 Deployment(或其他工作负载管理对象), 其创建会成功,但 Deployment 可能无法使其管理的所有 Pod 都运行起来。 在这种情况下,你可以使用 kubectl describe 等命令检查 Deployment 的状态, 以查看发生了什么。

  • 对于 cpumemory 资源:ResourceQuota 强制该命名空间中的每个(新)Pod 为该资源设置限制。 如果你在命名空间中为 cpumemory 实施资源配额, 你或其他客户端必须为你提交的每个新 Pod 指定该资源的 requestslimits。 否则,控制平面可能会拒绝接纳该 Pod
  • 对于其他资源:ResourceQuota 可以工作,并且会忽略命名空间中的 Pod,而无需为该资源设置限制或请求。 这意味着,如果资源配额限制了此命名空间的临时存储,则可以创建没有限制/请求临时存储的新 Pod。

你可以使用 LimitRange 自动设置对这些资源的默认请求。

ResourceQuota 对象的名称必须是合法的 DNS 子域名

下面是使用命名空间和配额构建策略的示例:

  • 在具有 32 GiB 内存和 16 核 CPU 资源的集群中,允许 A 团队使用 20 GiB 内存 和 10 核的 CPU 资源, 允许 B 团队使用 10 GiB 内存和 4 核的 CPU 资源,并且预留 2 GiB 内存和 2 核的 CPU 资源供将来分配。
  • 限制 "testing" 命名空间使用 1 核 CPU 资源和 1GiB 内存。允许 "production" 命名空间使用任意数量。

在集群容量小于各命名空间配额总和的情况下,可能存在资源竞争。资源竞争时,Kubernetes 系统会遵循先到先得的原则。

启用资源配额

ResourceQuota 的支持在很多 Kubernetes 版本中是默认启用的。 当 API 服务器 的命令行标志 --enable-admission-plugins= 中包含 ResourceQuota 时, 资源配额会被启用。

当命名空间中存在一个 ResourceQuota 对象时,对于该命名空间而言,资源配额就是开启的。

资源配额的类型

ResourceQuota 机制允许你执行不同类别的限制。本节说明你可以执行的限制类型。

基础设施资源的配额

用户可以对给定命名空间下的可被请求的计算资源总量进行限制。

配额机制所支持的资源类型:

资源名称描述
limits.cpu所有非终止状态的 Pod,其 CPU 限额总量不能超过该值。
limits.memory所有非终止状态的 Pod,其内存限额总量不能超过该值。
requests.cpu所有非终止状态的 Pod,其 CPU 需求总量不能超过该值。
requests.memory所有非终止状态的 Pod,其内存需求总量不能超过该值。
hugepages-<size>对于所有非终止状态的 Pod,针对指定尺寸的巨页请求总数不能超过此值。
cpurequests.cpu 相同。
memoryrequests.memory 相同。

扩展资源的配额

除上述资源外,在 Kubernetes 1.10 版本中, 还添加了对扩展资源的支持。

由于扩展资源不可超量分配,因此没有必要在配额中为同一扩展资源同时指定 requestslimits。 对于扩展资源而言,仅允许使用前缀为 requests. 的配额项。

以 GPU 拓展资源为例,如果资源名称为 nvidia.com/gpu,并且要将命名空间中请求的 GPU 资源总数限制为 4,则可以如下定义配额:

  • requests.nvidia.com/gpu: 4

有关更多详细信息,请参阅查看和设置配额

存储的配额

你可以对给定命名空间下可以请求的存储卷总量进行限制。

此外,你还可以基于关联的 StorageClass 来限制存储资源的消耗。

资源名称描述
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 相关的所有持久卷申领中,命名空间中可以存在的持久卷申领总数。

例如,如果你想要将 gold StorageClass 与 bronze StorageClass 分开进行存储配额配置, 则可以按如下方式定义配额:

  • gold.storageclass.storage.k8s.io/requests.storage: 500Gi
  • bronze.storageclass.storage.k8s.io/requests.storage: 100Gi

本地临时存储的配额

特性状态: Kubernetes v1.8 [alpha]
资源名称描述
requests.ephemeral-storage在命名空间的所有 Pod 中,本地临时存储请求的总和不能超过此值。
limits.ephemeral-storage在命名空间的所有 Pod 中,本地临时存储限制值的总和不能超过此值。
ephemeral-storagerequests.ephemeral-storage 相同。

说明:

如果所使用的是 CRI 容器运行时,容器日志会被计入临时存储配额, 这可能会导致存储配额耗尽的 Pod 被意外地驱逐出节点。

参考日志架构了解详细信息。

对象数量的配额

你可以使用以下语法为 Kubernetes API 中一种特定资源类型的总数设置配额:

  • count/<resource>.<group>:用于非核心 API 组的资源
  • count/<resource>:用于核心 API 组的资源

例如,PodTemplate API 属于核心 API 组,因此如果你想限制某个命名空间中的 PodTemplate 对象的数量,你可以使用 count/podtemplates

这类配额非常有助于防止控制平面存储资源耗尽。 例如,由于某台服务器上的 Secret 较大,你可能希望对其进行限制。 集群中 Secret 过多实际上可能导致服务器和控制器无法启动。 你也可以为 Job 设置配额,以防止出现配置不当的 CronJob。 某些 CronJob 如果在一个命名空间中创建了过多的 Job,可能会引发 DoS 攻击。

如果你以这种方式定义配额,它将应用于属于 API 服务器一部分的 Kubernetes API,以及 CustomResourceDefinition 支持的任何自定义资源。例如,要在 example.com API 组中创建 widgets 定制资源的配额,可以使用 count/widgets.example.com。 如果你使用聚合 API 添加未定义为 CustomResourceDefinitions 的其他自定义 API,则核心 Kubernetes 控制平面不会对聚合 API 实施配额管理。 如果合适,扩展 API 服务器需要为自定义 API 提供配额管理。

通用语法

以下是一些常见对象类别的示例,建议你为这些对象设置数量配额。每一项后面列出了相应的配置字符串:

  • count/pods
  • count/persistentvolumeclaims
  • count/services
  • count/secrets
  • count/configmaps
  • count/deployments.apps
  • count/replicasets.apps
  • count/statefulsets.apps
  • count/jobs.batch
  • count/cronjobs.batch
特殊语法

还有另一种语法只能设置相同类型的配额,只对某些 API 类别起作用。 支持以下类型:

资源名称描述
configmaps在该命名空间中允许存在的 ConfigMap 总数上限。
persistentvolumeclaims在该命名空间中允许存在的 PVC 的总数上限。
pods在该命名空间中允许存在的非终止状态的 Pod 总数上限。Pod 终止状态等价于 Pod 的 .status.phase in (Failed, Succeeded) 为真。
replicationcontrollers在该命名空间中允许存在的 ReplicationController 总数上限。
resourcequotas在该命名空间中允许存在的 ResourceQuota 总数上限。
services在该命名空间中允许存在的 Service 总数上限。
services.loadbalancers在该命名空间中允许存在的 LoadBalancer 类型的 Service 总数上限。
services.nodeports在该命名空间中允许存在的 NodePort 或 LoadBalancer 类型的 Service 的 NodePort 总数上限。
secrets在该命名空间中允许存在的 Secret 总数上限。

例如,pods 配额统计某个命名空间中所创建的、非终止状态的 pods 个数并确保其不超过某上限值。 用户可能希望在某命名空间中设置 pods 配额,以避免有用户创建很多小的 Pod, 从而耗尽集群所能提供的 Pod IP 地址。

你可以在查看和设置配额一节查看更多示例。

配额作用域

每个配额都有一组相关的 scope(作用域),配额只会对作用域内的资源生效。 配额机制仅统计所列举的作用域的交集中的资源用量。

当一个作用域被添加到配额中后,它会对作用域相关的资源数量作限制。 如配额中指定了允许(作用域)集合之外的资源,会导致验证错误。

作用域描述
Terminating匹配所有 spec.activeDeadlineSeconds 不小于 0 的 Pod。
NotTerminating匹配所有 spec.activeDeadlineSeconds 是 nil 的 Pod。
BestEffort匹配所有 Qos 是 BestEffort 的 Pod。
NotBestEffort匹配所有 Qos 不是 BestEffort 的 Pod。
PriorityClass匹配所有引用了所指定的优先级类的 Pod。
CrossNamespacePodAffinity匹配那些设置了跨名字空间(反)亲和性条件的 Pod。
VolumeAttributesClass匹配引用了指定卷属性类的 PersistentVolumeClaim。

BestEffort 作用域限制配额跟踪以下资源:

  • pods

TerminatingNotTerminatingNotBestEffortPriorityClass 这些作用域限制配额跟踪以下资源:

  • pods
  • cpu
  • memory
  • requests.cpu
  • requests.memory
  • limits.cpu
  • limits.memory

需要注意的是,你不可以在同一个配额对象中同时设置 TerminatingNotTerminating 作用域,你也不可以在同一个配额中同时设置 BestEffortNotBestEffort 作用域。

scopeSelector 支持在 operator 字段中使用以下值:

  • In
  • NotIn
  • Exists
  • DoesNotExist

定义 scopeSelector 时,如果使用以下值之一作为 scopeName 的值,则对应的 operator 只能是 Exists

  • Terminating
  • NotTerminating
  • BestEffort
  • NotBestEffort

如果 operatorInNotIn 之一,则 values 字段必须至少包含一个值。 例如:

  scopeSelector:
    matchExpressions:
      - scopeName: PriorityClass
        operator: In
        values:
          - middle

如果 operatorExistsDoesNotExist,则可以设置 values 字段。

基于优先级类(PriorityClass)来设置资源配额

特性状态: Kubernetes v1.17 [stable]

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

本示例创建一个配额对象,并将其与具有特定优先级的 Pod 进行匹配,其工作方式如下:

  • 集群中的 Pod 可取三个优先级类之一,即 "low"、"medium"、"high"。
  • 为每个优先级创建一个配额对象。

将以下 YAML 保存到文件 quota.yaml 中。

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"]

使用 kubectl create 命令运行以下操作。

kubectl create -f ./quota.yaml
resourcequota/pods-high created
resourcequota/pods-medium created
resourcequota/pods-low created

使用 kubectl describe quota 操作验证配额的 Used 值为 0

kubectl describe quota
Name:       pods-high
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         0     1k
memory      0     200Gi
pods        0     10


Name:       pods-low
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         0     5
memory      0     10Gi
pods        0     10


Name:       pods-medium
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         0     10
memory      0     20Gi
pods        0     10

创建优先级为 "high" 的 Pod。 将以下 YAML 保存到文件 high-priority-pod.yaml 中。

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

使用 kubectl create 运行以下操作。

kubectl create -f ./high-priority-pod.yaml

确认 "high" 优先级配额 pods-high 的 "Used" 统计信息已更改,并且其他两个配额未更改。

kubectl describe quota
Name:       pods-high
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         500m  1k
memory      10Gi  200Gi
pods        1     10


Name:       pods-low
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         0     5
memory      0     10Gi
pods        0     10


Name:       pods-medium
Namespace:  default
Resource    Used  Hard
--------    ----  ----
cpu         0     10
memory      0     20Gi
pods        0     10

跨名字空间的 Pod 亲和性配额

特性状态: Kubernetes v1.24 [stable]

集群运维人员可以使用 CrossNamespacePodAffinity 配额作用域来限制哪个名字空间中可以存在包含跨名字空间亲和性规则的 Pod。 更为具体一点,此作用域用来配置哪些 Pod 可以在其 Pod 亲和性规则中设置 namespacesnamespaceSelector 字段。

禁止用户使用跨名字空间的亲和性规则可能是一种被需要的能力, 因为带有反亲和性约束的 Pod 可能会阻止所有其他名字空间的 Pod 被调度到某失效域中。

使用此作用域操作符可以避免某些名字空间(例如下面例子中的 foo-ns)运行特别的 Pod, 这类 Pod 使用跨名字空间的 Pod 亲和性约束,在该名字空间中创建了作用域为 CrossNamespacePodAffinity 的、硬性约束为 0 的资源配额对象。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: disable-cross-namespace-affinity
  namespace: foo-ns
spec:
  hard:
    pods: "0"
  scopeSelector:
    matchExpressions:
    - scopeName: CrossNamespacePodAffinity
      operator: Exists

如果集群运维人员希望默认禁止使用 namespacesnamespaceSelector, 而仅仅允许在特定命名空间中这样做,他们可以将 CrossNamespacePodAffinity 作为一个被约束的资源。方法是为 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: CrossNamespacePodAffinity
        operator: Exists

基于上面的配置,只有名字空间中包含作用域为 CrossNamespacePodAffinity 且硬性约束大于或等于使用 namespacesnamespaceSelector 字段的 Pod 个数时,才可以在该名字空间中继续创建在其 Pod 亲和性规则中设置 namespacesnamespaceSelector 的新 Pod。

按 VolumeAttributesClass 设置资源配额

特性状态: Kubernetes v1.34 [stable](enabled by default)

PersistentVolumeClaim(PVC)可以在创建时指定一个特定的卷属性类, 并且在创建后也可以进行修改。你可以通过在配额规约中使用 scopeSelector 字段,基于关联的卷属性类来控制 PVC 对存储资源的消耗。

PVC 通过以下字段引用关联的卷属性类:

  • spec.volumeAttributesClassName
  • status.currentVolumeAttributesClassName
  • status.modifyVolumeStatus.targetVolumeAttributesClassName

仅当配额规约中的 scopeSelector 选择 PVC 时,配额才会被匹配并计入消耗。

当使用 scopeSelector 字段为卷属性类限定配额范围时,配额对象只会跟踪以下资源:

  • persistentvolumeclaims
  • requests.storage

以下示例创建一个配额对象,并将其与具有特定卷属性类的 PVC 进行匹配。示例逻辑如下:

  • 集群中的 PVC 至少属于三个卷属性类之一:“gold”、“silver”、“copper”。
  • 为每个卷属性类分别创建一个配额对象。

将以下 YAML 保存为文件 quota-vac.yaml

apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: pvcs-gold
  spec:
    hard:
      requests.storage: "10Gi"
      persistentvolumeclaims: "10"
    scopeSelector:
      matchExpressions:
      - operator: In
        scopeName: VolumeAttributesClass
        values: ["gold"]
- apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: pvcs-silver
  spec:
    hard:
      requests.storage: "20Gi"
      persistentvolumeclaims: "10"
    scopeSelector:
      matchExpressions:
      - operator: In
        scopeName: VolumeAttributesClass
        values: ["silver"]
- apiVersion: v1
  kind: ResourceQuota
  metadata:
    name: pvcs-copper
  spec:
    hard:
      requests.storage: "30Gi"
      persistentvolumeclaims: "10"
    scopeSelector:
      matchExpressions:
      - operator: In
        scopeName: VolumeAttributesClass
        values: ["copper"]

使用 kubectl create 应用 YAML 文件:

kubectl create -f ./quota-vac.yaml
resourcequota/pvcs-gold created
resourcequota/pvcs-silver created
resourcequota/pvcs-copper created

使用 kubectl describe quota 验证 Used 配额为 0

kubectl describe quota
Name:                   pvcs-gold
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
requests.storage        0     10Gi


Name:                   pvcs-silver
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
requests.storage        0     20Gi


Name:                   pvcs-copper
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
requests.storage        0     30Gi

创建一个卷属性类为 "gold" 的 PVC。将以下 YAML 保存为文件 gold-vac-pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: gold-vac-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName:  # 将此项更改为你要使用的存储类的名称
  volumeAttributesClassName: gold

使用 kubectl create 应用此 YAML:

kubectl create -f ./gold-vac-pvc.yaml

验证 "gold" 卷属性类配额的 "Used" 统计,pvcs-gold 已发生了变化,而另外两个配额没有变化:

kubectl describe quota
Name:                   pvcs-gold
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  1     10
requests.storage        2Gi   10Gi


Name:                   pvcs-silver
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
requests.storage        0     20Gi


Name:                   pvcs-copper
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
requests.storage        0     30Gi

一旦 PVC 被绑定,就允许修改预期卷属性类。使用 kubectl patch 将其修改为 "silver":

kubectl patch pvc gold-vac-pvc --type='merge' -p '{"spec":{"volumeAttributesClassName":"silver"}}'

验证 “silver” 卷属性类配额的 “Used” 统计,pvcs-silver 已发生变化, pvcs-copper 没有变化,pvcs-gold 可能没有变化或已释放(具体取决于 PVC 的状态):

kubectl describe quota
Name:                   pvcs-gold
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  1     10
requests.storage        2Gi   10Gi


Name:                   pvcs-silver
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  1     10
requests.storage        2Gi   20Gi


Name:                   pvcs-copper
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
requests.storage        0     30Gi

使用 kubectl patch 将其修改为 "copper":

kubectl patch pvc gold-vac-pvc --type='merge' -p '{"spec":{"volumeAttributesClassName":"copper"}}'

验证 "copper" 卷属性类配额的 “Used” 统计,pvcs-copper 已经发生变化, pvcs-silverpvcs-gold 可能没有变化或已释放(取决于 PVC 的状态)。

kubectl describe quota
Name:                   pvcs-gold
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  1     10
requests.storage        2Gi   10Gi


Name:                   pvcs-silver
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  1     10
requests.storage        2Gi   20Gi


Name:                   pvcs-copper
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  1     10
requests.storage        2Gi   30Gi

使用以下命令打印 PVC 的清单:

kubectl get pvc gold-vac-pvc -o yaml

可能会显示如下输出:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: gold-vac-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: default
  volumeAttributesClassName: copper
status:
  accessModes:
    - ReadWriteOnce
  capacity:
    storage: 2Gi
  currentVolumeAttributesClassName: gold
  phase: Bound
  modifyVolumeStatus:
    status: InProgress
    targetVolumeAttributesClassName: silver
  storageClassName: default

稍等片刻,待卷修改完成后,再次验证配额:

kubectl describe quota
Name:                   pvcs-gold
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
requests.storage        0     10Gi


Name:                   pvcs-silver
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  0     10
requests.storage        0     20Gi


Name:                   pvcs-copper
Namespace:              default
Resource                Used  Hard
--------                ----  ----
persistentvolumeclaims  1     10
requests.storage        2Gi   30Gi

请求与限制的比较

分配计算资源时,每个容器可以为 CPU 或内存指定请求和约束。 配额可以针对二者之一进行设置。

如果配额中指定了 requests.cpurequests.memory 的值,则它要求每个容器都显式给出对这些资源的请求。 同理,如果配额中指定了 limits.cpulimits.memory 的值,那么它要求每个容器都显式设定对应资源的限制。

查看和设置配额

kubectl 支持创建、更新和查看配额:

kubectl create namespace myspace
cat <<EOF > compute-resources.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-resources
spec:
  hard:
    requests.cpu: "1"
    requests.memory: "1Gi"
    limits.cpu: "2"
    limits.memory: "2Gi"
    requests.nvidia.com/gpu: 4
EOF
kubectl create -f ./compute-resources.yaml --namespace=myspace
cat <<EOF > object-counts.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: object-counts
spec:
  hard:
    configmaps: "10"
    persistentvolumeclaims: "4"
    pods: "4"
    replicationcontrollers: "20"
    secrets: "10"
    services: "10"
    services.loadbalancers: "2"
EOF
kubectl create -f ./object-counts.yaml --namespace=myspace
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

kubectl 还使用语法 count/<resource>.<group> 支持所有标准的、命名空间域的资源的对象计数配额:

kubectl create namespace myspace
kubectl create quota test --hard=count/deployments.apps=2,count/replicasets.apps=4,count/pods=3,count/secrets=4 --namespace=myspace
kubectl create deployment nginx --image=nginx --namespace=myspace --replicas=2
kubectl describe quota --namespace=myspace
Name:                         test
Namespace:                    myspace
Resource                      Used  Hard
--------                      ----  ----
count/deployments.apps        1     2
count/pods                    2     3
count/replicasets.apps        1     4
count/secrets                 1     4

配额和集群容量

ResourceQuota 与集群资源总量是完全独立的。它们通过绝对的单位来配置。 所以,为集群添加节点时,资源配额不会自动赋予每个命名空间消耗更多资源的能力。

有时可能需要资源配额支持更复杂的策略,比如:

  • 在几个团队中按比例划分总的集群资源。
  • 允许每个租户根据需要增加资源使用量,但要有足够的限制以防止资源意外耗尽。
  • 探测某个命名空间的需求,添加物理节点并扩大资源配额值。

这些策略可以通过将资源配额作为一个组成模块、手动编写一个控制器来监控资源使用情况, 并结合其他信号调整命名空间上的硬性资源配额来实现。

注意:资源配额对集群资源总体进行划分,但它对节点没有限制:来自不同命名空间的 Pod 可能在同一节点上运行。

默认情况下限制特定优先级的资源消耗

有时候可能希望当且仅当某名字空间中存在匹配的配额对象时,才可以创建特定优先级 (例如 "cluster-services")的 Pod。

通过这种机制,操作人员能够限制某些高优先级类仅出现在有限数量的命名空间中, 而并非每个命名空间默认情况下都能够使用这些优先级类。

要实现此目的,应设置 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: PriorityClass
        operator: In
        values: ["cluster-services"]

现在在 kube-system 名字空间中创建一个资源配额对象:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: pods-cluster-services
spec:
  scopeSelector:
    matchExpressions:
      - operator : In
        scopeName: PriorityClass
        values: ["cluster-services"]
kubectl apply -f https://k8s.io/examples/policy/priority-class-resourcequota.yaml -n kube-system
resourcequota/pods-cluster-services created

在这里,当以下条件满足时可以创建 Pod:

  1. Pod 未设置 priorityClassName
  2. Pod 的 priorityClassName 设置值不是 cluster-services
  3. Pod 的 priorityClassName 设置值为 cluster-services,它将被创建于 kube-system 名字空间中,并且它已经通过了资源配额检查。

如果 Pod 的 priorityClassName 设置为 cluster-services,但要被创建到 kube-system 之外的别的名字空间,则 Pod 创建请求也被拒绝。

接下来

最后修改 October 18, 2025 at 4:36 PM PST: [zh-cn]sync resource-quotas.md (1250ff502b)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.