Kubernetes Pod 一直 Pending,先看 PodScheduled 条件

第 2 页

如果 FailedScheduling 里是 Too many pods,就别继续盯 CPU/内存了。这通常是节点上的非终态 Pod 数接近 .status.allocatable.pods;Kubernetes 1.24+ 可以先对符合该 Pod 约束的候选节点核对:

kubectl get node NODE \
  -o jsonpath='{.status.capacity.pods}{"\t"}{.status.allocatable.pods}{"\n"}'
kubectl get pods -A \
  --field-selector spec.nodeName=NODE,status.phase!=Succeeded,status.phase!=Failed \
  --no-headers | wc -l

第二条需要跨命名空间 list pods 权限。上限还可能受 kubelet maxPods、CNI/IP 容量和每节点常驻的 DaemonSet 影响,别直接把 maxPods 调大;先确认网络插件能提供足够地址。处理后再看新 Pod 的事件、PodScheduled=True 和业务容器 Ready=True

如果 FailedScheduling 提示的是 Insufficient nvidia.com/gpu 或其他扩展资源,kubectl top 看不出原因。Kubernetes 1.24+ 可以先核对 Pod 请求和候选节点实际向调度器公布的数量:

kubectl -n NS get pod POD -o jsonpath='{range .spec.containers[*]}{.name}{"\t"}{.resources.requests}{"\n"}{end}'
kubectl get node NODE \
  -o jsonpath='{.status.capacity.nvidia\.com/gpu}{"\t"}{.status.allocatable.nvidia\.com/gpu}{"\n"}'

扩展资源通常由设备插件上报;节点有硬件但 allocatable 缺失或变成 0 时,要查对应设备插件 Pod、节点状态和 kubelet 日志,继续加普通 CPU/内存没用。读取节点及系统组件日志需要相应权限。修复后确认节点重新公布资源、新 Pod 出现 PodScheduled=True,并以容器 Ready=True 为准。

如果事件里是 Insufficient ephemeral-storage,也要单独看,kubectl top 通常不提供这个调度口径。Kubernetes 1.24+ 可先核对目标 Pod 的 request 和候选节点公布的可分配量:

kubectl -n NS get pod POD \
  -o jsonpath='{range .spec.initContainers[*]}init/{.name}{"\t"}{.resources.requests.ephemeral-storage}{"\n"}{end}{range .spec.containers[*]}app/{.name}{"\t"}{.resources.requests.ephemeral-storage}{"\n"}{end}{.spec.overhead.ephemeral-storage}{"\n"}'
kubectl get node NODE \
  -o jsonpath='{.status.allocatable.ephemeral-storage}{"\n"}'
kubectl describe node NODE

调度器比较的是 request 与 Allocatable/已分配 request,不是节点当下的 df 使用率;真实磁盘紧张则还可能表现为 DiskPressure 和 taint,是另一条分支。读取 Node 需要相应 RBAC 权限。改工作负载模板或节点容量后,看新 Pod 的事件不再出现该原因,并确认 PodScheduled=True、容器 Ready=True

事件里如果是 didn't have free ports for the requested pod ports,可以单独查 hostPort;这和 Service 的 NodePort 不是一回事。Kubernetes/kubectl 1.24+ 可先看目标 Pod 请求了什么:

kubectl -n NS get pod POD \
  -o jsonpath='{range .spec.containers[*].ports[*]}{.name}{"\t"}hostIP={.hostIP}{"\t"}hostPort={.hostPort}{"\t"}protocol={.protocol}{"\n"}{end}'

再对候选节点列出现有 Pod 的端口占用:

kubectl get pods -A --field-selector spec.nodeName=NODE \
  -o jsonpath='{range .items[*]}{.metadata.namespace}{"/"}{.metadata.name}{"\t"}{range .spec.containers[*].ports[*]}{.hostIP}{":"}{.hostPort}{"/"}{.protocol}{" "}{end}{"\n"}{end}'

第二条需要跨命名空间 list pods 权限,空值或 0 不是实际占用。冲突按节点上的地址、端口和协议判断;修正控制器模板或端口规划后,确认新 Pod 不再出现这条事件,并检查 PodScheduled=True、容器 Ready=True