3. ResourceQuota 进阶:配额作用域、优先级类与配额关联、硬限制与软限制

ResourceQuota 的基础用法只能按 Namespace 做总量控制,但在多租户、多优先级、多工作负载类型的生产集群中,这种粗粒度配额远远不够。Kubernetes 提供了 ScopeSelector(配额作用域)、PriorityClass(优先级类) 与配额关联机制,以及 硬限制(Hard) 与 软限制(Soft) 的差异化策略,让资源配额从“一刀切”进化为“精细化治理”。

3.1 配额作用域(ScopeSelector)

ScopeSelector 允许 ResourceQuota 只匹配特定“作用域”内的 Pod 或资源对象,从而实现按资源生命周期、服务质量等级(QoS)或优先级进行差异化配额控制。

3.1.1 内置作用域类型

作用域名称 匹配对象 典型场景
BestEffort QoS 等级为 BestEffort 的 Pod 限制低优先级、无资源预留的“尽力而为”型任务
NotBestEffort QoS 等级非 BestEffort 的 Pod(Guaranteed 或 Burstable) 保障有资源预留的生产级 Pod 的配额
Terminating activeDeadlineSeconds 被设置的 Pod 批处理、Job 类有生命周期的任务
NotTerminating activeDeadlineSeconds 未被设置的 Pod 长期运行的服务(Deployment、StatefulSet)
PriorityClass 指定优先级类的 Pod(需配合 scopeSelector.matchExpressions) 按优先级类隔离配额池

3.1.2 使用 ScopeSelector 的 YAML 示例

以下 ResourceQuota 只对 非 BestEffort 且 非 Terminating 的 Pod 生效,即只限制长期运行且有资源预留的服务 Pod:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: production
spec:
  hard:
    requests.cpu: "20"
    requests.memory: "40Gi"
    limits.cpu: "40"
    limits.memory: "80Gi"
  scopeSelector:
    matchExpressions:
      - operator: In
        scopeName: NotBestEffort
      - operator: In
        scopeName: NotTerminating
最佳实践: 在同一个 Namespace 中可以创建多个 ResourceQuota,每个使用不同的 ScopeSelector,实现“按类型分池”的配额管理。例如:一个配额池给长期服务(NotBestEffort + NotTerminating),另一个配额池给批处理任务(BestEffort + Terminating)。

3.2 优先级类(PriorityClass)与配额关联

PriorityClass 是 Kubernetes 调度优先级的核心对象。通过将 PriorityClass 与 ResourceQuota 的 ScopeSelector 关联,可以实现 按优先级分配资源配额,确保高优先级工作负载不会被低优先级任务挤占资源。

3.2.1 优先级类定义示例

apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: high-priority
value: 1000000
globalDefault: false
description: "高优先级生产服务"
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: low-priority
value: 100
globalDefault: false
description: "低优先级批处理任务"

3.2.2 按优先级类隔离配额

通过 scopeSelector 的 PriorityClass 作用域,可以为不同优先级类创建独立的配额池:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: high-priority-quota
  namespace: production
spec:
  hard:
    pods: "50"
    requests.cpu: "10"
    requests.memory: "20Gi"
  scopeSelector:
    matchExpressions:
      - operator: In
        scopeName: PriorityClass
        values: ["high-priority"]
---
apiVersion: v1
kind: ResourceQuota
metadata:
  name: low-priority-quota
  namespace: production
spec:
  hard:
    pods: "200"
    requests.cpu: "30"
    requests.memory: "60Gi"
  scopeSelector:
    matchExpressions:
      - operator: In
        scopeName: PriorityClass
        values: ["low-priority"]
注意: 使用 PriorityClass 作用域时,Pod 必须显式设置 priorityClassName,否则不会被任何 PriorityClass 作用域的配额匹配。未设置优先级类的 Pod 默认使用集群的 globalDefault PriorityClass(如果存在),否则不会被匹配。

3.3 配额硬限制与软限制

ResourceQuota 支持两种限制模式:硬限制(Hard) 和 软限制(Soft)。硬限制是阈值,超过即拒绝;软限制允许超过,但会触发告警或驱逐机制。

3.3.1 硬限制(Hard)

硬限制是 ResourceQuota 的默认模式。当 Namespace 内的资源使用量达到或超过硬限制时,Kubernetes API Server 会拒绝创建新的 Pod 或资源对象,并返回 403 Forbidden 错误。

  • 适用场景: 资源容量上限、租户隔离、成本控制。
  • 行为: 立即拒绝,不可协商。
  • 示例: pods: "100" 表示最多允许 100 个 Pod。

3.3.2 软限制(Soft)

软限制允许资源使用量超过阈值,但会记录事件并触发 配额驱逐(Quota Eviction)。Kubernetes 会定期检查软限制,如果超过阈值且持续时间超过 gracePeriod,则会驱逐 Pod 以回收资源。

  • 适用场景: 突发流量容忍、资源弹性、渐进式告警。
  • 行为: 允许超过,但超过后进入“宽限期”,宽限期结束后驱逐 Pod。
  • 配置: 使用 spec.scopes 或 scopeSelector 配合 spec.hard 和 spec.soft 字段。

3.3.3 硬限制与软限制对比

特性 硬限制(Hard) 软限制(Soft)
阈值行为 超过即拒绝 超过允许,但触发驱逐
宽限期 无 可配置(gracePeriod)
适用资源 所有配额资源 仅支持 requests.* 和 limits.*
驱逐机制 无 超过宽限期后驱逐 Pod
典型用途 硬性资源上限 弹性资源池、突发流量缓冲

3.3.4 软限制配置示例

apiVersion: v1
kind: ResourceQuota
metadata:
  name: soft-quota
  namespace: elastic
spec:
  hard:
    requests.cpu: "10"
    requests.memory: "20Gi"
  soft:
    requests.cpu: "8"
    requests.memory: "16Gi"
  scopeSelector:
    matchExpressions:
      - operator: In
        scopeName: NotBestEffort
关键行为: 当 Namespace 的 CPU 请求超过 8 核(软限制)但未达到 10 核(硬限制)时,Kubernetes 会记录 Event 并启动宽限期计时器。如果宽限期(默认 7 天,可通过 --soft-eviction-grace-period 调整)内资源使用量未回落到软限制以下,kubelet 将开始驱逐 Pod,直到资源使用量低于软限制。

3.4 综合架构:ScopeSelector + PriorityClass + 硬/软限制

将上述三个概念组合,可以构建一个完整的、多层次的配额治理体系。以下 SVG 图展示了这种组合架构:

ResourceQuota 进阶组合架构 Namespace: production 高优先级配额池 Scope: PriorityClass=high Hard: CPU 10, Mem 20Gi Soft: CPU 8, Mem 16Gi Pod 上限: 50 宽限期: 5 分钟 低优先级配额池 Scope: PriorityClass=low Hard: CPU 30, Mem 60Gi Soft: CPU 25, Mem 50Gi Pod 上限: 200 宽限期: 15 分钟 批处理配额池 Scope: BestEffort + Terminating Hard: CPU 5, Mem 10Gi Soft: 无 Pod 上限: 100 无宽限期 Pod: web-server priorityClassName: high Pod: batch-job priorityClassName: low Pod: data-crunch 无 priorityClassName 说明: • 每个配额池独立计数,互不干扰。 • 高优先级配额池使用软限制(宽限期 5 分钟),低优先级使用软限制(宽限期 15 分钟),批处理仅使用硬限制。 • 未设置 priorityClassName 的 Pod 默认匹配批处理配额池(如果集群配置了 globalDefault)。

3.5 生产实践建议

  • 分层设计: 为每个 Namespace 创建至少 2-3 个 ResourceQuota,分别覆盖高优先级服务、低优先级任务和批处理作业。
  • 软限制宽限期: 高优先级服务的软限制宽限期应较短(如 1-5 分钟),以便快速回收资源;低优先级任务可设置较长宽限期(如 15-30 分钟),容忍突发流量。
  • 监控与告警: 使用 kubectl describe resourcequota 或 Prometheus 监控配额使用率,对软限制触发事件设置告警。
  • 避免冲突: 同一个 Pod 只能被一个 ResourceQuota 的 ScopeSelector 匹配。如果多个配额的作用域重叠,Pod 创建会失败。建议使用互斥的作用域组合。
进阶技巧: 结合 LimitRange 与 ResourceQuota 使用。LimitRange 设置 Pod 和容器的默认资源请求/限制以及最小/最大值,ResourceQuota 设置 Namespace 总量上限。两者配合可以实现“容器级别约束 + Namespace 级别总量控制”的完整治理。