核心概念:理解 ResourceQuota、LimitRange 与 Namespace 的关系

说实话,我刚接触 Kubernetes 资源管理那会儿,也把这三个东西搞混过。Namespace 我懂,就是个隔离空间嘛。但 ResourceQuota 和 LimitRange 到底有啥区别?为啥要同时用?

后来在线上踩了几次坑,才真正明白——这三者其实是「空间 → 边界 → 默认值」的层层递进关系。Namespace 划地盘,ResourceQuota 定上限,LimitRange 设默认。缺一个,你的集群都可能出乱子。

Namespace:你的资源隔离单元

Namespace 说白了就是 Kubernetes 里的虚拟集群。同一个集群里,不同团队、不同环境(dev/staging/prod)各占一个 Namespace,互不干扰。

我个人习惯把 Namespace 比作「公寓楼里的独立房间」。每个房间有自己的门牌号,里面的人用自己房间的资源,不能随便跑到隔壁房间拿东西。

关键认知: ResourceQuota 和 LimitRange 都是作用于特定 Namespace 的。没有 Namespace,这两个策略就无处安放。

ResourceQuota:给 Namespace 画红线

ResourceQuota 解决的是「这个 Namespace 最多能用多少」的问题。它像一个总量阀门,防止某个团队把集群资源吃光。

我记得有一次,测试环境的某个团队部署了一个带资源泄漏的 CronJob,CPU 请求一路飙升。要不是提前配了 ResourceQuota,整个集群可能都被拖垮。

一个典型的 ResourceQuota 配置长这样:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: dev-quota
  namespace: dev
spec:
  hard:
    requests.cpu: "4"
    requests.memory: "8Gi"
    limits.cpu: "8"
    limits.memory: "16Gi"
    persistentvolumeclaims: "10"
    pods: "20"
    count/deployments.apps: "5"

这里我设了几个关键指标:

  • requests.cpu / memory:所有 Pod 请求的总和上限
  • limits.cpu / memory:所有 Pod 限制的总和上限
  • pods / deployments:对象数量上限
我曾经踩过的坑: 只配了 limits 没配 requests。结果某个 Pod 的 request 设得极低,limit 设得极高,调度器以为它很省资源,实际跑起来却疯狂占内存。后来我学乖了——requests 和 limits 必须成对配置。

LimitRange:给 Pod 设默认值和边界

ResourceQuota 管的是总量,LimitRange 管的是个体。它解决两个问题:

  1. 用户没设资源限制时,自动给个默认值
  2. 防止用户设出离谱的请求/限制值

你想想看,如果团队里有人忘了给 Pod 设 resources,会发生什么?Pod 会以零请求运行,调度器觉得它不占资源,结果节点上挤满了这种「隐形胖子」。LimitRange 就是用来堵这个漏洞的。

apiVersion: v1
kind: LimitRange
metadata:
  name: dev-limits
  namespace: dev
spec:
  limits:
  - max:
      cpu: "2"
      memory: "4Gi"
    min:
      cpu: "100m"
      memory: "128Mi"
    default:
      cpu: "500m"
      memory: "512Mi"
    defaultRequest:
      cpu: "200m"
      memory: "256Mi"
    type: Container

这里的关键字段:

  • max / min:单个容器能设的上限和下限
  • default:用户没设 limits 时自动注入的值
  • defaultRequest:用户没设 requests 时自动注入的值
一个小技巧: default 和 defaultRequest 可以不一样。我通常把 defaultRequest 设得比 default 低一些,这样 Pod 在调度时显得「瘦」,实际运行时又有足够的 limit 兜底。

三者的关系:一张图说清楚

嗯,这里我用一张 SVG 图来展示它们之间的协作逻辑:

Namespace、ResourceQuota、LimitRange 协作关系 Namespace: dev ResourceQuota 总量上限 CPU: 4/8 Memory: 8Gi/16Gi Pods: 20 LimitRange 个体边界 + 默认值 min: 100m/128Mi max: 2/4Gi default: 500m/512Mi Pod A request: 200m/256Mi Pod B request: 500m/512Mi Pod C request: 100m/128Mi ResourceQuota 限制所有 Pod 的总和,LimitRange 约束每个 Pod 的上下限和默认值

三者配合的实战场景

光说概念太干,我拿一个真实场景来串一下。假设你有一个 dev 命名空间,团队有 5 个人,每人部署 2-3 个微服务:

组件 作用 配置示例
Namespace 划定隔离边界 kubectl create ns dev
ResourceQuota 防止总量超支 CPU 请求 ≤ 4 核,内存 ≤ 8Gi
LimitRange 防止单个 Pod 异常 单容器 ≤ 2 核 / 4Gi,默认 500m / 512Mi

有了这三层防护,即使有人手滑写了个 resources: { limits: { cpu: "100", memory: "500Gi" } },LimitRange 会直接拒绝创建。即使有人忘了设 resources,LimitRange 也会自动注入默认值。即使所有 Pod 加起来超了总量,ResourceQuota 会阻止新 Pod 调度。

一句话总结: Namespace 是房间,ResourceQuota 是房间的总电表,LimitRange 是每个电器的额定功率和默认功率。三者缺一不可。

避坑指南:我踩过的三个雷

这些年我在资源配额上栽过不少跟头,挑三个最典型的说说:

  • 只配 ResourceQuota 不配 LimitRange:结果某个 Pod 没设 resources,调度成功但运行时 OOMKilled。LimitRange 的默认值能兜住这种「裸奔」Pod。
  • LimitRange 的 max 设得太小:有一次我把 max memory 设成 1Gi,结果有个需要 2Gi 的批处理任务死活起不来。排查了半天才发现是 LimitRange 在拦。
  • ResourceQuota 的 count 类型没配:只配了 CPU 和内存,没配 pods 数量上限。结果团队创建了 100 多个小 Pod,虽然 CPU 没超,但 etcd 压力暴增。
我的建议: 新建 Namespace 时,先把 ResourceQuota 和 LimitRange 的 YAML 写好,再让业务团队往里部署。这叫「先立规矩,再放人进来」。

好了,这三个核心概念的关系你应该清楚了。下一层我们要聊的是——这些配额到底怎么算?requests 和 limits 的差值去哪了?嗯,那是另一个有意思的话题。