3、资源配额(ResourceQuota)原理:Kubernetes ResourceQuota 对象详解、作用域(Scope)、配额类型(计算、存储、对象数)及与 LimitRange 的配合

在多租户 Kubernetes 集群中,ResourceQuota 是防止“吵闹邻居”问题的核心机制。它通过限制命名空间(Namespace)级别的总资源消耗,确保每个租户不会过度抢占集群资源。本章将深入剖析 ResourceQuota 的对象结构、作用域、配额类型,并阐明其与 LimitRange 的协同关系。

3.1 ResourceQuota 对象详解

ResourceQuota 是一个 Kubernetes 原生 API 对象,作用于特定的 Namespace。它定义了一组硬性限制(Hard Limits),当 Namespace 内所有 Pod、PersistentVolumeClaim(PVC)等对象的资源使用总量超过这些限制时,API Server 会拒绝创建新的资源对象。

3.1.1 对象结构

一个典型的 ResourceQuota YAML 清单包含以下核心字段:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-quota
  namespace: tenant-a
spec:
  hard:
    requests.cpu: "4"
    requests.memory: "8Gi"
    limits.cpu: "8"
    limits.memory: "16Gi"
    persistentvolumeclaims: "10"
    pods: "20"
    services: "10"
    configmaps: "10"
    secrets: "10"
    count/deployments.apps: "5"
    count/statefulsets.apps: "5"
字段 说明 示例值
spec.hard 定义资源配额的上限(硬限制),键值对形式 requests.cpu: "4"
spec.scopes 可选字段,限定配额生效的 Pod 调度状态 BestEffort, NotTerminating
status.hard 当前生效的硬限制(只读) 与 spec.hard 一致
status.used 当前 Namespace 内已使用的资源量(只读) requests.cpu: "2.5"
最佳实践: 在 CAPI 管理的多租户场景中,建议为每个租户 Namespace 创建独立的 ResourceQuota,并在 ClusterClass 或 ClusterResourceSet 中通过模板自动注入,避免人工遗漏。

3.2 作用域(Scope)

ResourceQuota 的作用域允许管理员根据 Pod 的 QoS 类别 或 终止状态 来精细化控制配额。这在高密度多租户环境中尤为重要,可以防止低优先级 Pod 抢占关键业务的资源。

3.2.1 支持的 Scope 类型

Scope 名称 描述 适用场景
BestEffort 仅对 QoS 类别为 BestEffort 的 Pod 生效 限制批处理、测试任务的资源总量
NotBestEffort 对 QoS 类别非 BestEffort 的 Pod 生效 保障生产级服务的资源配额
Terminating 对 spec.activeDeadlineSeconds 已设置的 Pod 生效 限制有超时时间的 Job 类任务
NotTerminating 对 spec.activeDeadlineSeconds 未设置的 Pod 生效 限制常驻服务(Deployment、StatefulSet)
PriorityClass 根据 PriorityClass 名称匹配(需指定 scopeSelector) 按优先级隔离不同租户的关键业务

3.2.2 使用示例:按 QoS 隔离

apiVersion: v1
kind: ResourceQuota
metadata:
  name: best-effort-quota
  namespace: tenant-b
spec:
  hard:
    pods: "10"
    requests.cpu: "2"
    requests.memory: "4Gi"
  scopes:
    - BestEffort
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: guaranteed-quota
  namespace: tenant-b
spec:
  hard:
    pods: "20"
    requests.cpu: "8"
    requests.memory: "32Gi"
  scopes:
    - NotBestEffort
关键点: 一个 Namespace 可以同时存在多个 ResourceQuota,只要它们的作用域不重叠。Kubernetes 会计算所有匹配的 ResourceQuota 的并集作为最终限制。

3.3 配额类型

ResourceQuota 支持三类配额:计算资源、存储资源 和 对象数量。理解每种类型的计量单位是正确配置的前提。

3.3.1 计算资源配额

资源名称 单位 说明
requests.cpu 核(m 或整数) 所有 Pod 的 CPU 请求总和上限
requests.memory 字节(Mi、Gi) 所有 Pod 的内存请求总和上限
limits.cpu 核(m 或整数) 所有 Pod 的 CPU 限制总和上限
limits.memory 字节(Mi、Gi) 所有 Pod 的内存限制总和上限

3.3.2 存储资源配额

资源名称 单位 说明
requests.storage 字节(Gi、Ti) 所有 PVC 的存储请求总和上限
persistentvolumeclaims 整数 PVC 对象数量上限
requests.ephemeral-storage 字节(Gi) 临时存储请求总和上限

3.3.3 对象数量配额

资源名称 说明
pods Pod 对象数量上限
services Service 对象数量上限
configmaps ConfigMap 对象数量上限
secrets Secret 对象数量上限
count/deployments.apps 特定 API 资源的对象数量上限(通用格式)
count/statefulsets.apps StatefulSet 对象数量上限
注意: 对象数量配额使用 count/<resource>.<group> 格式时,必须确保 API 组名称正确。例如 count/deployments.apps 中的 apps 是 API 组名,不可省略。

3.4 ResourceQuota 与 LimitRange 的配合

ResourceQuota 控制的是 总量,而 LimitRange 控制的是 单个 Pod 或容器的默认值/极值。两者必须配合使用,才能构建完整的资源治理体系。

3.4.1 为什么需要 LimitRange?

  • 防止单个 Pod 过度占用: 如果没有 LimitRange,一个 Pod 可以声明 limits.cpu: 100,即使 ResourceQuota 总量为 10,也会导致其他 Pod 无法调度。
  • 提供默认值: 当 Pod 未显式设置 requests 或 limits 时,LimitRange 可以自动注入默认值,确保 ResourceQuota 的计量准确。
  • 约束范围: 限制 Pod 的 requests 和 limits 的最小值、最大值,避免极端配置。

3.4.2 典型配合模式

# LimitRange:为每个容器设置默认值和范围
apiVersion: v1
kind: LimitRange
metadata:
  name: container-limits
  namespace: tenant-a
spec:
  limits:
    - type: Container
      default:
        cpu: "500m"
        memory: "512Mi"
      defaultRequest:
        cpu: "200m"
        memory: "256Mi"
      max:
        cpu: "2"
        memory: "4Gi"
      min:
        cpu: "50m"
        memory: "64Mi"
---
# ResourceQuota:限制 Namespace 总量
apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-quota
  namespace: tenant-a
spec:
  hard:
    requests.cpu: "8"
    requests.memory: "16Gi"
    limits.cpu: "16"
    limits.memory: "32Gi"
    pods: "20"

3.4.3 协同工作流程

  1. 准入控制阶段: LimitRange 首先对 Pod 进行校验,确保其资源声明在 min 和 max 范围内;如果未设置,则注入默认值。
  2. 配额校验阶段: ResourceQuota 控制器计算 Namespace 内所有 Pod 的资源总和(包括 LimitRange 注入的默认值),判断是否超过 hard 限制。
  3. 拒绝或允许: 只有同时通过 LimitRange 和 ResourceQuota 校验的 Pod 才会被创建。
ResourceQuota 与 LimitRange 协同工作流程 用户创建 Pod LimitRange 准入控制 注入默认值 / 校验 min-max 范围 拒绝创建 返回错误信息 通过 LimitRange 进入 ResourceQuota 校验 ResourceQuota 校验 检查 Namespace 总量 Pod 创建成功
实战要点: 在 CAPI 多租户集群中,建议先创建 LimitRange 再创建 ResourceQuota,或者通过 Admission Webhook 保证两者同时生效。如果只配置 ResourceQuota 而不配置 LimitRange,未设置资源限制的 Pod 将无法通过配额校验(因为 requests 和 limits 为 0,可能被拒绝或导致配额计算异常)。

3.5 多租户场景下的配置建议

  • 按租户粒度隔离: 每个租户 Namespace 独立配置 ResourceQuota,避免跨 Namespace 的资源争抢。
  • 设置合理的缓冲: 配额总量建议为预期使用量的 1.2~1.5 倍,避免因 Pod 滚动更新时的临时资源占用导致拒绝。
  • 监控配额使用率: 通过 kubectl describe resourcequota 或 Prometheus 监控 kube_resourcequota 指标,及时调整配额。
  • 结合 PriorityClass: 使用 scopeSelector 为高优先级 Pod 预留独立配额,保障关键业务。