3. ResourceQuota 基础:API 定义、作用域与资源类型

ResourceQuota 是 Kubernetes 内置的准入控制机制,用于限制命名空间(Namespace)级别的资源消耗总量。对于 Operator 开发者而言,理解 ResourceQuota 的底层定义、作用域以及所支持的资源类型,是评估控制循环稳定性的第一步。当 Operator 在配额不足的命名空间中创建 Pod 或 PVC 时,API Server 会直接拒绝请求,导致控制循环进入重试-失败-再重试的震荡状态。

3.1 ResourceQuota API 定义

ResourceQuota 的完整 API 定义位于 v1 核心组,其核心结构包含 Spec.Hard(硬限制)和 Status.Hard/Status.Used(当前使用量)。以下是一个标准的 ResourceQuota YAML 定义:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: my-namespace
spec:
  hard:
    requests.cpu: "4"
    requests.memory: "8Gi"
    limits.cpu: "8"
    limits.memory: "16Gi"
    persistentvolumeclaims: "10"
    pods: "50"
    count/deployments.apps: "5"
    count/services: "10"
  scopeSelector:
    matchExpressions:
      - operator: In
        scopeName: PriorityClass
        values:
          - high-priority
关键字段说明:
  • spec.hard:定义资源上限的硬约束,键为资源类型,值为配额数值。
  • spec.scopeSelector:可选字段,用于将配额限定到特定作用域(如特定 PriorityClass)。
  • status.hard:实际生效的硬限制(与 spec.hard 一致)。
  • status.used:当前命名空间内已使用的资源量,由 Kubernetes 控制器自动更新。

3.2 作用域(Scope)

ResourceQuota 支持通过 scopeSelector 或 scopes 字段将配额限制到特定的资源子集。作用域决定了哪些对象会被计入配额统计。下表列出了 Kubernetes 内置的 Scope 类型及其含义:

Scope 名称 作用范围 典型使用场景
BestEffort 仅 QoS 等级为 BestEffort 的 Pod 限制低优先级任务的资源总量
NotBestEffort QoS 等级非 BestEffort 的 Pod 保障高优先级 Pod 的资源池
Terminating 设置了 activeDeadlineSeconds 的 Pod 限制批处理作业的资源消耗
NotTerminating 未设置 activeDeadlineSeconds 的 Pod 限制常驻服务 Pod 的资源
PriorityClass 指定 PriorityClass 名称的 Pod 按优先级等级分配配额
CrossNamespacePodAffinity 使用了跨命名空间 Pod 亲和性的 Pod 控制跨命名空间调度的影响
Operator 开发提示: 当 Operator 创建 Pod 时,如果未显式设置 requests 和 limits,该 Pod 会被归入 BestEffort 作用域。如果命名空间同时配置了 BestEffort 和 NotBestEffort 两个 ResourceQuota,Operator 创建的 Pod 可能因作用域不匹配而意外被拒绝。建议 Operator 始终为 Pod 设置明确的资源请求和限制。

3.3 支持的资源类型

ResourceQuota 支持三类资源:计算资源(CPU/内存)、存储资源(PVC/临时存储)和对象计数(Pod/Service/ConfigMap 等)。下表按类别列出所有标准资源类型:

类别 资源类型键 单位/说明
计算资源 requests.cpu CPU 请求总量,单位:m(毫核)
requests.memory 内存请求总量,单位:Mi/Gi
limits.cpu CPU 限制总量
limits.memory 内存限制总量
存储资源 requests.storage 所有 PVC 的存储请求总量
persistentvolumeclaims PVC 对象数量上限
requests.ephemeral-storage 临时存储请求总量
对象计数 pods Pod 对象数量上限
services Service 对象数量上限
configmaps ConfigMap 对象数量上限
persistentvolumeclaims PVC 对象数量上限(与存储资源重叠)
count/deployments.apps 特定 API 资源的计数,格式:count/<resource>.<group>
count/ingresses.networking.k8s.io Ingress 对象计数
常见陷阱: 对象计数类型的键名区分大小写,且必须使用复数形式。例如 count/deployments.apps 正确,count/deployment.apps 或 count/Deployments.apps 均无效。Operator 在创建自定义资源(CRD)时,如果未在 ResourceQuota 中显式声明对应的 count/ 条目,该 CRD 对象将不受配额限制,可能导致资源失控。

3.4 ResourceQuota 与准入控制流程

下图展示了 ResourceQuota 在 Kubernetes 准入控制链中的位置及其对 Operator 控制循环的影响:

ResourceQuota 准入控制流程 Operator 控制循环 创建 Pod/PVC 请求 API Server 准入控制 ResourceQuota 检查 配额充足? 允许创建 拒绝并返回 403 控制循环重试 影响分析: 当 ResourceQuota 拒绝请求时,Operator 控制循环会进入指数退避重试。如果配额长期不足,重试间隔可能增长到 5 分钟以上, 导致控制循环延迟、Requeue 堆积,甚至触发 Leader 选举超时。建议 Operator 在创建资源前主动查询配额使用量。

3.5 配额不足时的控制循环行为

当 Operator 尝试创建资源但命名空间配额不足时,API Server 会返回 HTTP 403 Forbidden 错误,错误消息中包含 exceeded quota 字样。Operator 的 Reconciler 通常会将此错误视为临时故障,触发 Requeue 并进入指数退避。以下是不同 Operator 框架的典型行为对比:

Operator 框架 默认重试策略 对控制循环稳定性的影响
controller-runtime (Go) 指数退避,最大间隔 16 分钟 Requeue 队列堆积,延迟增加
Operator SDK (Ansible) 固定间隔 5 秒,最多重试 10 次 快速失败,但可能错过临时配额释放
Kopf (Python) 可配置退避,默认 30 秒 相对温和,但需手动处理配额检查
自定义 Shell Operator 无内置重试,需自行实现 容易导致无限循环或资源泄漏
最佳实践: 在 Operator 的 Reconciler 中,建议在创建资源前调用 ResourceQuota 的 status.used 字段,结合 status.hard 计算剩余配额。如果剩余配额不足,直接返回成功(不触发重试),等待下一次 Requeue 周期(通常 10-30 秒)再检查。这样可以避免指数退避导致的长时间延迟。