在共用 Kubernetes 集群里,资源争抢往往不是运维最先察觉的故障,而是从一次诡异的 Pod Pending 或者节点压力开始的。某个业务团队发布了一个没有声明资源请求的 Deployment,调度器可能会把它塞到任意节点,实际运行后内存持续上涨,最后触发 kubelet 驱逐。要避免这种局面,需要同时使用 ResourceQuota 和 LimitRange 两个对象:前者管住整个命名空间的资源总量,后者管住单个 Pod 或容器的资源规格。

一、ResourceQuota 与 LimitRange 的定位差异
ResourceQuota 工作在命名空间级别,它的核心语义是硬性总量控制。一个命名空间下所有 Pod、PVC、Service 等对象合计申请的 CPU 和内存不能超过预先设定的上限。这里要注意,ResourceQuota 统计的是对象的请求值(requests)和限制值(limits),而不是节点上实际消耗的瞬时值。例如一个 Pod 声明了 requests.cpu: 500m,无论它当前是否真的用了 500m CPU,这 500m 都会从配额中扣减。这样设计的原因是调度决策基于 requests,而配额需要在准入阶段就拦住超量创建。
下面是一个典型的 ResourceQuota 配置,它同时限制了计算资源、存储资源以及对象数量:
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-a-quota
namespace: team-a
spec:
hard:
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
persistentvolumeclaims: "5"
requests.storage: 100Gi
pods: "20"
上面的配置表示命名空间 team-a 内所有 Pod 的 CPU 请求总和不能超过 4 核,CPU 限制总和不能超过 8 核;内存请求和限制分别不能超过 8Gi 和 16Gi。同时 PVC 数量最多 5 个,所有 PVC 的存储请求总和不超过 100Gi,Pod 数量最多 20 个。对象数量配额经常被忽略,但它对控制 Service、ConfigMap、Secret 等资源同样有效。
LimitRange 则是作用于单个 Pod 或容器的策略。它的作用是给容器设置默认请求和默认限制,并且限制容器可声明的最小值和最大值。比如团队里有开发者从来不在 YAML 里写 resources 字段,如果没有 LimitRange,这些 Pod 就完全没有资源约束;一旦有了 LimitRange,创建时准入控制器会自动补上默认值。下面是一个适合开发命名空间的 LimitRange:
apiVersion: v1
kind: LimitRange
metadata:
name: team-a-limits
namespace: team-a
spec:
limits:
- max:
cpu: "2"
memory: 4Gi
min:
cpu: "100m"
memory: 128Mi
default:
cpu: "500m"
memory: 512Mi
defaultRequest:
cpu: "200m"
memory: 256Mi
type: Container
这里 default 对应容器未指定 limits 时自动写入的值,defaultRequest 对应容器未指定 requests 时自动写入的值。max 和 min 则划定容器可声明的合法范围,超出这个范围的 Pod 会被直接拒绝。需要特别说明,如果容器只写了 limits 没写 requests,Kubernetes 会在没有 defaultRequest 的情况下把 requests 自动设置为与 limits 相等;如果两者都没写,则使用 LimitRange 的 defaultRequest 和 default。
二、实战配置:从零给命名空间加上配额
假设现在有一个名为 team-a 的命名空间,还未配置任何管控。第一步先创建命名空间,然后分别应用 ResourceQuota 和 LimitRange 两个清单。可以手动执行 kubectl create namespace team-a,再用 kubectl apply -f quota.yaml -f limitrange.yaml 完成部署。部署完成后,可以通过 kubectl describe resourcequota team-a-quota -n team-a 查看当前使用量和总量。
kubectl create namespace team-a kubectl apply -f resourcequota.yaml -f limitrange.yaml kubectl describe resourcequota team-a-quota -n team-a
输出中会列出每个资源项的 Used 和 Hard,例如 requests.cpu: 500m/4 表示已经使用了 500m CPU 请求,配额上限为 4 核。这个对比能帮助团队及时发现哪个资源维度快触顶。如果命名空间里已经存在没有声明资源的 Pod,应用 LimitRange 不会追溯修改它们,只会在后续创建或更新时生效。因此老 Pod 需要滚动更新或手动补上 resources 字段,才能纳入统一的默认值体系。
在给团队配置配额时,最实用的组合是 ResourceQuota 设置一个相对宽松的总量,LimitRange 设置一个合理的默认值。总量太紧会阻碍正常发布,默认值太大又失去保护意义。通常可以先观察现有工作负载一周左右的峰值,再乘以 1.2 到 1.5 的冗余系数作为初始配额。例如一个团队日常使用 CPU 请求合计约 2 核,可以先给 3 核到 4 核的请求配额,同时把单个容器的默认 CPU 请求设置在 200m 到 500m 之间。
三、配额判断顺序与常见故障排查
ResourceQuota 的判断发生在 API 服务器的准入阶段,而不是调度阶段。也就是说,只要 Pod 声明的 requests 或 limits 累加后超过命名空间剩余配额,创建请求就会被拒绝,Pod 根本不会进入调度队列。报错信息通常类似 exceeded quota: team-a-quota, requested: requests.cpu=1, used: requests.cpu=3800m, limited: requests.cpu=4。这个信息明确指出是哪个资源维度超了、已用多少、上限多少,是排查配额问题的第一入口。
一个常见的误区是只检查节点资源,却忽略了对象数量配额。比如配置里限制 Pod 数量为 20,团队已经有 18 个 Pod,此时再创建一个 StatefulSet 包含 3 个副本,就会触发 pods: exceeded quota。另一个容易踩坑的地方是 LimitRange 的默认值覆盖。假设命名空间已经存在 LimitRange,开发者在 Deployment 里写死了 resources: {},准入控制器会用默认值填充,但如果在 template 里没有写 containers 的 resources 字段,而同时 ResourceQuota 已经设定了 requests 配额,创建仍然会成功,因为默认值补上了请求。如果团队不想让默认值生效,需要显式写一个低于默认值的 requests,但这时又可能触发 LimitRange 的 min 限制。
多容器 Pod 的场景也需要注意:LimitRange 的 max 和 min 是针对单个容器独立校验的,而 ResourceQuota 统计的是 Pod 内所有容器声明值的总和。例如一个 Pod 包含两个容器,每个容器 requests.cpu 为 500m,那么对 ResourceQuota 来说这个 Pod 消耗了 1 核 CPU 请求。如果命名空间剩余配额只有 800m,这个 Pod 就会被拒绝,尽管每个容器都符合 LimitRange 的范围。排查时可以先用 kubectl get events -n team-a --sort-by=.lastTimestamp 查看准入拒绝事件,再结合 kubectl describe limitrange 看默认值和上下限。
四、生产环境配额策略的几条实用建议
生产环境中不建议只设置 ResourceQuota 而不设置 LimitRange,因为这样会强制所有 Pod 都必须手动声明资源。开发团队一旦忘记写 resources 字段,Pod 会直接被拒绝,体验很差。反过来,只设置 LimitRange 不设置 ResourceQuota,每个 Pod 虽然有了默认值,但总量仍然可能被大量副本撑爆。两者配合才能形成完整闭环:LimitRange 保证单个对象有合理规格,ResourceQuota 保证整个命名空间有总量上限。
配额的数值不是一成不变的,需要结合监控系统持续调整。可以关注两个指标:一是实际资源使用率与请求值的比例,如果实际使用长期低于请求值,说明配额被过度预留,可以适当调低请求配额;二是配额触达频率,如果团队经常因为配额不足发布失败,说明需要扩容集群或者优化应用规格。还可以为不同环境设置不同策略,例如测试环境采用较紧的配额和较小的默认值,生产环境给予更多余量,但要严格限制单容器的最大内存和 CPU。
最后,ResourceQuota 和 LimitRange 只能解决资源规划和准入控制问题,不能替代运行时保护。如果某个 Pod 在运行中内存突然上涨,超出 limits,kubelet 会按照内核 OOM 打分驱逐进程,但不会阻止它被调度。因此还需要结合 requests 与 limits 的合理设定、Pod 优先级以及节点资源预留来构建完整的资源管理体系。把这些机制用好后,集群里的资源竞争会从无序争抢变成可预期、可追踪、可治理的状态。
KubernetesResourceQuotaLimitRange修改时间:2026-09-28 15:12:36