K8s 资源配额与 LimitRange:防止一个团队吃掉整个集群

发布时间:2026/7/23 7:22:30

K8s 资源配额与 LimitRange:防止一个团队吃掉整个集群 K8s 资源配额与 LimitRange防止一个团队吃掉整个集群一、某个 Pod 的内存泄露把同节点上 15 个服务全拖垮了K8s 集群中最常见的生产事故之一一个团队部署了一个新服务没配置资源限制。这个服务有内存泄露24 小时后吃光节点全部 64GB 内存内核 OOM Killer 开始随机杀进程——同节点上另外 15 个 Pod 被无辜牵连。运维排查了半天才发现罪魁祸首是一个没人管的开发环境 Pod。K8s 的资源管理有三个层次但太多团队只做了第一层就不管了。第一层是requests和limitsPod 级别第二层是ResourceQuotaNamespace 级别第三层是LimitRange全局默认值。三层缺一不可。很多团队觉得资源限制会影响性能先不设这是最危险的认知。资源限制的本质不是让服务跑得慢一点而是让一个服务出问题时不要把整条船一起弄沉。它是安全机制不是性能调优工具。二、底层机制与原理剖析三层资源管理的关系第一层 Pod 级别的 requests 和 limitsrequestsPod 启动时调度器用来预留的资源。K8s 保证 Pod 至少能用到这个量limitsPod 能使用的最大资源。超出 limits 时CPU 被 throttled限制而不是 kill内存被 OOMKilled直接 kill常见错误只设 limits 不设 requests。调度器不知道 Pod 需要多少资源可能把 Pod 调度到资源不足的节点第二层 Namespace 级别 ResourceQuota限制整个 Namespace 的总资源用量。例如team-a 的 Namespace 总共只能使用 20 核 CPU、64GB 内存这个层次解决了一个团队占用过多资源挤占其他团队的问题ResourceQuota 统计的是 requests 值不是实际使用量。如果一个 Pod 的 request8Gi 但实际只用 2Giquota 里仍然扣 8Gi第三层 LimitRange全局默认值为没有设置 requests/limits 的 Pod 自动注入默认值防止我忘了设置变成把集群炸了可以设置最大/最小限制防止单个 Pod 请求不合理的大资源三、生产级代码实现# k8s/resource-quota.yaml # Team-A 的 ResourceQuota LimitRange 全套配置 --- # 1. ResourceQuota限制整个 Namespace 的资源使用 apiVersion: v1 kind: ResourceQuota metadata: name: team-a-quota namespace: team-a spec: hard: # 计算资源限制 requests.cpu: 20 # 所有 Pod 的 CPU request 总和不超过 20 核 requests.memory: 64Gi # 所有 Pod 的内存 request 总和不超过 64GB limits.cpu: 40 # 所有 Pod 的 CPU limit 总和不超过 40 核 limits.memory: 128Gi # 所有 Pod 的内存 limit 总和不超过 128GB # 存储资源限制 requests.storage: 500Gi persistentvolumeclaims: 10 # 对象数量限制防止资源泄露——无限创建 Service/ConfigMap count/services: 10 count/configmaps: 30 count/secrets: 20 count/deployments.apps: 15 --- # 2. LimitRangePod 级别的默认值和上下限 apiVersion: v1 kind: LimitRange metadata: name: team-a-limits namespace: team-a spec: limits: # 容器级别的限制 - type: Container # 默认值Pod 没有指定时使用 default: cpu: 500m memory: 512Mi defaultRequest: cpu: 200m memory: 256Mi # 硬性上下限超过范围的 Pod 无法创建 max: cpu: 4 memory: 8Gi min: cpu: 50m memory: 64Mi # 要求 requests 和 limits 的比例CPU 不限制比例 maxLimitRequestRatio: memory: 2 # limit 不能超过 request 的 2 倍 # PVC 级别的限制 - type: PersistentVolumeClaim min: storage: 1Gi max: storage: 100Gi# k8s/deployment.yaml # 正确的 Pod 资源配置示例 apiVersion: apps/v1 kind: Deployment metadata: name: agent-api namespace: team-a spec: replicas: 3 selector: matchLabels: app: agent-api template: metadata: labels: app: agent-api spec: containers: - name: agent-api image: agent-api:v1.2.3 ports: - containerPort: 8080 # 资源限制经过压测得出的合理值 # request 不是我估计它要这么多而是压测后的数据 # 这里 500m CPU 是基于 QPS200 时的 p95 CPU 用量400m 20% buffer resources: requests: cpu: 500m memory: 512Mi limits: cpu: 2 memory: 2Gi # 就绪探针确认服务是否 ready 接收流量 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 10 periodSeconds: 5# 运维检查命令 # 查看 Namespace 的配额使用情况 kubectl describe resourcequota team-a-quota -n team-a # 输出示例: # Name: team-a-quota # Namespace: team-a # Resource Used Hard # -------- ---- ---- # limits.cpu 12 40 # limits.memory 48Gi 128Gi # requests.cpu 8 20 # requests.memory 24Gi 64Gi # count/services 3 10 # 查看 LimitRange 配置 kubectl describe limitrange team-a-limits -n team-a # 查找没有设置资源限制的 Pod安全隐患 kubectl get pods -n team-a -o json | \ jq -r .items[] | select(.spec.containers[].resources.requests null or .spec.containers[].resources.limits null) | .metadata.name四、边界分析与架构权衡ResourceQuota 的副作用基于 requests 统计而不是实际使用量。团队可能会虚报 request设置一个很高的值来申请空间实际使用却很低——造成资源浪费解决方法配合 LimitRange 设置maxLimitRequestRatio限制 limit/request 的比例防止虚报配额过严的问题如果 quota 用完了新 Pod 无法创建即便节点上实际还有很多空闲资源因为统计的是 requests不是实际使用需要建立配额申请和 review 流程——团队扩容前提交 resource request form或使用 VPAVertical Pod Autoscaler自动调整 Pod 的 requests 值来释放 quota什么场景不适合用严格的 ResourceQuota开发/测试环境——配额过严会频繁触发quota exceeded错误降低开发效率。建议用 LimitRange 限制单 Pod 即可quota 放宽单团队小集群 3 个 Namespace——引入 quota 的管理成本大于收益极度弹性伸缩的场景——如果使用 Karpenter 或 Cluster Autoscaler Spot 实例动态扩容固定的 quota 会限制弹性五、总结K8s 的资源管理三层结构缺一不可Pod 级别的 requests/limits 是单容器防护ResourceQuota 是跨团队的资源隔离LimitRange 是忘记配置时的兜底保护。关键是所有生产 Pod 必须有 requests 和 limits所有的生产 Namespace 必须有 ResourceQuota。这不是可选的优化项是生产环境的最低安全基线。

相关新闻