3. Kubernetes 资源配额(ResourceQuota)详解:CPU、内存、存储、对象数量限制

在多租户 Kubernetes 集群中,资源配额(ResourceQuota)是防止“吵闹邻居”效应、保障租户间公平调度的核心机制。Argo CD 在部署多租户应用时,必须确保每个 Namespace 的配额设置合理,否则应用可能因资源不足而无法调度。本章深入解析 ResourceQuota 的四种限制维度:计算资源(CPU/内存)、存储资源、对象数量,以及配额的作用域与最佳实践。

核心概念: ResourceQuota 是 Namespace 级别的资源约束对象,它通过 Admission Controller 在 Pod 创建或更新时进行校验。一旦 Namespace 设置了配额,该 Namespace 下的所有 Pod 必须显式声明资源请求(requests)和限制(limits),否则无法创建。

3.1 资源配额的四维模型

Kubernetes ResourceQuota 从四个维度对 Namespace 进行资源管控,每个维度对应不同的资源类型和计量单位:

维度 资源类型 计量单位 典型配额字段
计算资源 CPU、内存 CPU: 核心数(如 1、500m)
内存: 字节(如 1Gi、512Mi)
requests.cpu, limits.memory
存储资源 持久卷声明(PVC) 字节(如 10Gi、100Gi) requests.storage, persistentvolumeclaims
对象数量 Kubernetes 对象(Pod、Service、ConfigMap 等) 整数(如 100、50) count/pods, count/services
扩展资源 GPU、FPGA 等自定义资源 整数(如 1、2) requests.nvidia.com/gpu
关键区别: 计算资源和存储资源限制的是“资源总量”,而对象数量限制的是“对象实例数”。例如,limits.cpu: 10 表示所有 Pod 的 CPU 上限总和不超过 10 核;count/pods: 50 表示该 Namespace 最多只能创建 50 个 Pod。
ResourceQuota 四维模型架构图 ResourceQuota 四维模型架构图 ResourceQuota 计算资源 CPU / 内存 存储资源 PVC / 存储总量 对象数量 Pod / Service / ConfigMap 扩展资源 GPU / FPGA / 自定义 每个维度独立配置,可同时设置多个配额对象

3.2 计算资源配额:CPU 与内存

计算资源配额是 ResourceQuota 最常用的维度,它控制 Namespace 内所有容器对 CPU 和内存的消耗。配额分为 requests(请求量)和 limits(上限)两个层面:

  • requests.cpu / requests.memory:所有 Pod 的请求量总和上限,用于调度决策。
  • limits.cpu / limits.memory:所有 Pod 的限制量总和上限,用于运行时资源上限。

以下是一个典型的计算资源配额 YAML 示例:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: compute-quota
  namespace: team-alpha
spec:
  hard:
    requests.cpu: "4"        # 所有 Pod 的 CPU 请求总和不超过 4 核
    requests.memory: "8Gi"   # 所有 Pod 的内存请求总和不超过 8Gi
    limits.cpu: "8"          # 所有 Pod 的 CPU 上限总和不超过 8 核
    limits.memory: "16Gi"    # 所有 Pod 的内存上限总和不超过 16Gi
注意: 如果 Namespace 设置了 ResourceQuota,则每个 Pod 必须显式声明 resources.requests 和 resources.limits。未声明的 Pod 创建请求会被 Admission Controller 拒绝。这是多租户场景中常见的“配额陷阱”。

3.3 存储资源配额:PVC 与存储总量

存储资源配额控制 Namespace 内持久卷声明(PVC)的总存储容量和数量。主要字段包括:

字段 说明 示例值
requests.storage 所有 PVC 的存储请求总和上限 100Gi
persistentvolumeclaims PVC 对象数量上限 10
requests.storage/<storage-class> 按 StorageClass 细分的存储配额 requests.storage/ssd: 50Gi

示例:限制 Namespace 内所有 PVC 总存储不超过 100Gi,且最多创建 10 个 PVC:

spec:
  hard:
    requests.storage: "100Gi"
    persistentvolumeclaims: "10"

3.4 对象数量配额:限制 Kubernetes 对象实例

对象数量配额用于防止某个租户创建过多 Kubernetes 对象,导致 etcd 或 API Server 压力过大。支持限制的对象类型包括:

  • 核心对象:count/pods、count/services、count/configmaps、count/secrets
  • 工作负载对象:count/deployments.apps、count/statefulsets.apps、count/jobs.batch
  • 网络对象:count/ingresses.networking.k8s.io、count/networkpolicies.networking.k8s.io
  • RBAC 对象:count/rolebindings.rbac.authorization.k8s.io、count/roles.rbac.authorization.k8s.io

示例:限制 Namespace 内最多 50 个 Pod、20 个 Service、10 个 ConfigMap:

spec:
  hard:
    count/pods: "50"
    count/services: "20"
    count/configmaps: "10"
最佳实践: 在多租户场景中,建议至少限制 count/pods 和 count/services,防止租户创建大量空 Pod 或 Service 进行资源耗尽攻击。Argo CD 部署应用时,应提前检查目标 Namespace 的配额余量,避免部署失败。

3.5 配额作用域(Scope)与优先级

ResourceQuota 支持通过 scopes 字段限定配额生效范围,常见作用域包括:

作用域 说明 适用场景
BestEffort 仅限制 QoS 为 BestEffort 的 Pod(未设置 requests/limits) 限制低优先级任务
NotBestEffort 仅限制 QoS 不为 BestEffort 的 Pod 保障高优先级任务资源
Terminating 仅限制设置了 activeDeadlineSeconds 的 Pod 批处理任务配额
NotTerminating 仅限制未设置 activeDeadlineSeconds 的 Pod 长期运行服务配额
PriorityClass 按 PriorityClass 名称细分配额 多优先级资源隔离

示例:为高优先级任务(PriorityClass: high)单独设置配额:

spec:
  hard:
    pods: "10"
    requests.cpu: "2"
    requests.memory: "4Gi"
  scopes:
    - PriorityClass
  scopeSelector:
    matchExpressions:
      - key: priorityclass
        operator: In
        values: ["high"]

3.6 多租户场景下的配额设计策略

在 Argo CD 结合多租户的实践中,ResourceQuota 的设计需要遵循以下原则:

  1. 按租户粒度分配:每个租户(Team/Project)对应一个 Namespace,每个 Namespace 设置独立的 ResourceQuota。
  2. 预留缓冲余量:配额总和应小于集群总容量,预留 10%-20% 的缓冲空间用于突发调度。
  3. 分层配额:同时设置计算资源配额和对象数量配额,避免单一维度成为瓶颈。
  4. 动态调整:通过 Argo CD 的 ApplicationSet 或 GitOps 流水线,在部署时自动注入或更新 ResourceQuota。
  5. 监控告警:使用 kubectl describe quota 或 Prometheus 监控配额使用率,接近上限时触发告警。
多租户 ResourceQuota 设计流程图 多租户 ResourceQuota 设计流程图 集群总容量评估 预留 15% 缓冲空间 按租户分配配额 计算 + 存储配额 对象数量配额 Argo CD 部署校验

3.7 配额冲突排查与 Argo CD 集成

当 Argo CD 尝试同步应用时,如果目标 Namespace 的 ResourceQuota 不足,会触发以下错误:

Error: failed to create pod: pods "my-app-xxx" is forbidden: exceeded quota: compute-quota, 
requested: requests.cpu=500m, used: requests.cpu=4, limited: requests.cpu=4

排查步骤:

  1. 使用 kubectl describe quota -n <namespace> 查看当前配额使用情况。
  2. 检查 Argo CD Application 的 spec.destination.namespace 是否正确。
  3. 在 Argo CD 的 PreSync hook 中添加配额检查脚本,提前预警。
  4. 使用 argocd app diff 对比当前资源与目标资源,确认资源请求量。
Argo CD 集成建议: 在 ApplicationSet 模板中,为每个租户的 Namespace 自动生成 ResourceQuota 对象,并通过 syncPolicy.autoSelfHeal 确保配额始终与 Git 仓库一致。这样,配额变更只需修改 Git 仓库中的 YAML 文件,Argo CD 会自动同步。