3. Kubernetes 资源配额(ResourceQuota)详解:CPU、内存、存储、对象数量限制
在多租户 Kubernetes 集群中,资源配额(ResourceQuota)是防止“吵闹邻居”效应、保障租户间公平调度的核心机制。Argo CD 在部署多租户应用时,必须确保每个 Namespace 的配额设置合理,否则应用可能因资源不足而无法调度。本章深入解析 ResourceQuota 的四种限制维度:计算资源(CPU/内存)、存储资源、对象数量,以及配额的作用域与最佳实践。
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。
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
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 的设计需要遵循以下原则:
- 按租户粒度分配:每个租户(Team/Project)对应一个 Namespace,每个 Namespace 设置独立的 ResourceQuota。
- 预留缓冲余量:配额总和应小于集群总容量,预留 10%-20% 的缓冲空间用于突发调度。
- 分层配额:同时设置计算资源配额和对象数量配额,避免单一维度成为瓶颈。
- 动态调整:通过 Argo CD 的 ApplicationSet 或 GitOps 流水线,在部署时自动注入或更新 ResourceQuota。
- 监控告警:使用
kubectl describe quota或 Prometheus 监控配额使用率,接近上限时触发告警。
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
排查步骤:
- 使用
kubectl describe quota -n <namespace>查看当前配额使用情况。 - 检查 Argo CD Application 的
spec.destination.namespace是否正确。 - 在 Argo CD 的 PreSync hook 中添加配额检查脚本,提前预警。
- 使用
argocd app diff对比当前资源与目标资源,确认资源请求量。
syncPolicy.autoSelfHeal 确保配额始终与 Git 仓库一致。这样,配额变更只需修改 Git 仓库中的 YAML 文件,Argo CD 会自动同步。