
在 K8s 里,Pod 看起来没问题、Deployment 也正常,但 Pod 就是不启动,事件里还反复出现:
pod has unbound immediate PersistentVolumeClaimsfailed to provision volume- PVC 状态卡在
Pending
大概率不是调度、不是镜像、不是容器启动参数------而是存储链路有问题。
1. 先把概念讲清:PVC Pending 到底说明了什么?
PVC 处于 Pending 的本质含义只有一句话:
集群目前找不到可绑定的 PV,或者无法按 StorageClass 动态创建 PV。
不是"应用错了",而是"存储还没准备好"。K8s 会主动阻塞依赖该 PVC 的 Pod,避免"半启动、写坏数据"。
2. 必须了解的存储链路(排障核心)
你可以把 K8s 持久化存储理解成一条链路:
Pod → PVC → PV → 后端存储(云盘/NFS/分布式存储)
只要中间任何一环对不上,Pod 就会一直等,无法启动。
3. PVC Pending 的 3 类根因(99% 都在这里)
下面按 K8s 控制器实际决策顺序讲,排障更快。
根因 A:没有可匹配的 PV(静态供给/绑定条件不满足)
当你用的是"预创建 PV(静态)"或集群动态供给失效时,K8s 会尝试找一个满足条件的 PV:
-
容量 ≥ PVC 请求值(如 20Gi)
-
StorageClass 匹配(或双方都不指定/同一类)
-
访问模式匹配(如
ReadWriteOnce) -
PV 处于
Available、未被占用
典型现象
-
kubectl get pv看不到符合条件的AvailablePV -
PVC Events 里提示找不到匹配卷(或一直无事件)
常见原因
-
你写了
storageClassName: fast-ssd,但集群里根本没有这个 StorageClass -
PV 有但已被绑定/处于
Released等状态 -
PVC 请求
RWO,但后端或 PV 定义不支持
根因 B:动态路径断了(StorageClass/Provisioner/CSI 不工作)
如果 PVC 指定了 StorageClass(或走默认 StorageClass),K8s 会尝试按 StorageClass 描述去"自动创建卷"。这依赖:
-
StorageClass 存在且配置正确
-
provisioner 正确(一般是 CSI 驱动的 provisioner)
-
CSI 驱动已安装且控制面组件正常
典型现象
-
PVC Events 里出现
ProvisioningFailed、failed to provision volume -
StorageClass 看起来"名字在",但实际不产出 PV(最迷惑)
根因 C:K8s 申请了,但后端存储拒绝了(配额/权限/后端故障)
这一类是"链路都对,但后端不让创建/创建失败",常见包括:
-
云盘配额不足(quota exceeded)
-
权限不足(如云厂商 IAM、vSphere 权限)
-
CSI controller 异常、组件 CrashLoop
-
存储后端不可用(控制面能看到失败,但 PVC 仍 Pending 等待)
典型现象
kubectl describe pvc的 Events 明确写了失败原因(这一步最关键)
4. 标准化排障 SOP(按这个走,基本不绕路)
Step 1:先看 PVC 的事件(不要先看 Pod 日志)
bash
kubectl get pvc -A
kubectl describe pvc -n <namespace> <pvc-name>
重点看 Events 段,通常能直接定位到:
-
找不到 StorageClass
-
provisioner 不存在
-
ProvisioningFailed -
failed to provision volume
Step 2:确认 StorageClass 是否存在、是否为默认
bash
kubectl get storageclass
kubectl get storageclass -o wide
排查点:
-
PVC 里写的
storageClassName是否拼对、是否存在 -
如果 PVC 没写
storageClassName:集群是否设置了默认 StorageClass((default)标识) -
默认 StorageClass 的机制依赖注解
storageclass.kubernetes.io/is-default-class
典型坑(迁移/改造后高发):旧 StorageClass 名称被删了,但历史 YAML 还在引用旧名字,导致新建 PVC 全 Pending。
Step 3:检查 PV 是否存在且可绑定
bash
kubectl get pv
kubectl get pv -o wide
你要看到的是:有 PV 处于 Available,并且它的容量/访问模式/StorageClass 能满足 PVC。
Step 4:确认 CSI 驱动与控制器日志(动态供给必做)
不同集群组件名字不一样,但思路一致:在存储相关命名空间(常见 kube-system)查看 CSI controller / provisioner 的日志。
bash
kubectl get pods -n kube-system | grep -i csi
kubectl logs -n kube-system <csi-controller-pod>
kubectl get events -n <namespace> --sort-by=.metadata.creationTimestamp
你要找的是"后端明确拒绝"的证据:权限、配额、参数不支持、后端不可达等。
5. 对症下药修复清单(最常见、最有效)
修复 1:StorageClass 名称不对/不存在
现象 :PVC 指定了 storageClassName,但集群没有该 StorageClass。
处理:
-
改 PVC 使用正确的 StorageClass
-
或补齐对应 StorageClass(并确保 provisioner/CSI 可用)
修复 2:集群没有默认 StorageClass(PVC 未指定时)
现象 :PVC 没写 storageClassName,集群也没有 (default) StorageClass,PVC 可能一直 Pending。
处理:设置/切换默认 StorageClass(按官方文档流程)。
修复 3:CSI 未安装或 controller 异常
现象 :Events 报 provisioning 失败,或 StorageClass 存在但"完全不出卷"。
处理:
-
确认 CSI 驱动安装完成(controller、node 组件都正常)
-
查 controller 日志定位后端错误
修复 4:后端拒绝创建(配额/权限/后端故障)
现象 :failed to provision volume,日志提示 quota/permission/backend unavailable。
处理:
-
云盘配额:扩容配额或换规格/换区域策略
-
权限:补齐 IAM/存储平台权限
-
后端:恢复存储服务、修复 CSI controller 稳定性
6. 生产级经验:为什么"应用没动,突然全 Pending"?
一个很典型的生产事故模型:
-
集群迁移/重装/版本升级
-
旧 StorageClass 名称被替换或删除
-
业务 YAML(PVC/StatefulSet)仍引用旧
storageClassName -
结果:新 Pod 全卡住,业务看起来像"发布失败",但根因是存储链路断了
建议做法(工程化)
-
把 StorageClass 名称当成"接口契约",变更要做全量影响评估
-
上线前做一条"PVC 动态供给冒烟测试"(创建一个临时 PVC 看能否自动绑定 PV)
7. 一页速查(拿去就能用)
bash
# 1) 先看 PVC 事件(最关键)
kubectl describe pvc -n <ns> <pvc>
# 2) StorageClass 是否存在/默认是否正确
kubectl get sc
kubectl get sc -o wide
# 3) 有没有可绑定的 PV
kubectl get pv -o wide
# 4) 动态供给:查 CSI
kubectl get pods -n kube-system | grep -i csi
kubectl logs -n kube-system <csi-controller-pod>
# 5) 补充:按时间看事件流
kubectl get events -n <ns> --sort-by=.metadata.creationTimestamp