登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  业界新闻

Kubernetes 资源配额怎样避免命名空间之间互相争抢

来源:17golang原创

时间:2026-11-14 05:06:31 471浏览 收藏

我在共享 Kubernetes 集群里最容易遇到的争抢,不是某个 Pod 突然变慢,而是一个命名空间不断提高 requests,最后让别的团队的新 Pod 无法进入。ResourceQuota 的正确用法是先按 namespace 划出总量边界,再用 LimitRange 约束单个 Pod 或容器的最小、最大值和默认值;这样“团队总预算”和“单个工作负载上限”才不会混在一起。

给每个业务 namespace 配置独立的 ResourceQuota,并让每个容器明确 requests/limits;如果担心遗漏,再用 LimitRange 注入默认值。需要注意,ResourceQuota 统计的是 namespace 的聚合消耗,不会把 Pod 固定到某些节点,也不会自动把集群新增容量分给某个 namespace。

官方地址:https://kubernetes.io/docs/concepts/policy/resource-quotas/

先把命名空间边界和配额职责分清

ResourceQuota 只在它所在的 namespace 内生效。它可以统计非终止 Pod 的 CPU、内存请求和限制,也可以统计 Pod、PVC、Service、Secret 等对象数量。不同 namespace 可以各自有一套上限,但这些上限是绝对值:把集群扩容,并不会自动提高现有 quota。

治理问题主要对象应该由谁负责
一个团队总共能申请多少 CPU、内存ResourceQuotanamespace 聚合预算
一个 Pod 或容器不能超过多少LimitRange单对象上下限与默认值
Pod 最终落在哪台节点调度器、节点池、亲和性放置和容量规划

因此,quota 不是“给 namespace 预留一组节点”。多个 namespace 的 Pod 仍可能落在同一个节点上,最终是否调度成功还取决于节点可用资源、调度约束和 Pod 的 requests。配额要解决的是一个 namespace 能向集群申请多少,以及 API Server 是否应该拒绝继续增加。

Kubernetes 命名空间、ResourceQuota、LimitRange 与节点调度边界的结构说明图
图1:结构说明图,展示 namespace 聚合预算、单 Pod 约束和节点调度的职责边界;这是静态说明图,不是运行截图。

初始化 ResourceQuota 的总量边界

我通常先为每个业务 namespace 建立一份小而清楚的 quota,先限制 requests 总量,再限制 limits 总量和 Pod 数。下面的示例把“可调度承诺”“最大限制”和“对象数量”放在同一个 namespace 的治理文件里:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-a-budget
  namespace: team-a
spec:
  hard:
    # requests 影响调度承诺,控制团队最多申请的 CPU 和内存
    requests.cpu: "8"
    requests.memory: 16Gi
    # limits 约束运行时上限,避免限制总和无限增大
    limits.cpu: "12"
    limits.memory: 24Gi
    # 限制活跃 Pod 数,防止错误的批量创建拖垮集群对象
    pods: "40"

这里的 requests.cpu 与 requests.memory 是 namespace 内所有相关 Pod 的请求总和,limits.* 则是限制总和。只要新的创建或更新会让 used 超过 hard,API 请求就会被拒绝。资源名可以使用简写的 cpu、memory,但团队规范最好统一写出 requests.*,减少读配置时的歧义。

用 requests、limits 和 LimitRange 处理单 Pod

只配总量还不够:如果 namespace 有 16Gi 内存预算,一个 Pod 也可能一次申请接近全部预算。LimitRange 适合给单个容器规定最小、最大和默认的 requests/limits;它和 ResourceQuota 是互补关系,不要拿其中一个替代另一个。

apiVersion: v1
kind: LimitRange
metadata:
  name: team-a-defaults
  namespace: team-a
spec:
  limits:
  - type: Container
    # 未填写资源字段的容器使用默认值,避免 quota 因缺少字段而拒绝
    default:
      cpu: "500m"
      memory: 512Mi
    defaultRequest:
      cpu: "100m"
      memory: 128Mi
    # 单容器不能申请超过这个上限,也不能低于最小请求
    max:
      cpu: "2"
      memory: 4Gi
    min:
      cpu: "50m"
      memory: 64Mi

这个组合有一个常被忽视的顺序:Pod 进入 API Server 时,LimitRange 可以为缺省字段提供默认值,然后 ResourceQuota 再按 namespace 汇总。若在启用 CPU 或内存 quota 的 namespace 中完全不写请求或限制,Pod 可能因为缺少对应资源字段而无法通过准入;所以默认值应和团队的实际工作负载一起评估,不能随便填一个极小数字。

Kubernetes Pod 资源字段经过 LimitRange 后汇总到 ResourceQuota 的关系说明图
图2:关系说明图,展示容器资源字段、LimitRange 默认与上下限、ResourceQuota hard/used 的静态关系;这是解释性示意,不是运行结果。

运行检查并观察拒绝原因

配置完后,我会先看 quota 的 hard 和 used,再检查工作负载是否带有预期的资源字段。下面的命令只负责读取状态,不依赖某个发行版的额外插件:

# 查看 team-a 的配额上限与当前消耗
kubectl get resourcequota -n team-a -o yaml

# 用表格快速观察 requests、limits 和 Pod 数的剩余空间
kubectl describe resourcequota team-a-budget -n team-a

# 查看 Pod 最终得到的 requests/limits,确认默认值是否符合预期
kubectl get pods -n team-a -o custom-columns='NAME:.metadata.name,CPU_REQ:.spec.containers[*].resources.requests.cpu,MEM_REQ:.spec.containers[*].resources.requests.memory,CPU_LIMIT:.spec.containers[*].resources.limits.cpu,MEM_LIMIT:.spec.containers[*].resources.limits.memory'

如果创建失败,重点看返回中的 exceeded quota、requested、used 和 limited。例如当前内存请求是 15Gi,quota 上限是 16Gi,新 Pod 再申请 2Gi 就会被拒绝;这不是“节点刚好没空位”的同一个问题,而是 namespace 的 API 准入预算先被触发。

排查时不要只看 Deployment 副本数。一个 Deployment 可能通过 ReplicaSet 创建多个 Pod,Job 或 CronJob 也可能持续产生对象;应同时观察 quota 的对象数量项和工作负载控制器的副本策略。

扩展到对象数量和分级治理

当团队已经有稳定的 CPU、内存预算后,再补对象数量通常比继续扩大资源配额更有效。例如对 PVC、LoadBalancer Service 或 Secret 设置数量限制,可以防止错误脚本不断创建对象,耗尽控制面存储或云资源配额:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: team-a-object-budget
  namespace: team-a
spec:
  hard:
    # 保护持久化存储申请和高成本的外部负载均衡入口
    persistentvolumeclaims: "12"
    services.loadbalancers: "2"
    # 限制控制面对象数量,降低批量错误的影响面
    count/secrets: "80"
    count/jobs.batch: "100"

如果集群需要按 PriorityClass 给高、低优先级工作负载分配不同预算,可以使用带 scopeSelector 的 ResourceQuota。它仍然是 namespace 内的聚合统计,不会把低优先级 Pod 自动赶到别的节点,也不会替代节点池或抢占策略的整体设计。

最后要记住一个边界:配额变化不会回溯修改已经创建的资源。扩大 quota 不会自动改变旧 Pod 的 requests,缩小 quota 也不等于立即驱逐已经运行的 Pod;它主要影响后续创建或更新是否能通过检查。

清理与总结

实验 namespace 不再使用时,先确认里面没有要保留的对象,再删除测试资源。生产环境不要直接照抄示例数字,而应从历史用量、峰值副本数、节点容量和故障余量倒推 hard 值。

# 仅删除本教程创建的测试 namespace;生产环境请先确认清理范围
kubectl delete namespace team-a

我的落地顺序是:先用 ResourceQuota 定义 namespace 的总预算,再用 LimitRange 收紧单容器的边界,随后用 hard/used 和 Pod 实际字段做复查。这样即使多个团队共用节点,也能把“谁申请了多少”和“单个 Pod 能申请多少”拆成可解释的两层规则。

常见问题

ResourceQuota 能把团队固定到独立节点吗?

不能。它限制 namespace 的聚合资源和对象数量,不负责节点放置;节点池、污点容忍、亲和性和调度策略才是节点隔离工具。

只配置 requests.cpu,为什么 Pod 仍可能创建失败?

需要结合 namespace 里的 quota 项和 Pod 字段看。如果 quota 同时要求 CPU 或内存的请求/限制,而容器没有对应字段,准入可能拒绝;LimitRange 可以提供默认值,但默认值本身也要满足最小值、最大值和团队预算。

新增节点后要不要自动提高每个 namespace 的 quota?

不应该自动提高。quota 是治理预算而不是节点容量镜像;应根据团队实际需求、共享余量和调度策略重新分配,避免扩容后所有 namespace 同时放大申请。

一句话总结:用 ResourceQuota 限制 namespace 总量,用 LimitRange 限制单对象,用 requests 表达调度承诺,再用 hard/used 观察真实消耗;这比给所有 namespace 一个过大的上限更能减少互相争抢。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>