3. 资源配额(ResourceQuota):CPU/内存配额、对象数量配额、作用域与优先级

在多租户集群中,资源配额是防止“噪声邻居”效应、保障租户间公平调度的第一道防线。Kubernetes 的 ResourceQuota 对象为每个命名空间设定资源消耗上限,涵盖计算资源(CPU/内存)、存储资源以及各类 API 对象的数量。本章将深入剖析配额模型、作用域机制与优先级冲突处理,帮助你在蓝图模板中构建可预测、可审计的资源边界。

3.1 配额核心模型:CPU 与内存的语义差异

CPU 和内存是两种不同压缩属性的资源,配额系统对它们的处理方式截然不同:

属性 CPU 内存
可压缩性 可压缩(限流,不杀死 Pod) 不可压缩(OOM 时杀死 Pod)
配额单位 m(毫核),1 CPU = 1000m Mi、Gi 等二进制单位
requests 与 limits requests 保证调度,limits 限制突发 requests 保证分配,limits 防止泄漏
超额行为 Pod 可运行,但被限流(throttle) Pod 被 OOM Kill
配额检查时机 Pod 创建/更新时 Pod 创建/更新时
调优要点: 对于延迟敏感型工作负载(如实时推理),建议将 CPU requests 设置得接近 limits,避免因 CPU 限流导致 P99 延迟抖动。对于批处理任务,可以适当放大 CPU limits 以利用空闲周期。

3.2 对象数量配额:控制集群控制面压力

除了计算资源,ResourceQuota 还可以限制命名空间内各类 API 对象的数量。这是防止租户创建海量小对象压垮 etcd 或 API Server 的关键手段。

apiVersion: v1
kind: ResourceQuota
metadata:
  name: tenant-quota
  namespace: tenant-a
spec:
  hard:
    # 计算资源
    requests.cpu: "10"
    requests.memory: "20Gi"
    limits.cpu: "20"
    limits.memory: "40Gi"
    # 存储资源
    requests.storage: "100Gi"
    persistentvolumeclaims: "10"
    # 核心对象数量
    pods: "50"
    services: "10"
    configmaps: "20"
    secrets: "20"
    replicationcontrollers: "10"
    # 扩展对象数量
    count/deployments.apps: "5"
    count/statefulsets.apps: "5"
    count/jobs.batch: "10"
    count/cronjobs.batch: "5"
注意: 对象数量配额使用 count/<resource>.<group> 格式。对于集群作用域的资源(如 Node、PersistentVolume),ResourceQuota 无法限制,需要使用 ClusterResourceQuota(OpenShift 特性)或准入控制策略。

3.3 作用域(Scopes):精细化配额控制

作用域允许配额只对特定状态的 Pod 生效,避免“一刀切”导致资源浪费。Kubernetes 内置了以下作用域:

作用域 含义 典型场景
BestEffort Pod 未设置 requests 和 limits 限制低优先级、无 QoS 保证的测试 Pod
NotBestEffort Pod 设置了 requests 或 limits 保障生产级 Pod 的资源池
Terminating Pod 设置了 activeDeadlineSeconds 批处理任务、CI/CD 构建 Pod
NotTerminating Pod 未设置 activeDeadlineSeconds 长期运行的服务 Pod
PriorityClass 基于 PriorityClass 名称匹配 高优与低优工作负载隔离

通过组合作用域,可以为同一命名空间创建多个配额对象,实现分层资源池:

# 高优 Pod 配额:允许使用更多资源
apiVersion: v1
kind: ResourceQuota
metadata:
  name: high-priority-quota
  namespace: tenant-a
spec:
  hard:
    pods: "20"
    requests.cpu: "8"
    requests.memory: "16Gi"
  scopeSelector:
    matchExpressions:
    - operator: In
      scopeName: PriorityClass
      values: ["high-priority"]

---
# 低优 Pod 配额:限制严格
apiVersion: v1
kind: ResourceQuota
metadata:
  name: low-priority-quota
  namespace: tenant-a
spec:
  hard:
    pods: "10"
    requests.cpu: "2"
    requests.memory: "4Gi"
  scopeSelector:
    matchExpressions:
    - operator: In
      scopeName: PriorityClass
      values: ["low-priority"]
最佳实践: 在蓝图模板中,为每个租户命名空间创建至少两个配额对象:一个用于 NotTerminating + NotBestEffort 作用域(保障在线服务),另一个用于 Terminating + BestEffort 作用域(允许离线任务弹性使用空闲资源)。

3.4 优先级与冲突处理:配额准入的裁决逻辑

当多个配额对象作用于同一个 Pod 时,Kubernetes 使用以下优先级规则进行裁决:

  1. 作用域匹配优先:Pod 匹配的 scopeSelector 越精确,对应配额越优先。
  2. 最小剩余量优先:如果多个配额都匹配,系统选择剩余资源比例最小的配额进行校验,避免资源碎片。
  3. 硬限制不可突破:所有匹配的配额中,任何一个的 hard 限制被违反,Pod 创建都会被拒绝。
  4. 默认配额兜底:如果 Pod 不匹配任何作用域,则使用不带 scopeSelector 的默认配额。

以下 SVG 图展示了多租户场景下配额准入的完整决策流程:

ResourceQuota 准入决策流程 Pod 创建请求 匹配 scopeSelector 或默认 Quota? 是 收集所有匹配的 Quota 列表 计算每个 Quota 的剩余资源比例 选择剩余比例最小的 Quota 校验 校验通过 → Pod 创建成功 拒绝创建 否 拒绝创建 说明:当多个 Quota 匹配时,系统选择剩余资源比例最小的 Quota 进行校验,确保资源分配最紧张的 Quota 优先被满足。 任何匹配的 Quota 中有一个违反 hard 限制,Pod 创建即被拒绝。

3.5 性能调优:配额对调度器与 API Server 的影响

大规模集群中,ResourceQuota 的频繁校验可能成为性能瓶颈。以下是关键调优方向:

组件 影响 调优策略
API Server 每次 Pod 创建/更新都触发配额校验,增加 etcd 读取压力 启用 --admission-control-config-file 配置配额准入缓存;使用 ResourceQuota 的 spec.scopeSelector 减少不必要的校验
Scheduler 配额校验在调度前完成,但调度器仍需等待准入结果 使用 PodSchedulingReadiness 门控提前过滤不可调度 Pod;避免在配额已满时反复重试
etcd 大量 ResourceQuota 对象(每个命名空间多个)增加存储和 watch 开销 合并作用域相近的配额对象;使用 count/ 前缀限制配额对象自身数量
Kubelet 配额不直接影响 Kubelet,但 Pod 创建失败后 Kubelet 会重试 设置合理的 --pod-max-in-unschedulable-pods-duration 避免无效重试
实战经验: 在 500+ 节点集群中,我们观察到每个命名空间超过 5 个 ResourceQuota 对象时,API Server 的准入延迟从 2ms 上升到 15ms。建议将配额对象数量控制在每个命名空间 3 个以内,并通过 scopeSelector 的 operator: In 组合多个值来减少对象数量。

3.6 蓝图模板中的配额设计模式

基于以上分析,我们在多租户蓝图模板中推荐以下配额设计模式:

  1. 分层配额:为每个租户命名空间创建 3 个配额对象——在线服务配额(NotTerminating + NotBestEffort)、离线任务配额(Terminating)、弹性配额(BestEffort)。
  2. 预留缓冲:配额 hard 值设置为集群容量的 80%,预留 20% 给系统组件和突发扩容。
  3. 对象数量限制:对 pods、services、configmaps 设置硬上限,防止租户创建海量小对象。
  4. 优先级隔离:使用 PriorityClass 作用域将高优工作负载与低优工作负载的配额池完全隔离。
  5. 监控告警:对配额使用率设置告警阈值(如 80% 告警、95% 严重告警),提前干预。

以下 SVG 图展示了蓝图模板中推荐的配额分层架构:

蓝图模板:分层 ResourceQuota 架构 租户命名空间:tenant-a 在线服务配额 scope: NotTerminating scope: NotBestEffort CPU: 8 / Mem: 16Gi Pods: 30 / Svcs: 5 离线任务配额 scope: Terminating CPU: 4 / Mem: 8Gi Pods: 20 / Jobs: 10 CronJobs: 5 弹性配额 scope: BestEffort CPU: 2 / Mem: 4Gi Pods: 10 (无 QoS 保证) 在线服务 Pod(高优) 批处理 Job Pod(中优) 测试 Pod(低优) 说明:每个租户命名空间包含 3 个独立配额池,通过 scopeSelector 精确匹配不同优先级的 Pod。 在线服务配额使用 NotTerminating + NotBestEffort 确保长期运行的服务不被离线任务挤占。
关键结论: ResourceQuota 是多租户集群资源隔离的基石。通过合理设计作用域、优先级和对象数量限制,可以在不牺牲资源利用率的前提下,为每个租户提供可预测的资源边界。在蓝图模板中,建议将配额设计为可配置参数,通过 GitOps 流程统一管理,避免手动修改导致的配置漂移。