资源配额 / OOMKilled / RBAC / 调度排障
OOMKilled
现象: Pod 退出码 137(SIGKILL),Reason 为 OOMKilled。
快速定位
# 确认 OOMKilled
kubectl describe pod <name> -n <ns> | grep -E "Last State|Reason|Exit Code"
# 检查资源限制
kubectl get pod <name> -n <ns> \
-o jsonpath='{.spec.containers[*].resources.limits.memory}'
# 检查节点内存
kubectl top nodes
free -h
OOMKill 的底层机制
Linux OOM Killer 根据进程的 oom_score 选择要杀掉的进程。
Kubernetes 通过 oom_score_adj(由 kubelet 按 QoS 等级设置)控制 OOM 优先级:
| QoS 等级 | oom_score_adj | OOM 优先级 |
|---|---|---|
| Guaranteed | -997 | 最低(最难杀) |
| Burstable | min(max(2, 1000 - 1000×memoryRequest/nodeMemory), 999) | 中等 |
| BestEffort | 1000 | 最高(最先杀) |
内存的 Burstable QoS 陷阱(重要)
当内存 Request < Limit 时,Pod 处于 Burstable QoS。OOM Killer 用 Request 值(而非 Limit 值) 计算 oom_score,导致反直觉现象:
- Pod A (Burstable):requests: 2Gi, limits: 4Gi,实际只用 512Mi
- Pod B (Guaranteed):requests: 512Mi, limits: 512Mi,实际只用 512Mi
Node 内存紧张时,Pod A 反而更容易被 OOMKill——尽管它的 Request 更大。
结论: 内存强烈建议设置 Request = Limit,使 Pod 进入 Guaranteed QoS, oom_score_adj 固定为 -997,最不容易被 OOMKill。
更多细节参见 k8s-resource-limits-configuration。
修复方案
- 增大 memory limits(如果是正常业务增长)
kubectl patch deployment - 检查内存泄漏(使用
kubectl top pod观察趋势) - 设 Guaranteed QoS:让内存 Request = Limit
- 优化应用内存使用
- Java: JVM
-Xmx设为容器 limit 的 75-80% - Go: 设
GOMEMLIMIT环境变量(Go 1.19+) - 增加节点内存或扩容节点
ResourceQuota 与 LimitRange
LimitRange:Namespace 级默认资源限制
当 Pod 未设置 resources 时自动生效默认值:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: my-app
spec:
limits:
- type: Container
default: # 未设 limits 时的默认值
cpu: "100m"
memory: "128Mi"
defaultRequest: # 未设 requests 时的默认值
cpu: "100m"
memory: "128Mi"
min: # 最小允许值
cpu: "10m"
memory: "16Mi"
max: # 最大允许值
cpu: "4"
memory: "8Gi"
maxLimitRequestRatio: # limit/request 比例上限
cpu: 10
memory: 10
ResourceQuota:限制 Namespace 总资源
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "10"
requests.memory: "20Gi"
limits.cpu: "20"
limits.memory: "40Gi"
pods: "50"
排查命令
# 查看 Namespace 资源配额
kubectl describe resourcequota -n <namespace>
kubectl get resourcequota -n <namespace> -o yaml
# 查看 LimitRange
kubectl describe limitrange -n <namespace>
常见问题
- ResourceQuota 超限 → 新 Pod 无法创建(Events 显示
quota相关错误) - LimitRange 默认值生效 → 未设 resources 的 Pod 自动获得默认配置
- LimitRange max 值过低 → Pod 请求超限无法创建
- LimitRange 的
maxLimitRequestRatio→ 限制 limit/request 比例,防止过度超售
详细配置指南参见 k8s-resource-limits-configuration。面试速查参见 k8s-interview-100-questions。
RBAC 权限问题
现象: "forbidden" 错误。
# 测试权限
kubectl auth can-i <verb> <resource> \
--as=system:serviceaccount:<ns>:<sa-name>
# 检查 ServiceAccount
kubectl get sa <name> -n <ns> -o yaml
# 检查 Role/ClusterRole 和绑定
kubectl get role,rolebinding -n <ns>
kubectl describe role <name> -n <ns>
kubectl describe rolebinding <name> -n <ns>
修复: 创建正确的 Role + RoleBinding 并关联到 ServiceAccount。
调度失败 — Taint 与 Toleration
现象: Pod 满足资源条件但不满足污点条件。
# 查看节点污点
kubectl get node <name> -o jsonpath='{.spec.taints}'
# 查看 Pod 容忍
kubectl get pod <name> -n <ns> -o jsonpath='{.spec.tolerations}'
常见污点:
node.kubernetes.io/not-ready:NoExecutenode.kubernetes.io/unreachable:NoExecutenode-role.kubernetes.io/control-plane:NoSchedule
修复:
- 添加 Tolerations 到 Pod
- 移除节点污点:
kubectl taint node <name> <key>:NoSchedule-
生产操作安全规范
操作前必查清单:
- 影响范围确认 — 操作会影响哪些 Pod/用户/业务?
- 配置备份 —
kubectl get <res> <name> -n <ns> -o yaml > backup.yaml - 回滚方案 — 准备好回滚命令
- 执行窗口 — 业务低峰期
- 通知相关方 — 提前通知业务方和值班人员
高风险操作(警惕):
- 删除 Namespace(不可逆)
- 修改 RBAC 权限(可能丢失集群管理权限)
- 删除 StorageClass(PV 无法恢复)
- 修改 etcd 数据
- 大规模删除 Pod
关联页面
| 页面 | 关联点 |
|---|---|
| docker-production-pitfalls | Docker 原生 OOMKill 与资源限制视角 |
| k8s-resource-limits-configuration | K8s 资源限制详细配置指南 |
| jvm-container-oom-offheap-troubleshooting | JVM 堆外内存(DirectByteBuffer/Metaspace/线程栈)导致容器 OOMKi |
| k8s-capacity-planning-qos-cost-optimization | K8s 容量规划方法论与成本优化 — 从流量到资源预算的完整框架,含 QoS 策略、弹性伸缩协同、落 |
| k8s-pod-pending-troubleshooting-guide | Pod Pending 排障指南 — 7 个排查方向(资源不足/污点/亲和性/存储/配额/选择器/端 |
| k8s-scheduling-strategy-guide | K8s 调度策略完整指南(nodeSelector/Affinity/Taint/Topology/PriorityClass) |