在 kind 集群里用没有供应器的 StorageClass 复现 PVC Pending,再用静态 PV 修复

演练目标

环境准备

安装 Docker、kind 和 kubectl,kind 版本需支持 hostPath PV(默认都支持)。

kind create cluster --name lab-pvc
kubectl get nodes
kubectl get storageclass
kubectl create namespace lab-pvc
kubectl config set-context --current --namespace=lab-pvc

kind 默认不一定有可用的默认 StorageClass,这正好避免实验被自动供应器“修好”。

注入故障

创建一个没有对应供应器的 StorageClass,以及引用它的 PVC:

kubectl apply -f - <<'EOF'
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: lab-static
provisioner: example.com/no-provisioner
volumeBindingMode: Immediate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: lab-pvc
spec:
  accessModes: ["ReadWriteOnce"]
  storageClassName: lab-static
  resources:
    requests:
      storage: 1Gi
EOF

观察现象

kubectl get pvc lab-pvc
kubectl describe pvc lab-pvc | sed -n '/Events:/,$p'
kubectl get storageclass lab-static -o yaml
kubectl get pv
kubectl get events --sort-by=.lastTimestamp | tail -20

预期 PVC 状态为 Pending,describe 的 Events 显示等待外部供应器创建卷,例如 waiting for a volume to be created, either by external provisioner "example.com/no-provisioner" or manually created by system administrator;PV 列表为空,因为没有匹配的卷。

判断与定位

  1. PVC Pending 时先看 describe pvc 的 Events,它通常会直接指出“没有供应器”“没有匹配 PV”或“容量不足”。
  2. 检查 StorageClass 是否存在、是否是默认类、provisioner 是否有对应控制器运行。
  3. 检查 PVC 的容量、accessModes 和 storageClassName 是否与现有 PV 匹配。
  4. 容易误判:volumeBindingMode: WaitForFirstConsumer 下,PVC 在 Pod 调度前 Pending 是正常设计,不是故障;只要创建使用该 PVC 的 Pod,绑定就会继续。另一个误判是 storageClassName: "",它表示禁用动态供应,只绑定显式空 class 的 PV。
  5. PVC 的 storageClassName 创建后通常不可修改,写错后需要删除重建。

修复

手工创建一个匹配的静态 PV,让 PVC 完成绑定:

kubectl apply -f - <<'EOF'
apiVersion: v1
kind: PersistentVolume
metadata:
  name: lab-pv
spec:
  capacity:
    storage: 1Gi
  accessModes: ["ReadWriteOnce"]
  storageClassName: lab-static
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /tmp/lab-pv
    type: DirectoryOrCreate
EOF
kubectl get pv lab-pv
kubectl get pvc lab-pvc

两者都应显示 Bound,表示静态绑定完成。需要挂载时,再创建引用该 PVC 的 Pod;hostPath 只适合本地实验,生产应使用 CSI 和真实存储后端。

清理与回滚

kubectl delete pvc lab-pvc --ignore-not-found
kubectl delete pv lab-pv --ignore-not-found
kubectl delete storageclass lab-static --ignore-not-found
kubectl delete namespace lab-pvc --ignore-not-found
kind delete cluster --name lab-pvc

先删 Pod 和 PVC,再删 PV,最后删 StorageClass。Retain 策略下 PV 删除后底层数据仍可能保留,本实验的 hostPath 会随 kind 节点一起删除。

复盘

延伸阅读

读完自测

  1. WaitForFirstConsumer 模式下 PVC 一直 Pending,是否一定是故障?
  2. 静态 PV 要与 PVC 绑定,哪些字段必须匹配?
  3. 为什么 storageClassName: "" 的 PVC 不会走动态供应?
答案
  1. 不一定。没有 Pod 使用该 PVC 时,等待首个消费者是预期行为。
  2. 容量不小于请求、accessModes 兼容、storageClassName 一致,且 PV 处于 Available 状态。
  3. 空字符串显式表示不使用 StorageClass,只匹配同样没有 class 的 PV,因此不会触发动态供应。