我不会起名字322 · 后端 / 算法 / 数据库
文章目录
- [PV/PVC 一直 Pending:StorageClass 与绑定条件的 4 个检查点](#PV/PVC 一直 Pending:StorageClass 与绑定条件的 4 个检查点)
-
- [一、先看 PVC 的 Events](#一、先看 PVC 的 Events)
- [二、检查点 1:StorageClass 名字对不对](#二、检查点 1:StorageClass 名字对不对)
- [三、检查点 2:VolumeBindingMode 与 `WaitForFirstConsumer`](#三、检查点 2:VolumeBindingMode 与
WaitForFirstConsumer) - [四、检查点 3:CSI 驱动活着吗](#四、检查点 3:CSI 驱动活着吗)
- [五、检查点 4:静态 PV 的匹配条件](#五、检查点 4:静态 PV 的匹配条件)
- 六、还有一个坑:扩容
- 七、带走物
PV/PVC 一直 Pending:StorageClass 与绑定条件的 4 个检查点
一、先看 PVC 的 Events
PVC Pending 时,原因通常直接写在 Events 里:
bash
kubectl describe pvc data-mysql-0 -n <ns>
text
Events:
Type Reason Message
---- ------ -------
Normal WaitForFirstConsumer waiting for first consumer to be created before binding
或者
text
Warning ProvisioningFailed storageclass.storage.k8s.io "fast-ssd" not found
看一眼 Events,一半的问题就有答案了。 下面四个检查点按概率排序。
二、检查点 1:StorageClass 名字对不对
这是最高频的原因。
bash
# 集群里有哪些 StorageClass
kubectl get storageclass
# NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE
# standard (default) kubernetes.io/gce-pd Delete Immediate
# fast-ssd ebs.csi.aws.com Delete WaitForFirstConsumer
# PVC 里写的是哪个
kubectl get pvc data-mysql-0 -o jsonpath='{.spec.storageClassName}'
两个常见错误:
- 名字拼错 (
fast-ssd写成fastssd)→ 报storageclass not found; - 没写
storageClassName→ 会尝试用默认 StorageClass,如果集群没设默认,PVC 就一直 Pending。
bash
# 看有没有默认 SC(annotations 里有那个标记)
kubectl get storageclass -o json |
jq -r '.items[] | select(.metadata.annotations["storageclass.kubernetes.io/is-default-class"]=="true") | .metadata.name'
没有默认 SC 时 ,要么显式写 storageClassName,要么给某个 SC 打默认标记:
bash
kubectl patch storageclass standard -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
还有一个坑 :storageClassName: ""(空字符串)表示明确不用动态供给 ,只会去匹配预先创建好的、没有 class 的 PV。写错了就会 Pending。
三、检查点 2:VolumeBindingMode 与 WaitForFirstConsumer
如果 Events 里是:
text
WaitingForFirstConsumer: waiting for first consumer to be created before binding
这不是错误,这是设计。
volumeBindingMode: WaitForFirstConsumer 的含义是:先不急着创建卷,等第一个真正用它的 Pod 被调度时,再根据 Pod 所在的节点/可用区来创建。
这么设计是为了避免跨可用区:如果在不知道 Pod 会调度到哪个可用区的情况下就创建 EBS 卷,很可能创建在错误的可用区,导致 Pod 无法挂载。
所以:
text
PVC Pending + WaitForFirstConsumer = 正常,等 Pod 创建就会绑定
但如果 Pod 已经创建了,PVC 还是 Pending,那就要往下查------通常是 Pod 本身因为别的原因没调度成功(回到 Pending 那篇的排查),或者 CSI 驱动有问题。
四、检查点 3:CSI 驱动活着吗
动态供给(Dynamic Provisioning)依赖 CSI 驱动:
bash
# 看 CSI 相关的 Pod
kubectl get pod -n kube-system | grep -iE "csi|ebs|gce|nfs"
# 以 aws-ebs-csi 为例
kubectl logs -n kube-system deploy/ebs-csi-controller --tail=50
常见的失败:
- CSI 驱动没装;
- CSI controller CrashLoop(通常是 IAM 权限问题);
- CSI node plugin 在目标节点上没跑(导致卷建好了但挂不上)。
bash
# 看 PVC 相关的事件(CSI 的错误会写在这里)
kubectl get events -n <ns> --sort-by=.lastTimestamp | grep -i pvc
典型错误:
text
Failed to provision volume with StorageClass "fast-ssd":
rpc error: code = Unauthenticated desc = ...
→ 权限问题,去查 CSI 用的 ServiceAccount / IAM role。
五、检查点 4:静态 PV 的匹配条件
如果你用的是预先创建的 PV(静态供给),那么 PV 和 PVC 必须满足所有匹配条件,否则永远绑不上:
| 条件 | 说明 |
|---|---|
storageClassName |
必须一致(或都为 "") |
accessModes |
PVC 要求的模式必须是 PV 支持的子集 |
capacity |
PV 的容量 ≥ PVC 的请求 |
volumeMode |
必须一致(Filesystem / Block) |
selector(如果 PVC 有) |
PV 的 label 必须匹配 |
nodeAffinity |
某些本地卷有节点亲和性约束 |
bash
# 看 PV 的状态和条件
kubectl get pv
kubectl describe pv <pv-name>
# 对比 PVC 的要求
kubectl get pvc <pvc-name> -o yaml | grep -A 5 -E "accessModes|resources|storageClassName|selector"
最常见的两个不匹配:
1. accessModes 不匹配。
text
RWO (ReadWriteOnce) 单节点读写
ROX (ReadOnlyMany) 多节点只读
RWX (ReadWriteMany) 多节点读写 ← 很多存储类型不支持!
比如 NFS 支持 RWX,但 EBS / 本地盘只支持 RWO。如果你的 PVC 要 RWX 但只有 RWO 的 PV,就永远 Pending。
2. 容量不够。 PV 是 10Gi,PVC 要 20Gi → 不匹配。
还有一个陷阱:PV 已经被别的 PVC 绑定了 (CLAIM 列显示已被占用),那它就不能再被你用。
bash
kubectl get pv
# NAME CAPACITY CLAIM STATUS
# pv-001 10Gi default/data-mysql-0 Bound ← 已被占用
# pv-002 10Gi Available ← 可用
六、还有一个坑:扩容
K8s 支持 PVC 扩容,但有条件:
bash
# 1. StorageClass 必须允许扩容
kubectl get storageclass fast-ssd -o jsonpath='{.allowVolumeExpansion}'
# 必须是 true
# 2. 有些存储类型只支持扩容不支持缩容
# 3. 某些文件系统(如 ext4)扩容后需要 Pod 重启才能识别
yaml
allowVolumeExpansion: true
如果 allowVolumeExpansion: false,改 PVC 的 resources.requests.storage 会被拒绝。
七、带走物
排查顺序:
bash
# 1. 看 Events(最重要)
kubectl describe pvc <pvc> -n <ns>
# 2. 检查点 1:StorageClass 名字
kubectl get storageclass
kubectl get pvc <pvc> -o jsonpath='{.spec.storageClassName}'
# 3. 检查点 2:是不是正常的 WaitForFirstConsumer
# 是 → 等 Pod 创建,不是错误
# 4. 检查点 3:CSI 驱动
kubectl get pod -n kube-system | grep -i csi
kubectl logs -n kube-system deploy/<csi-controller> --tail=50
# 5. 检查点 4:静态 PV 的匹配条件
kubectl get pv
kubectl describe pv <pv> # accessModes / capacity / claim
一句话定位表:
| Events | 原因 | 动作 |
|---|---|---|
storageclass "xxx" not found |
名字写错或没装 | 改名字 / 装驱动 |
waiting for first consumer |
正常行为 | 等 Pod 创建(或 Pod 自己 Pending,去查 Pod) |
failed to provision volume + rpc error |
CSI 驱动/权限问题 | 查 CSI Pod 和日志 |
| 静态 PV:无 Events 但一直 Pending | 匹配条件不满足 | 对比 class/accessModes/capacity |
| 改容量被拒 | allowVolumeExpansion: false |
改 SC(但已有 SC 不可改,要重建) |
一句话结论:PVC Pending 先看 describe 的 Events------waiting for first consumer 是正常的,storageclass not found 是名字错了,failed to provision 是 CSI 的问题;用静态 PV 的话还要逐条对比 class、accessModes 和容量。