3. CAPI Provider机制
在多租户 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 协同工作流程
- 准入控制阶段: LimitRange 首先对 Pod 进行校验,确保其资源声明在
min和max范围内;如果未设置,则注入默认值。 - 配额校验阶段: ResourceQuota 控制器计算 Namespace 内所有 Pod 的资源总和(包括 LimitRange 注入的默认值),判断是否超过
hard限制。 - 拒绝或允许: 只有同时通过 LimitRange 和 ResourceQuota 校验的 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 预留独立配额,保障关键业务。