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 | 控制跨命名空间调度的影响 |
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 控制循环的影响:
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 | 无内置重试,需自行实现 | 容易导致无限循环或资源泄漏 |
ResourceQuota 的 status.used 字段,结合 status.hard 计算剩余配额。如果剩余配额不足,直接返回成功(不触发重试),等待下一次 Requeue 周期(通常 10-30 秒)再检查。这样可以避免指数退避导致的长时间延迟。