Pod 卡在 Pending 状态的处理方法
- pod
- 2小时前
- 0评论
5 条命令快速定位
遇到 Pod Pending 别慌,按顺序敲这几条命令,5 分钟内就能把问题摸清楚:
# 1. 看 Pod 到底卡在哪
kubectl describe pod <pod-name> -n <namespace>
# 重点看 Events 尾部,会直接告诉你原因
# 2. 看集群里所有节点还剩多少资源
kubectl describe nodes | grep -A 5 "Allocated resources"
# 重点关注 CPU 和 Memory 的请求占比
# 3. 看节点实时负载(需要安装 metrics-server)
kubectl top nodes
# 4. 看调度器是不是还活着(自建集群用这条)
kubectl get pods -n kube-system -l component=kube-scheduler
托管集群用户注意:如果你用的是云厂商的托管集群(如 EKS、AKS、TKE 等),控制面由云厂商管理,用户通常无法直接查看调度器 Pod 的状态。建议通过云厂商控制台或工单确认调度器是否正常。
# 5. 筛选所有 Pending 的 Pod,看看是不是大面积沦陷
kubectl get pods -A --field-selector=status.phase=Pending
这几条命令跑完,90% 的情况你已经有答案了。
Pod Pending 到底发生了什么?
先搞清楚 K8s 调度的逻辑:
当你创建一个 Pod 时,它不会立刻被扔到某个节点上。调度器(kube-scheduler)会先对所有节点做一轮“过滤”——检查每个节点是否满足 Pod 的所有硬性要求,比如 CPU/内存是否够、节点标签是否匹配、污点能不能容忍等等。
调度器看的是 requests,不是 limits,更不是节点上的实时 CPU 使用率。
这句话太重要了,我见过无数人被这个点坑过。你 kubectl top nodes 一看 CPU 才用了 30%,心想“资源充足啊”,但调度器根本不看这个——它看的是所有 Pod 的 requests 总和有没有超过节点的 Allocatable。就算节点实际负载很低,只要 requests 满了,新 Pod 就进不来。
说到 Allocatable,有必要解释一下它是怎么来的。节点的 Allocatable 是在节点总容量基础上,扣除了 kubelet 为系统组件预留的资源(--kube-reserved 和 --system-reserved)以及驱逐阈值(--eviction-hard)之后的可分配量。如果你发现节点总容量很大但 Allocatable 少了很多,先去检查 kubelet 的这几个启动参数。
┌─────────────┐
│ Pod 创建 │
└──────┬──────┘
▼
┌─────────────┐ 过滤失败 ┌─────────────┐
│ 调度器过滤 │ ───────────────▶ │ Pending │
│ (Filter) │ │ FailedSched │
└──────┬──────┘ └─────────────┘
▼ 过滤通过
┌─────────────┐
│ 调度器打分 │
│ (Score) │
└──────┬──────┘
▼
┌─────────────┐
│ 绑定节点 │
└─────────────┘
过滤失败最常见的原因就是资源不足,Events 里会直接告诉你——0/3 nodes are available: 3 Insufficient cpu 或 Insufficient memory。
为什么 kubectl top nodes 显示资源充足,但 Pod 还是 Pending?
这个问题太常见了,值得单独拎出来说。
kubectl top nodes 显示的是节点上所有 Pod 当前瞬时的实际资源使用量总和,它依赖 metrics-server 从 kubelet 的 /stats/summary 端点采集数据。而调度器做决策时看的是 requests 总和——也就是 Pod 向集群“预订”的资源量。
这两者之间的差距可能非常大。一个 Pod requests: 2 CPU 但实际只用 0.1 CPU,在 top 命令里只显示 0.1,但在调度器的账本里已经扣掉了 2 个核。所以你会看到 top 显示资源充足,但调度器依然报 Insufficient。
我的建议:排查资源问题时,把 kubectl describe node 和 kubectl top nodes 结合起来看。前者告诉你“还有多少配额可以分配”,后者告诉你“实际用了多少”。两个数字都对不上,那就要去查每个 Pod 的 requests 配置了。
4步排查法:
第一步:确认是资源不足还是别的坑
拿到 kubectl describe pod 的输出后,Events 部分的 Message 字段会直接告诉你调度失败的原因。
kubectl describe pod my-app-xxxxxxxx-xxxxx
如果看到类似这样的信息:
Warning FailedScheduling 12s default-scheduler 0/4 nodes are available: 4 Insufficient cpu.
那就确定是 CPU 资源不足。如果是 Insufficient memory,就是内存不够。
但也有可能不是资源问题——比如 Events 显示 0/4 nodes are available: 4 node(s) had untolerated taint,那是污点没容忍;或者是 didn't match Pod's node affinity,那是亲和性规则太严。这些后面会单独提一嘴,但今天重点说资源不足。
第二步:看看到底哪个节点还有余粮
确认是资源不足后,下一步是搞清楚集群的资源水位。
kubectl describe nodes
重点看每个节点末尾的 Allocated resources 部分:
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 4800m (120%) 9600m (240%)
memory 8Gi (80%) 16Gi (160%
ephemeral-storage 0 (0%) 0 (0%)
cpu 4800m (120%), 这意味着这个节点上所有 Pod 的 CPU requests 总和已经超过了节点的可分配容量。新 Pod 自然进不来。
第三步:找出“高CPU”的 Pod
找到资源最紧张的节点后,看看是哪些 Pod 在消耗 requests:
kubectl describe node <node-name> | grep -A 10 "Non-terminated Pods"
更精确一点,看每个 Pod 的 requests:
kubectl get pods -n <namespace> -o=custom-columns=NAME:.metadata.name,CPU_REQ:.spec.containers[*].resources.requests.cpu,MEM_REQ:.spec.containers[*].resources.requests.memory
这时候你可能会发现:有些 Pod 的 requests 配得极其夸张——一个简单的 Node.js 服务配了 2 核 CPU、4Gi 内存,但实际运行只需要 100m CPU、256Mi 内存。
第四步:修改资源
方案一:降低 Pod 的 requests
resources:
requests:
cpu: 100m # 原来是 500m
memory: 256Mi # 原来是 1Gi
limits:
cpu: 200m
memory: 512Mi
方案二:清理僵尸 Pod 和过期资源
有时候节点上堆了一堆已经完成或驱逐的 Pod 还在占用 requests 记录。清理掉它们:
kubectl delete pod <pod-name> -n <namespace>
# 清理 Completed 状态的 Pod
kubectl delete pods -n <namespace> --field-selector=status.phase=Succeeded
方案三:扩容节点
如果业务确实需要这么多资源,那就加节点吧。云上环境可以用 Cluster Autoscaler 自动扩容。
预防处理:
三个习惯帮你远离 Pending
- 给所有 Pod 配合理的 requests ——不要照抄网上的模板,根据实际压测结果来。从 100m CPU、128Mi 内存开始,观察后再调整。
- 监控集群的 requests 水位,而不是实际使用率——在 Prometheus 里加一条 sum(kube_pod_container_resource_requests) 的告警,比只看 CPU 使用率靠谱得多。
- 用 PriorityClass 保核心业务——给关键服务配高优先级,资源紧张时能抢占低优先级 Pod 的资源。
