上一篇【第30篇】oS——K8s的“三六九等“资源优先级
下一篇【第32篇】ResourceQuota——多团队共享集群的"公平秤"
摘要
上两篇咱们把requests/limits和QoS掰碎讲了,你学会了"怎么给Pod配资源"和"资源紧张时谁先死"。但问题来了:在一个多人共享的集群里,你怎么保证每个人都会乖乖给Pod配资源?有的同事抄了个网上的YAML就deploy,什么resources都没写——结果搞出个BestEffort Pod,资源紧张时第一个被杀;有的同事写requests: cpu: 1m, limits: cpu: 100Gi——比例离谱到姥姥家了。
LimitRange就是来管这茬的。它作用在Namespace级别,像一个"管理员"一样盯着每个Pod创建——你忘了写requests?我给你补个默认值。你requests设太小?最小值不允许。你limits/requests比例太大?直接拒绝创建。这篇文章从LimitRange的四种限制项(Min/Max/Default/DefaultRequest)讲起,再到MaxLimitRequestRatio的精妙设计,最后实战给两个团队分别画"圈"——开发环境宽松点,生产环境严格点。
一、LimitRange解决什么问题——“管不住的手”
1.1 没有LimitRange的世界有多乱
【没有LimitRange时——"法外之地"】 Namespace: production(号称"生产环境") ┌─────────────────────────────────────────────────────────┐ │ │ │ 张三创建的Pod: 李四创建的Pod: │ │ ┌───────────────────┐ ┌───────────────────┐ │ │ │ resources: {} │ │ resources: │ │ │ │ → BestEffort │ │ requests: │ │ │ │ → 没任何保护 │ │ cpu: 1m │ │ │ │ → OOM时第一个死 │ │ memory: 1Mi │ │ │ └───────────────────┘ │ limits: │ │ │ │ cpu: 100000m │ │ │ 王五创建的Pod: │ memory: 1Ti │ │ │ ┌───────────────────┐ │ → 比例失衡 │ │ │ │ resources: │ └───────────────────┘ │ │ │ requests: │ │ │ │ cpu: 100m │ │ │ │ limits: │ 结果: │ │ │ cpu: 10000m │ • BestEffort Pod随时被杀 │ │ │ → limits大爆炸 │ • 1m request占位但不干活 │ │ │ → 可能抢占资源 │ • 10000m limit可能压死其他Pod │ │ └───────────────────┘ │ └─────────────────────────────────────────────────────────┘ Scheduler看了直摇头:"你们这个Namespace怎么啥配置都有啊?"1.2 LimitRange怎么管——“四条规矩”
【LimitRange的四种限制——"给每个Pod上箍"】 ┌─────────────────────────────────────────────────────────┐ │ LimitRange 四条规矩 │ │ │ │ 1. Min(最小值) │ │ ┌─────────────────────────────────────────────┐ │ │ │ "requests.cpu 至少 100m,别想拿1m糊弄我" │ │ │ │ "limits.memory 至少 128Mi,太低没有意义" │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ 2. Max(最大值) │ │ ┌─────────────────────────────────────────────┐ │ │ │ "limits.cpu 最多 4000m,别写100000m扛不住" │ │ │ │ "requests.memory 最多 16Gi,控制单个Pod" │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ 3. Default(默认值——没设limits时的自动填充) │ │ ┌─────────────────────────────────────────────┐ │ │ │ "忘了写limits.cpu?帮你填500m" │ │ │ │ "忘了写limits.memory?帮你填512Mi" │ │ │ └─────────────────────────────────────────────┘ │ │ │ │ 4. DefaultRequest(默认值——没设requests时的自动填充) │ │ ┌─────────────────────────────────────────────┐ │ │ │ "忘了写requests.cpu?帮你填200m" │ │ │ │ "忘了写requests.memory?帮你填256Mi" │ │ │ └─────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘二、LimitRange的四种限制详解
2.1 完整配置示例——“四条规矩一次写清楚”
apiVersion:v1kind:LimitRangemetadata:name:production-limitsnamespace:production# ← 作用域:只管这个Namespacespec:limits:# ==========================================# 第1条:限制Container级别的资源# ==========================================-type:Container# Min——资源不能低于这个值min:cpu:"100m"# 至少 0.1 核memory:"128Mi"# 至少 128Mi 内存# Max——资源不能超过这个值max:cpu:"4000m"# 最多 4 核memory:"16Gi"# 最多 16Gi 内存# Default——没写limits时自动补这个default:cpu:"500m"# 默认最多用 0.5 核memory:"512Mi"# 默认最多用 512Mi# DefaultRequest——没写requests时自动补这个defaultRequest:cpu:"200m"# 默认保证 0.2 核memory:"256Mi"# 默认保证 256Mi# MaxLimitRequestRatio——limits最多是requests的几倍maxLimitRequestRatio:cpu:"4"# CPU: limits/requests ≤ 4memory:"2"# 内存: limits/requests ≤ 2# 合法:requests=500m, limits=2000m → ratio=4 ✓# 非法:requests=100m, limits=2000m → ratio=20 ✗(被拒绝!)# ==========================================# 第2条:限制Pod级别的资源(所有容器总和)# ==========================================-type:Podmax:cpu:"8000m"# 整个Pod最多8核(所有容器总和)memory:"32Gi"# 整个Pod最多32Gi# ==========================================# 第3条:限制PVC存储大小# ==========================================-type:PersistentVolumeClaimmin:storage:"1Gi"# PVC最少申请1Gimax:storage:"100Gi"# PVC最多申请100Gi2.2 各限制项的执行效果
# 场景1:Pod忘了写resources——自动补默认值kubectl apply-f-<<EOF apiVersion: v1 kind: Pod metadata: name: no-resources spec: containers: - name: nginx image: nginx # 什么resources都没写! EOF# 查看效果——LimitRange自动填充了kubectl get pod no-resources-oyaml|grep-A10resources# resources:# limits:# cpu: 500m ← 自动补的 default# memory: 512Mi ← 自动补的 default# requests:# cpu: 200m ← 自动补的 defaultRequest# memory: 256Mi ← 自动补的 defaultRequest# 场景2:requests低于min——拒绝创建kubectl apply-f-<<EOF apiVersion: v1 kind: Pod metadata: name: too-small spec: containers: - name: nginx image: nginx resources: requests: cpu: "10m" # ← 低于 min 的 100m! memory: "64Mi" # ← 低于 min 的 128Mi! EOF# 结果:Pod创建失败# Error: Pod "too-small" is invalid:# spec.containers[0].resources.requests[cpu]:# Invalid value: "10m": must be greater than or equal to cpu limit# 场景3:limits/requests比例超限——拒绝创建kubectl apply-f-<<EOF apiVersion: v1 kind: Pod metadata: name: ratio-violation spec: containers: - name: nginx image: nginx resources: requests: cpu: "100m" limits: cpu: "10000m" # ← 100倍!MaxLimitRequestRatio=4 EOF# Error: ratio violation: cpu limit/request ratio of 100 exceeds max of 4要点:Default和DefaultRequest只在"用户没写那个字段"时才生效。如果用户写了requests但没写limits——limits会用default补,requests保持用户写的值。如果用户写了limits但没写requests——requests会用defaultRequest补(如果defaultRequest≤limits的话)。
2.3 验证LimitRange的生效
# 查看Namespace下的LimitRangekubectl get limitrange-nproduction# NAME CREATED AT# production-limits 2026-07-28T10:00:00Z# 查看详情kubectl describe limitrange production-limits-nproduction# Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio# ---- -------- --- --- --------------- ------------- -----------------------# Container cpu 100m 4000m 200m 500m 4# Container memory 128Mi 16Gi 256Mi 512Mi 2# 查看Namespace下的所有LimitRange注解(Pod创建后会带上这些信息)kubectl get pod my-pod-nproduction-oyaml|grep-A5annotations# annotations:# kubernetes.io/limit-ranger: 'LimitRanger plugin set: cpu request for container app'2.4 对比表:四种限制项的语义
| 限制项 | 作用对象 | 用户没写时 | 用户写了但不符合时 | 典型用途 |
|---|---|---|---|---|
| min | requests/limits的最小值 | 不作用 | 拒绝创建 | 防止"占坑"小Pod——requests=1m骗过Scheduler |
| max | requests/limits的最大值 | 不作用 | 拒绝创建 | 防止单个Pod吃掉所有资源 |
| default | limits的默认值 | 自动填充 | 不作用(用户写了就用用户的) | 防止BestEffort Pod——至少有个limits |
| defaultRequest | requests的默认值 | 自动填充 | 不作用 | 防止漏设requests导致的调度偏差 |
| maxLimitRequestRatio | limits/requests的比例上限 | 不作用 | 拒绝创建 | 防止极度不平衡配置 |
三、MaxLimitRequestRatio——“别想钻空子”
3.1 为什么要限制比例
【没有MaxLimitRequestRatio时——"聪明人"怎么钻空子】 场景:集群管理者说"所有Pod必须设requests和limits" "聪明人"的做法: ┌─────────────────────────────────────────────────┐ │ resources: │ │ requests: │ │ cpu: "1m" # ← 拿1m糊弄Scheduler │ │ memory: "1Mi" │ │ limits: │ │ cpu: "8000m" # ← 实际可以用8核! │ │ memory: "32Gi" │ │ │ │ 效果:Scheduler看Node剩了3500m, │ │ 1m vs 3500m → 调上来! │ │ 实际运行时用了8000m → 其他Pod全throttle │ └─────────────────────────────────────────────────┘ 有了MaxLimitRequestRatio之后: ┌─────────────────────────────────────────────────┐ │ maxLimitRequestRatio: │ │ cpu: "4" # limits最多是requests的4倍 │ │ memory: "2" # 内存最多2倍 │ │ │ │ requests: 1m, limits: 8000m → ratio: 8000 ✗ │ │ requests: 2000m, limits: 8000m → ratio: 4 ✓ │ └─────────────────────────────────────────────────┘3.2 ratio的合理配置
# 不同环境的推荐比率---# 生产环境——严格apiVersion:v1kind:LimitRangemetadata:name:strict-limitsnamespace:productionspec:limits:-type:ContainermaxLimitRequestRatio:cpu:"3"# ← 生产环境保守:最多3倍memory:"1.5"# ← 内存更严格:最多1.5倍# 意味着:如果你要配request为1Gi内存,limits最多1.5Gi# 原因:生产环境内存超售不能太大,否则OOM风险高---# 开发环境——宽松apiVersion:v1kind:LimitRangemetadata:name:relaxed-limitsnamespace:developmentspec:limits:-type:ContainermaxLimitRequestRatio:cpu:"10"# ← 开发环境:允许10倍memory:"4"# ← 内存:允许4倍# 原因:开发环境burst需求大,资源利用率不用太精确四、实战——多租户资源限制方案
4.1 方案设计——“给每个团队画不一样的圈”
【多租户Namespace资源规划】 集群总资源:20核CPU, 64Gi内存(4台4C/16Gi Node) ┌─────────────────────────────────────────────────────────┐ │ │ │ ┌───────────────────────┐ ┌───────────────────────┐ │ │ │ Namespace: team-a │ │ Namespace: team-b │ │ │ │ (核心业务团队) │ │ (数据分析团队) │ │ │ │ │ │ │ │ │ │ LimitRange: │ │ LimitRange: │ │ │ │ • min: 100m/128Mi │ │ • min: 50m/64Mi │ │ │ │ • max: 4C/16Gi │ │ • max: 4C/32Gi │ │ │ │ • default: 500m/512Mi │ │ • default: 1C/2Gi │ │ │ │ • defaultReq:200m/256Mi│ │ • defaultReq:500m/1Gi │ │ │ │ • ratio: 2/1.5 │ │ • ratio: 4/2 │ │ │ │ │ │ │ │ │ │ 风格:小而精致 │ │ 风格:大而粗放 │ │ │ │ 服务多但每个不占太多 │ │ 任务少但每个要很多资源 │ │ │ └───────────────────────┘ └───────────────────────┘ │ │ │ │ ┌───────────────────────┐ ┌───────────────────────┐ │ │ │ Namespace: dev │ │ Namespace: staging │ │ │ │ (开发测试) │ │ (预发布) │ │ │ │ │ │ │ │ │ │ LimitRange: │ │ LimitRange: │ │ │ │ • min: 10m/32Mi │ │ • min: 50m/64Mi │ │ │ │ • max: 2C/4Gi │ │ • max: 4C/16Gi │ │ │ │ • default: 200m/256Mi │ │ • default: 500m/512Mi │ │ │ │ • defaultReq:100m/128Mi│ │ • defaultReq:200m/256Mi│ │ │ │ • ratio: 10/4 │ │ • ratio: 4/2 │ │ │ │ │ │ │ │ │ │ 风格:尽量省资源 │ │ 风格:接近生产 │ │ │ └───────────────────────┘ └───────────────────────┘ │ └─────────────────────────────────────────────────────────┘4.2 完整配置代码
# ==========================================# team-a 的 LimitRange(核心业务团队)# ==========================================apiVersion:v1kind:LimitRangemetadata:name:team-a-limitsnamespace:team-aspec:limits:-type:Containermin:cpu:"100m"memory:"128Mi"max:cpu:"4000m"# 最多4核——防止单个Pod吃太多memory:"16Gi"default:cpu:"500m"memory:"512Mi"defaultRequest:cpu:"200m"memory:"256Mi"maxLimitRequestRatio:cpu:"2"# CPU严格——防止超售太多memory:"1.5"# 内存更严格——OOM很可怕-type:Podmax:cpu:"8000m"# 整个Pod(含Sidecar)最多8核memory:"32Gi"---# ==========================================# team-b 的 LimitRange(数据分析团队)# ==========================================apiVersion:v1kind:LimitRangemetadata:name:team-b-limitsnamespace:team-bspec:limits:-type:Containermin:cpu:"50m"# 允许更小的Podmemory:"64Mi"max:cpu:"4000m"memory:"32Gi"# 数据任务需要更多内存default:cpu:"1000m"# 默认给大点——数据任务CPU需求高memory:"2Gi"# 默认给2Gi——数据任务内存需求也高defaultRequest:cpu:"500m"memory:"1Gi"maxLimitRequestRatio:cpu:"4"# 宽松点——数据任务需要burstmemory:"2"---# ==========================================# dev 的 LimitRange(开发环境,尽量省资源)# ==========================================apiVersion:v1kind:LimitRangemetadata:name:dev-limitsnamespace:devspec:limits:-type:Containermin:cpu:"10m"# 开发环境可以用很小memory:"32Mi"max:cpu:"2000m"# 开发环境限制上限memory:"4Gi"default:cpu:"200m"memory:"256Mi"defaultRequest:cpu:"100m"memory:"128Mi"maxLimitRequestRatio:cpu:"10"# 开发环境放开ratio——burst随便用memory:"4"# 应用配置kubectl apply-fteam-a-limits.yaml kubectl apply-fteam-b-limits.yaml kubectl apply-fdev-limits.yaml# 验证各Namespace的LimitRangekubectl get limitrange --all-namespaces# NAMESPACE NAME CREATED AT# team-a team-a-limits 2026-07-28T10:00:00Z# team-b team-b-limits 2026-07-28T10:00:00Z# dev dev-limits 2026-07-28T10:00:00Z# 测试:在team-a里创建违反LimitRange的Podkubectl apply-nteam-a-f-<<EOF apiVersion: v1 kind: Pod metadata: name: bad-pod spec: containers: - name: nginx image: nginx resources: requests: cpu: "5m" # ← 低于team-a的min(100m) EOF# Error from server (Forbidden): error when creating "STDIN":# pods "bad-pod" is forbidden: minimum cpu usage per Container is 100m,# but request is 5m要点:LimitRange的Default和DefaultRequest有个重要特性——它们只在API Server接受创建请求时生效,修改LimitRange不对已有Pod产生任何影响。如果你想让已有Pod也按新规矩来,得重建它们(删除让Deployment重建)。
五、LimitRange常用操作速查
# 查看Namespace下的所有LimitRangekubectl get limitrange-nproduction# 查看详细配置kubectl describe limitrange production-limits-nproduction# 导出为YAML(备份/迁移用)kubectl get limitrange production-limits-nproduction-oyaml>backup.yaml# 修改LimitRangekubectl edit limitrange production-limits-nproduction# 删除LimitRangekubectl delete limitrange production-limits-nproduction# 查看Pod是否被LimitRange修改过kubectl describe pod my-pod-nproduction|grep-i"limit"# 或者看 annotations:kubectl get pod my-pod-nproduction-ojsonpath='{.metadata.annotations}'# {"kubernetes.io/limit-ranger":"LimitRanger plugin set: cpu, memory..."}# 测试:干跑一个Pod看看会不会被LimitRange拒绝kubectl apply-fmy-pod.yaml --dry-run=server-nproduction# 如果配置不合规,这里就会报错,不会实际创建本篇小结
LimitRange是Namespace级别的"资源管理员",自动纠偏、强制约束:
- 四种限制:Min(下限)、Max(上限)、Default(自动补limits)、DefaultRequest(自动补requests)——每种管不同的事
- MaxLimitRequestRatio是防止"钻空子"的利器——防止有人用极小request+极大limit绕过调度
- Default和DefaultRequest的妙用:只要用户忘了写resources,LimitRange就自动补——确保每个Pod至少是Burstable
- 不同环境不同策略:生产严格(ratio≤2-3)、开发宽松(ratio可达10),按团队需求定制
- 只管新建Pod——修改LimitRange不影响已有Pod,要生效就得重建
LimitRange管的是"单个Pod怎么配资源",但集群管理者还需要"整个Namespace能用多少资源"——接下来咱们聊ResourceQuota,多团队共享集群的"公平秤"。
上一篇【第30篇】oS——K8s的“三六九等“资源优先级
下一篇【第32篇】ResourceQuota——多团队共享集群的"公平秤"