Kubernetes Pod 一直 Pending 排查全流程:从 describe events 到资源、污点、PVC 逐层定位
Kubernetes Pod 一直 Pending 排查全流程:从 describe events 到资源、污点、PVC 逐层定位
上线时kubectl apply一把梭,结果kubectl get pods看到 Pod 卡在Pending十分钟不动。Pending 意味着调度器(scheduler)还没给这个 Pod 找到能落脚的节点,或者找到了节点但容器还没起来。它和CrashLoopBackOff(起来了又崩)是两码事——Pending 是根本没被调度上去。
这篇按「怎么定位 → 五类常见原因 → 每类怎么修」的顺序,给一套能照着敲的排查流程。
第一步:永远先看 describe 的 Events
九成 Pending 问题的答案就写在kubectl describe最底下的 Events 里,别急着改 YAML。
kubectl describe pod<pod-name>-n<namespace>翻到最下面的Events:段,重点看FailedScheduling这行。scheduler 会明确告诉你为什么调度不上去,比如:
Events: Type Reason Message ---- ------ ------- Warning FailedScheduling 0/3 nodes are available: 3 Insufficient cpu.这行0/3 nodes are available后面的原因,直接决定你往哪个方向查。下面按最常见的几类 Message 分别讲。
原因一:资源不够(Insufficient cpu/memory)
Message 长这样:0/3 nodes are available: 3 Insufficient cpu.或Insufficient memory。意思是所有节点的可分配剩余资源都小于你 Pod 的requests。
注意关键点:调度看的是requests 之和 vs 节点 allocatable,不是节点当前真实使用率。哪怕节点 CPU 实际只用了 10%,只要已调度 Pod 的 requests 加起来占满了,新 Pod 照样调度不上。
先看节点到底还剩多少:
kubectl describenode<node-name>|grep-A6"Allocated resources"输出里Requests那列就是已被预定的量:
Allocated resources: Resource Requests Limits cpu 3800m (95%) 6 (150%) memory 7Gi (90%) 10GiCPU requests 已经占到 95%,新 Pod 要 500m 自然塞不下。三种修法:
# 修法1:调低 Pod 的 requests(前提是真的用不了那么多)resources:requests:cpu:200m# 从 500m 降下来memory:256Mi# 修法2:扩容节点(手动加节点或让 Cluster Autoscaler 自动加)kubectl get nodes# 确认加成功# 修法3:清理占着 requests 却闲置的 Podkubectltoppods-A--sort-by=cpu# 找出「requests 高但实际使用低」的最容易被忽略的坑:某个 Pod 把requests.cpu写成了4(4 核),自己占满一台节点。写 requests 要按实际稳态用量估,不要照着 limits 抄。
原因二:节点有污点(Taints),Pod 没配容忍(Tolerations)
Message:node(s) had untolerated taint {key: value}。节点被打了污点(比如 master 节点默认带node-role.kubernetes.io/control-plane:NoSchedule),普通 Pod 不配 toleration 就被排斥。
看节点污点:
kubectl describenode<node-name>|grepTaints# Taints: node-role.kubernetes.io/control-plane:NoSchedule两种修法。如果这个污点确实该被这个 Pod 容忍(比如 DaemonSet 要跑在所有节点上),给 Pod 加 toleration:
tolerations:-key:"node-role.kubernetes.io/control-plane"operator:"Exists"effect:"NoSchedule"如果是节点被误打了污点(比如之前 drain 后忘了恢复),把污点去掉:
# 注意 key 后面加个减号表示删除kubectl taint nodes<node-name>node-role.kubernetes.io/control-plane:NoSchedule-还有一种自动加的污点要小心:节点 NotReady 或磁盘压力大时,K8s 会自动打node.kubernetes.io/not-ready等污点,这时候要去修节点本身,而不是加 toleration 硬塞。
原因三:nodeSelector / affinity 把自己框死了
Message:node(s) didn't match Pod's node affinity/selector。你给 Pod 加了nodeSelector或nodeAffinity,但没有节点带对应的 label。
# 比如要求节点有 disktype=ssd 标签nodeSelector:disktype:ssd排查:看有没有节点真带这个 label。
kubectl get nodes --show-labels|grepdisktype# 空 → 没有任何节点带这个标签,自然调度不上修法二选一:给目标节点打上 label,
kubectl label nodes<node-name>disktype=ssd或者放宽约束。硬亲和(requiredDuringScheduling)调不上就直接 Pending,如果只是「优先」而非「必须」,改成软亲和preferredDuringSchedulingIgnoredDuringExecution,匹配不到时也能退而求其次调到别的节点。
原因四:PVC 没绑上(pod has unbound immediate PersistentVolumeClaims)
Message:pod has unbound immediate PersistentVolumeClaims。Pod 挂了个 PVC,但这个 PVC 没找到能绑定的 PV,Pod 就跟着一起 Pending。
先看 PVC 自己的状态:
kubectl get pvc-n<namespace># NAME STATUS VOLUME CAPACITY STORAGECLASS# data Pending (空)PVC 也是 Pending,再 describe 它:
kubectl describe pvc data-n<namespace>常见两种根因:一是storageClassName写错或不存在,动态供应器根本没被触发;二是集群没装 provisioner(比如裸机集群没配 storage class)。
kubectl get storageclass# 确认 class 名字存在、且有 default 标记修法:PVC 的storageClassName对上真实存在的 class;裸机环境要么手动创建 PV 静态绑定,要么装个 provisioner(如 local-path-provisioner)。
原因五:调度上了但容器起不来(ContainerCreating 卡住)
有时 Pod 不是纯 Pending,而是ContainerCreating长时间不动——已经调度到节点了,但 kubelet 在拉镜像或挂卷时卡住。还是 describe 看 Events:
Failed to pull image ... ImagePullBackOff:镜像名/tag 写错,或私有仓库缺imagePullSecrets。MountVolume.SetUp failed:卷挂载失败,常是 PV 后端(NFS/云盘)不可达。
镜像拉取失败最常见,先手动在节点上验证镜像能不能拉:
# 私有仓库要给 Pod 配 imagePullSecretskubectl create secret docker-registry regcred\--docker-server=<你的仓库>--docker-username=<user>--docker-password=<pwd>然后在 Pod spec 里引用:
spec:imagePullSecrets:-name:regcred一条命令快速缩小范围
排查前先用这条把「所有异常 Pod + 事件」一次性捞出来,比逐个 describe 快:
# 按最近事件排序,直接看到 FailedScheduling 原因kubectl get events-n<namespace>--sort-by='.lastTimestamp'|grep-i-E"fail|pending|insufficient"小结
Pod Pending 的排查心法是「先问 scheduler 为什么调不上去」,而不是瞎改 YAML:
- 第一步永远是
kubectl describe pod看 Events 里的FailedScheduling,原因都写在那。 - Insufficient cpu/memory:比的是 requests 之和 vs 节点 allocatable,不是真实使用率 → 降 requests、扩节点或清闲置 Pod。
- untolerated taint:节点有污点 → 加 toleration 或删污点,自动打的污点要修节点本身。
- didn’t match node selector/affinity:约束太死没节点匹配 → 打 label 或把硬亲和改软亲和。
- unbound PVC:存储没绑上 → 查 storageClass 是否存在、有没有 provisioner。
- ContainerCreating 卡住:已调度但拉镜像/挂卷失败 → 查镜像名和 imagePullSecrets。
一句话记忆点:Pending 看 scheduler,CrashLoop 看容器日志——describe 的 Events 段是这两类问题共同的第一现场。