面向初级运维,使用 Linux 节点和稳定 Kubernetes API。命令按 Bash 编写。本文为教学故障场景,日志及结果为示意,不冒充生产实测;执行前确认 context、命名空间和权限。
一、遭遇情况:扩容了副本,新 Pod 却始终 Pending
Deployment 期望两个副本,新增 Pod 一直不运行。看到 Pending,有人马上准备把内存 requests 改小,但事件中真正的原因可能是节点标签不匹配。
本篇案例是复制部署文件时保留了旧环境的 nodeSelector,新集群没有对应标签的节点。资源再充足,也无法满足这个硬性调度约束。
二、原因分析:Pending 不是单一故障名称
Pod 还没选到节点,以及已经选到节点但仍在下载镜像或准备卷,都可能处于 Pending 阶段。kubectl get pods 的 STATUS 是便于展示的摘要,不等于完整状态模型。
先看 .spec.nodeName、PodScheduled 条件和事件,再决定是否进入调度器排查。已有节点、事件却是拉镜像失败时,应看第 4 篇,而不是继续修改调度要求。

三、排查思路:把调度器的话翻译成业务条件
kubectl get pods -n 目标命名空间 -o wide
kubectl describe pod 目标Pod -n 目标命名空间
kubectl get nodes --show-labels
kubectl describe node 目标节点
名称是占位符,先替换。读取事件中的原因,例如资源不足、节点选择器不匹配、不可容忍污点或 PVC 尚未绑定。单条消息可能包含多个节点分别失败的原因,不应只摘其中一个词。
| 证据 | 应继续核对 |
|---|---|
Insufficient cpu/memory |
requests、可分配资源与已有预留 |
| selector/affinity 不匹配 | Pod 条件与真实节点标签 |
| untolerated taint | 节点用途与目标工作负载是否允许进入 |
| unbound PVC | StorageClass、绑定模式与存储事件 |
| 节点不可调度 | 是否被维护操作 cordon,以及维护是否结束 |
调度通常按 requests 与节点可分配资源判断,不是只看当前 top 里 CPU 闲不闲。limits 和运行时实际消耗又是另一层约束。
四、实践:复现不存在的节点标签
在允许创建实验工作负载的测试集群,保存 kt03-pending.yaml。先确认没有节点使用下面故意选择的标签值。
apiVersion: v1
kind: Namespace
metadata:
name: kt03
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: kt03
spec:
replicas: 1
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
nodeSelector:
training.longtrail.cloud/pool: intentionally-missing
containers:
- name: web
image: nginx:stable-alpine
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
cpu: 250m
memory: 128Mi
kubectl apply -f kt03-pending.yaml
kubectl get pods -n kt03 -o wide
kubectl describe pod -n kt03 -l app=web
预期没有可用节点满足标签条件,事件指向调度失败。若首先遇到 ResourceQuota 或准入策略拒绝,Deployment 甚至可能没有成功创建 Pod,要以实际事件为准。
五、修复实践:修部署意图,不伪造节点用途
如果确认本实验应运行在普通 Linux 工作节点上,可只修改实验 Deployment 的选择器:
kubectl patch deployment web -n kt03 --type=merge -p '{"spec":{"template":{"spec":{"nodeSelector":{"training.longtrail.cloud/pool":null,"kubernetes.io/os":"linux"}}}}}'
kubectl rollout status deployment/web -n kt03 --timeout=120s
kubectl get pods -n kt03 -o wide
补丁删除错误标签条件,保留明确的 Linux 条件。成功还取决于实际节点可调度、镜像可拉取及资源足够;新的事件如果变了,就沿新证据继续查。
生产环境不能为了让 Pod 落地,就随意给控制面加标签、去掉专用节点污点或把所有 taint 都容忍。先确认业务应该去哪类节点,再改部署约束或按规划提供相应节点。
如果确实是 requests 大于实际需求,应结合测量修正;若业务需求合理,则需要容量调整或迁移,不能用虚低 requests 让调度器接受一个实际跑不稳的副本。
六、验证与总结
确认 Pod 已分配到预期类型的节点、容器 Ready、Deployment 完成发布,随后验证应用。单纯出现 nodeName,只证明调度成功,还没有证明启动和业务成功。
修复要写回部署源文件或 GitOps 配置,否则控制器同步后可能恢复错误选择器。实验完成后只处理 kt03 中自己创建的对象。
这类故障的顺序是:先分调度前后 → 读 FailedScheduling 的完整条件 → 对照节点 → 修一项有证据的约束 → 验证落点与业务。Pending 本身只是入口,调度事件才是进一步判断的依据。