K8s 1.26 集群里新上的 Pod 没写 resources,压测时它把节点内存吃到 30G,kubelet 开始驱逐同节点其他 Pod,业务方还以为是调度器出了问题。
一开始怀疑是「命名空间没有 LimitRange 和 ResourceQuota 兜底」,查了一圈,方向不对。
真正麻烦的地方在于,几个原因的现象几乎一样。没设 requests,调度器按零资源计算,Pod 能被塞进任何节点。少数情况下是没设 limits,容器可以吃满节点内存,触发节点级 OOM 和驱逐。
不容易想到的是,Java 容器按宿主机内存算堆,进一步放大了占用。
动手时先找出哪些 Pod 没设资源
kubectl get pod -A -o json | jq -r '.items[] | select(.spec.containers[].resources.requests==null) | .metadata.name' | head
接着确认节点的驱逐记录
kubectl describe node node-1 | grep -iE 'MemoryPressure|Evicted'
给工作负载补上 requests 和 limits
kubectl set resources deploy api --requests=cpu=500m,memory=1Gi --limits=cpu=2,memory=2Gi
剩下的就是用 LimitRange 给命名空间兜底
kubectl create quota default-quota --hard=requests.cpu=20,requests.memory=40Gi --dry-run=client -o yaml | kubectl apply -f -
我习惯把每一步的执行时间和结果记在一边,后面复盘省事。
改完先别撤,确认这几项。kubectl describe pod 显示 requests 和 limits 都已设置,压测时该 Pod 内存稳定在 2G 以内,节点不再出现驱逐事件。
容易忽略的是,limits 设得和 requests 一样会失去弹性,通常 requests 按均值、limits 按峰值;JVM 还要加 MaxRAMPercentage 让堆跟着 limit 走。线上能稳定复现的问题都不算难,难的是只在大流量下才出现的那种。
