实验基线:Kubernetes v1.37.0、kubectl v1.37.0。先在测试环境执行,记录变更前状态与回滚点;生产集群不得直接照抄节点地址、网段、存储类或资源额度。
四层模型
- Pod volume 描述容器如何挂载。
- PVC 表达应用对容量和访问模式的请求。
- PV 表示集群中的实际存储。
- StorageClass 通过 CSI 驱动定义动态供应参数与回收策略。
hostPath只适合单节点测试,不能当作多节点持久化方案。
动态供应示例
apiVersion: v1
kind: PersistentVolumeClaim
metadata: {name: data, namespace: lab}
spec:
accessModes: [ReadWriteOnce]
storageClassName: standard
resources:
requests: {storage: 1Gi}kubectl apply -f pvc.yaml
kubectl get pvc,pv -n lab
kubectl describe pvc data -n lab
kubectl get storageclass
kubectl get csidriverPVC Pending 时检查 StorageClass 名称、默认类、CSI 控制器、拓扑限制和事件。对有拓扑约束的存储,StorageClass 通常应使用 volumeBindingMode: WaitForFirstConsumer,避免卷先建到错误可用区。
扩容、回收与恢复
扩容前确认 StorageClass 的 allowVolumeExpansion及驱动能力;只增大请求,不要缩小。删除 PVC 前检查 PV 的 persistentVolumeReclaimPolicy:Delete 可能同时删除后端卷,Retain 需要人工回收。快照依赖 CSI Snapshot CRD 与控制器,创建后必须做一次“新 PVC 恢复—挂载—校验文件哈希”的演练,只有快照对象 Ready 不能证明可恢复。
从 PVC 到 Pod 的完整实验
apiVersion: v1
kind: Pod
metadata: {name: writer, namespace: lab}
spec:
containers:
- name: writer
image: busybox:1.36
command: ["sh","-c","date >> /data/history; sleep 3600"]
volumeMounts: [{name: data, mountPath: /data}]
volumes:
- name: data
persistentVolumeClaim: {claimName: data}kubectl apply -f pvc.yaml
kubectl apply -f writer.yaml
kubectl wait -n lab --for=condition=Ready pod/writer --timeout=120s
kubectl exec -n lab writer -- cat /data/history
kubectl delete pod writer -n lab
kubectl apply -f writer.yaml
kubectl exec -n lab writer -- cat /data/history重建 Pod 后文件仍存在,才验证了持久化基本语义。再检查 PVC 绑定的 PV、StorageClass、CSI 驱动和节点拓扑。
访问模式不是并发锁
RWO 表示卷可由单个节点读写,并不保证只有一个 Pod;同一节点上的多个 Pod 仍可能访问。RWOP 才是单 Pod 读写语义,但需要驱动支持。应用自身仍需处理文件锁、数据库一致性和故障恢复。
扩容操作
- 确认 StorageClass
allowVolumeExpansion: true。 - 确认 CSI 驱动支持控制面与文件系统扩容。
- 备份关键数据。
- 仅增大 PVC requests.storage。
- 观察 PVC conditions、事件和文件系统容量。
kubectl patch pvc data -n lab --type=merge -p '{"spec":{"resources":{"requests":{"storage":"2Gi"}}}}'
kubectl get pvc data -n lab -w
kubectl describe pvc data -n lab
kubectl exec -n lab writer -- df -h /data
快照恢复验收
VolumeSnapshot 依赖集群安装 snapshot CRD、snapshot-controller 和驱动支持。快照 ReadyToUse 后,用它创建新的 PVC,挂载到新的校验 Pod,比较文件数量、数据库一致性和哈希;不要在原卷上直接做“恢复测试”。删除测试对象前核对 snapshot content 的删除策略。
删除前四问
- PV reclaimPolicy 是 Delete 还是 Retain?
- 后端存储是否还有独立快照?
- StatefulSet 缩容/删除是否会保留 PVC?
- 恢复演练是否在目标 RTO 内成功?
静态 PV 只用于理解绑定
apiVersion: v1
kind: PersistentVolume
metadata: {name: lab-local-pv}
spec:
capacity: {storage: 1Gi}
volumeMode: Filesystem
accessModes: [ReadWriteOnce]
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
local: {path: /mnt/lab-data}
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions: [{key: kubernetes.io/hostname, operator: In, values: [replace-node]}]local 卷必须绑定节点且不会动态供应;节点永久损坏时数据不可迁移。生产优先使用满足故障域、性能、加密和快照要求的 CSI 存储。
快照清单与恢复链
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata: {name: data-snapshot, namespace: lab}
spec:
volumeSnapshotClassName: replace-snapshot-class
source: {persistentVolumeClaimName: data}- 等待
readyToUse: true并记录 boundVolumeSnapshotContentName。 - 创建 dataSource 指向快照的新 PVC。
- 挂载到只读校验 Pod。
- 比较业务层记录数、校验和与时间点。
- 记录恢复耗时,再删除测试副本。
备份矩阵
| 对象 | 方法 | 不能替代 |
|---|---|---|
| Kubernetes 对象 | etcd/资源清单备份 | PV 业务数据 |
| 块/文件卷 | CSI/存储快照 | 应用一致性 |
| 数据库 | 原生逻辑/物理备份 | 集群配置 |
数据库快照前应按产品要求冻结写入或使用一致性能力,否则“成功快照”仍可能无法恢复。
可复现记录模板
每次实验记录:集群版本、容器运行时、CNI/CSI 版本、命名空间、使用的 YAML Git 提交、开始与结束时间。命令输出至少保留对象状态、事件、关键日志和回滚结果。文中的占位符必须替换成自己的值,生产执行前应由第二人复核。
故障处理原则
- 先缩小影响面,不删除现场。
- 按对象状态—事件—日志—依赖顺序收集证据。
- 提出可证伪假设,一次只改变一个变量。
- 验证恢复后清理临时权限、调试 Pod、端口转发和测试数据。
完成检查
- 命令退出码为 0,目标对象状态与预期一致。
- 保存执行前后 YAML、事件与关键日志,确认没有把测试命名空间以外的对象改动。
- 故障演练完成后执行清理或回滚,再进行下一章。