PVC 一直 Pending?五步排查存储绑定

导语:Pod 卡在 ContainerCreating,一看是 PVC 一直 Pending?别急着删了重建。五步定位:看事件分形态 → 核对 StorageClass → 查空闲 PV → 查供应方日志 → 验证挂载条件,每步都有能当场执行的命令。

部署一个带持久化的应用,Pod 卡在 ContainerCreating 不动,进去一看:kubectl get pvc 里 PVC 的 STATUS 一直是 Pending。这是 K8s 存储问题里最常见的入口故障。很多人第一反应是把 PVC 删了重建,结果有时候好了,有时候越建越多------因为 Pending 的原因有好几种,不动手看事件就重建,纯属碰运气。

正确的做法是按层拆:先看事件分清形态,再核对 StorageClass,再查空闲 PV,再看供应方日志,最后验证挂载条件。五步走完,绝大多数 Pending 都能落到具体原因上。

第 1 步:看事件,先把 Pending 分成四类

PVC 为什么 Pending,答案就写在它自己的 Events 里:

bash 复制代码
kubectl describe pvc mydata -n prod

重点看 Events 段的原文,常见四类:

  1. 没等到消费方 :waiting for a volume to be created, either by external provisioner "xxx" or manually created by system administrator------供应方没响应或者没有供应方。
  2. 延迟绑定 :waiting for pod xxx to be scheduled------这不是故障,是 volumeBindingMode: WaitForFirstConsumer 在等 Pod 先调度。
  3. SC 不存在 :storageclass.storage.k8s.io "xxx" not found------PVC 里写的存储类名字不存在。
  4. 匹配不上 :no persistent volumes available for this claim and no storage class is set------没有现成 PV 能接住这个申请。

先把形态分清,后面查的方向完全不同:第 2 类不用修,把 Pod 的调度问题解决掉它自己会绑定;第 1、3、4 类才需要往下查。

一个容易忽略的点:PVC 的 Events 只保留最近的,新建 PVC 事件很少时,把 describe 输出拉到最底下看,或者用 kubectl get events -n prod --sort-by=.lastTimestamp | grep mydata 过滤一遍。

第 2 步:核对 StorageClass,名字和默认标注

第 3 类「SC not found」最简单也最高频------PVC 里 storageClassName 拼错了。先看集群里有哪些存储类:

bash 复制代码
kubectl get sc
kubectl get sc -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.provisioner}{"\t"}{.volumeBindingMode}{"\n"}{end}'

逐项核对三件事:

  • 名字对不对 :PVC 的 storageClassName 与 get sc 的名字逐字符比对,fast-ssd 和 fast-ss 差一个字符就报 not found。
  • 默认存储类在不在 :看有没有标了 storageclass.kubernetes.io/is-default-class: "true" 的 SC。PVC 不写 storageClassName 时会自动用它;如果默认 SC 被删了或没人标,不写名字的 PVC 就会永远 Pending。
  • 绑定模式 :volumeBindingMode 是 Immediate 还是 WaitForFirstConsumer。前者创建 PVC 立刻绑,后者要等 Pod 调度到某个节点才在对应可用区/节点供卷。多可用区集群强烈建议后者,否则跨区调度会挂载失败。

改名字直接 kubectl edit pvc 是不行的------PVC 的 storageClassName 字段不可变,只能删了重建(数据没绑定就不存在丢数据问题)。

第 3 步:查空闲 PV,能不能接住这个申请

如果 PVC 没写 storageClassName(或写了但想手动绑定),就要看有没有现成 PV 能匹配:

bash 复制代码
kubectl get pv
kubectl get pv -o custom-columns=NAME:.metadata.name,CLAIM:.spec.claimRef.name,STATUS:.status.phase,CAP:.spec.capacity.storage,MODES:.spec.accessModes

逐列核对:

  • 状态 :只有 Available 的 PV 能被新 PVC 绑定。Bound 已被占用;Released 已被旧 claim 释放但数据还在,默认策略下不能复用 ,必须手动清掉 spec.claimRef 才会回到 Available。
  • 容量:PV 的 capacity 必须 ≥ PVC 的 requests。申请 20Gi、PV 只有 10Gi,永远不会绑。
  • AccessModes :PVC 要 ReadWriteMany、PV 只有 RWO,匹配不上。
  • StorageClassName :手动绑定也要求两者的 storageClassName 一致(或都是空)。

Released 的 PV 想复用,编辑 PV 删掉 spec.claimRef 字段即可;如果 reclaimPolicy 是 Delete,PV 会直接被删掉,别指望它留着。

第 4 步:查供应方,让 provisioner 自己开口

第 1 类「等外部供应方」------PVC 挂在了一个 SC 上,但 SC 对应的 provisioner 没干活。分两看:

先看 SC 的 provisioner 指向谁,再确认这个供应方在集群里活着:

bash 复制代码
kubectl get sc fast-ssd -o jsonpath='{.provisioner}'
kubectl get pods -A | grep -iE 'provisioner|csi'
  • 内置 provisioner(如 hostPath、local-path)由 controller-manager 处理,失败信息直接出现在 PVC Events 里,一般是节点上路径不存在、权限不足。
  • 外部 provisioner(nfs-subdir-external-provisioner、CSI 驱动、Harbor 之后的 ceph-csi 等)是独立 Pod,要看它自己的日志:
bash 复制代码
kubectl logs -f -n kube-system <provisioner-pod> | grep -i mydata

高频失败原因:NFS 服务端不通或导出目录没建 、CSI 驱动的 node plugin 没起来 (kubectl get pods -A -o wide 看是否缺节点)、存储后端配额打满或磁盘满 、SC 的 parameters 写错(比如 ceph 的 clusterID 与 CephCluster 对不上)。报错原文几乎都会点名具体原因,比猜快十倍。

第 5 步:验证挂载条件,绑上了≠能用了

STATUS 变成 Bound 不算完,Pod 经常还是起不来,卡在 ContainerCreating。这时候查三个挂载条件:

bash 复制代码
kubectl get pv <pv-name> -o jsonpath='{.spec.nodeAffinity}'
kubectl describe pod <pod-name> | grep -A 5 -i mount
  • 节点亲和:local PV / WaitForFirstConsumer 绑定的卷带 nodeAffinity,只允许调度到特定节点。Pod 打了节点选择器却选不到那些节点,就会卡住。
  • 挂载报错 :Events 里 MountVolume.SetUp failed 一类报错,通常是 NFS 服务端拒连、路径不存在、或文件系统类型不支持(节点缺 nfs-common 就会挂载超时)。
  • 权限 :容器内非 root 用户写不了挂载点,补 securityContext.fsGroup;ext4/xfs 的 local PV 还要注意目录属主。

一图总结

  • 第一步看事件:describe pvc 把 Pending 分四类,延迟绑定不算故障
  • 第二步核 SC:名字逐字符对,默认标注与绑定模式两查
  • 第三步找 PV:Available + 容量 + AccessModes 三匹配,Released 要清 claimRef
  • 第四步问供应方:provisioner 日志点名报错,配额与参数细核对
  • 第五步验挂载:nodeAffinity、Mount 报错、fsGroup 权限

避坑清单

  1. PVC 的 storageClassName、spec.resources.requests.storage 创建后不可改,要改只能删了重建------先确认没 Bound 再删。
  2. 删 PVC 之前想清楚 reclaimPolicy:Delete 会连 PV 带数据一起删,生产环境重要数据一律 Retain。
  3. Released 状态的 PV 不能直接复用,手动清 spec.claimRef 才会回 Available;Delete 策略下 PV 已被删。
  4. 不写 storageClassName 依赖默认 SC 时,删 SC 前先确认没有 PVC 在等它,否则一批 PVC 集体 Pending。
  5. WaitForFirstConsumer 模式下 PVC 一直「等 Pod」是正常的,先修 Pod 调度(资源不足、亲和冲突、污点),别去动存储。
  6. 节点挂 NFS 卷必须装 nfs-common(Debian 系)/ nfs-utils(RHEL 系),缺包的表现就是 mount 超时,错误信息里却看不出是缺包。
  7. 排查 provisioner 时先看它的 Pod 是不是真的在跑:CSI 驱动是 DaemonSet + Deployment 双件套,node plugin 缺节点是隐蔽故障源。

小结

PVC Pending 之所以让人烦躁,是因为「卷没造出来」「卷造了绑不上」「绑上了挂不了」三类完全不同的问题共用一个状态。先用 describe 的 Events 分清形态,再沿「SC → PV → provisioner → 挂载条件」这条链逐层核对,每一步都有明确的验证命令。记住一条:删了重建只是重掷骰子,Events 里的报错原文才是答案。

相关推荐
9624561 小时前
一次 Kubernetes 临时存储压力引发的小程序授权雪崩:从 Pod 驱逐到定时任务漏执行
容器·小程序·kubernetes
SatanII1 小时前
Kubernetes 网络
网络·容器·kubernetes
知已难寻11 小时前
第 2 篇 · 云的地基:服务器、存储、网络三大基础设施
运维·服务器·网络·云原生·云计算·负载均衡·1024程序员节
阿里云云原生15 小时前
车企数据隐私保护必修课:如何用 SLS mask 守住日志中的敏感信息
云原生
阿里云云原生16 小时前
切换模型会损失缓存,智能路由还省钱吗?
云原生
闲云野鹤在人间16 小时前
Kubernetes Service 与 kube-proxy 详解
云原生·容器·kubernetes
我不会起名字32216 小时前
节点 NotReady:kubelet 与容器运行时的 4 步排查
云原生·kubernetes·kubelet·排查
说实话起个名字真难啊17 小时前
实战docker部署dify及注意点
运维·docker·容器
闲云自留地18 小时前
K8s Service 全解:服务发现、四种类型、会话保持、金丝雀发布一篇通
容器·kubernetes·服务发现