【K8s资源请求与限制】稳定不掉队:这3个核心区别90%人搞反了
你是否遇到过 Pod 好好的突然就重启了节点明明还有资源 Pod 却一直 Pending或者更闹心的——你的服务响应突然变慢查了一圈发现是 CPU 被限流了这些问题的根源十有八九和资源 Requests/Limits 有关。我搞 K8s 运维这几年在这个问题上踩过的坑加起来可以写一篇文章了。今天就把这一套实践总结分享出来代码可以直接复制跑。先搞清楚概念requests 是保障limits 是上限Requests 是 K8s 调度器做决策的依据。你申请 1 核 CPU 和 512Mi 内存调度器就会找一个满足这个“最低要求”的节点把 Pod 塞上去。它本质上是预留。Limits 是硬天花板。如果你没设 requestK8s 会自动帮你把 limit 复制成 request这个踩坑点之后说。说实话我把这个问题搞反了很久以为 request 是“上限”limits 是“下限”。其实 request 不会限制运行时使用量它只影响调度和最小保障。Pod 可以用超过 request 的资源——只要节点还有。但绝对不能超过 limit。❗这儿最关键CPU 和内存超限后的后果完全不一样CPU 超限 →限流。内核通过 CFS 配额强制限流超过极限就限流Pod 还能活但响应变慢。如果你的服务是 API 网关这种延迟敏感型应用CPU limit 设太紧会导致 p99 延迟飙升。解决办法之一是让开发侧评估加 CPU或启用 CPU Burst后面的彩蛋里会讲到。内存超限 →OOMKilled。超过 limit 内核可能会直接 killstatus 显示 OOMKilledPod 自动重启。内存没有限流机制用多了就是死。这和磁盘的 QOS 不一样内存压力下内核只能选一个 kill。啥也不设会发生什么刚用 K8s 时我最常犯的错就是忽略资源设置——因为反正 Pod 也能跑起来。不设 request → 调度器不知道你的需求可能把一堆 Pod 塞到一个节点上结果大家都抢资源谁也跑不好。不设 limit → 没人管上限。一个 Pod 有内存泄漏就把整个节点拖垮其他 Pod 全被驱逐。我见过内存耗尽触发节点级连失败的情况就是一个 Pod 没设 limit 导致的。结论生产环境必须设且内存 limit 必须设。CPU limit 存在争议——限流可能导致延迟飙升有的团队只设 CPU request 跳过 CPU limit。默认保守起见在生产环境可以先都设上再根据观察调整。实操Requests Limits 配置模板下面的 YAML 是一个 Deployment 的配置示例。request 是 100m CPU 和 256Mi 内存limit 是 500m CPU 和 512Mi 内存apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 3 selector: matchLabels: app: my-app template: metadata: labels: app: my-app spec: containers: - name: app image: myapp:v1 resources: requests: cpu: 100m # 0.1 核 CPU 保证 memory: 256Mi # 256 MiB 内存保证 limits: cpu: 500m # 0.5 核 CPU 上限 memory: 512Mi # 512 MiB 内存上限 -- 超了直接 OOMKill单位说明CPU 用m毫核1000m1核。内存用二进制单位Mi、Gi——匹配 Linux 的报告方式128Mi 128×1024²字节。QoS节点压力下谁先被驱逐K8s 给 Pod 分配三种 QoS 类决定了节点资源紧张时的驱逐顺序。QoS 类条件驱逐优先级适用场景Guaranteed所有容器的 request limitCPU内存最后被驱逐最安全核心生产服务、数据库Burstablerequest limit至少一个容器有 request/limit中等大多数 Web 应用BestEffort完全不设 requests/limits第一个被驱逐没事别用这个BestEffort 是“让社区测试环境跑测试任务”用的别拿到生产环境。大多数业务 Pod 停留在 Burstable 没问题但重要服务尽量提高到 Guaranteed——它是真正的最高保护等级。VPA懒得手动调K8s 帮你自动右规模每次做容量评估都耗时间。K8s 官方 VPA 能根据 Pod 历史用量自动推荐或自动调整requests/limits。我一般在生产上推荐先开Off模式——让 VPA 推荐但不自动改——人看一眼再决定。安装 VPA前提Metrics Server 已部署git clone https://github.com/kubernetes/autoscaler.git cd autoscaler/vertical-pod-autoscaler ./hack/vpa-up.sh # 部署 VPA 组件 kubectl get pods -n kube-system | grep vpa # 验证组件运行创建一个 VPA 对象apiVersion: autoscaling.k8s.io/v1 kind: VerticalPodAutoscaler metadata: name: my-app-vpa spec: targetRef: apiVersion: apps/v1 kind: Deployment name: my-app updatePolicy: updateMode: Off # 只推荐不修改。想自动改就用 Auto resourcePolicy: containerPolicies: - containerName: * minAllowed: cpu: 50m memory: 128Mi maxAllowed: cpu: 2 memory: 2GiupdateMode有四种Off只推荐、Initial只在创建时设一次、Auto自动重建 Pod 应用推荐、Recreate重启时应用。生产环境建议先用 Off 观察几周推荐值确认符合使用模式后再手动应用到 Deployment。配置生产环境 LimitRange 和 ResourceQuota如果不按命名空间做配额一个团队可能会把整个集群资源吃光。LimitRange 是个好帮手能自动注入默认资源。LimitRange为命名空间设置默认值自动给 Pod 注入资源apiVersion: v1 kind: LimitRange metadata: name: default-resource-limits namespace: default spec: limits: - default: # 没设 limits 时用这个 cpu: 500m memory: 512Mi defaultRequest: # 没设 requests 时用这个 cpu: 100m memory: 256Mi max: # 设 limits 时必须 ≤ 这个值 cpu: 2 memory: 2Gi min: cpu: 50m memory: 128Mi type: Container创建后开发者创建 Pod 时如果不设资源K8s 自动注入 request100m 内存/256Milimit500m CPU/512Mi 内存。小心加了 LimitRange 之后再改已存在的 Pod 不会变。前面留了个坑如果 namespace 里有两个或更多 LimitRange默认值用哪个不确定所以一个 namespace 最好只设一个 LimitRange。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 pods: 20它防止单个命名空间耗尽集群所有资源。配合 LimitRange 使用效果更好——Quota 强制用 Pod 必须配置 requests/limits否则无法计算配额。如果创建 Pod 超过配额限制API Server 会拒绝并返回错误。排查问题1. Pod 一直 Pendingkubectl describe pod会告诉你原因。如果看到类似 “0/3 nodes available: 1 Insufficient cpu, 2 Insufficient memory”说明 request 大于任何节点的可用容量。要么增加节点规格要么降低 Pod request。2. Pod 莫名重启先看kubectl describe pod在 Events 或 Container Status 里找 “OOMKilled”。确认后有两种可能反复 OOM 说明 limit 设太低了或者你的应用实际需要更多内存。还有一种特殊情况——Golang 应用没有配合GOMEMLIMIT→ 内存使用超过 K8s 内存 limit 被 kill。运行在 Pod 里面的 Java、Go 应用要格外小心 JVM/Go GC 与 K8s 内存 limit 的配合关系。3. 服务响应变慢看指标CPU 使用量接近 CPU limit 导致限流延迟升高。检查kubectl top pod、kubectl describe pod | grep -i throttle适当提高 CPU limit或移除 CPU limit。如果是在云厂商的 K8s 集群可以尝试启用 CPU Burst 功能缓解限流。这里有一套成熟的资源基准合理 ratios内存用 binary 单位Mi/GiLimit/Request 初期按 1.5-2 倍设。稳定后极限稳定型如数据库用 1:1 到 1:1.1对突发型 Web 服务limit 可到 request 的 2-4 倍。监控 调整用kubectl top pod看实际用量把 request 设到略高于 P95 用量加 20-30% 余量。至于大集群的自动弹性伸缩可以考虑配合 HPA基于负载水平扩缩 VPA垂直优化单 Pod 节点扩容的联动方式。用 kubectl 查资源kubectl top pod --all-namespaces # 实时资源用量 kubectl describe pod pod-name # OOM 原因、QoS 类等 kubectl get pod pod-name -o yaml | grep qosClass总结 4 点Requests ≠ Limitrequest 是调度依据limit 是硬上限。CPU 超限会限流内存超限会 OOMKilled。一定要设资源不设就是 BestEffort节点紧张时第一个被干掉。Guaranteed 最安全核心服务把 CPU 和内存的 request 都等于限值。VPA Off分析生产环境先用 Off 模式看推荐值结合 HPA 做全自动扩缩。好了上面这套都是我亲手打磨出来的。你那边在生产环境有没有因为资源设置不合理翻过车欢迎评论区聊聊——说不定你的经验下次就能帮到更多人。