
在前一篇《第 7 天:存储管理——PV、PVC 与持久化存储》中,我们学习了 PV 和 PVC 的基本用法,那套”管理员手动创建 PV、用户声明 PVC”的静态供给模式,对于生产环境来说效率太低。随着集群规模扩大、有状态应用越来越多,我们需要一套能够按需自动创建存储、支持多种后端、并且具备备份恢复能力的完整存储方案。本文就深入讲解 Kubernetes 存储进阶的核心:CSI 容器存储接口、StorageClass 动态供给,以及基于 Velero 的备份恢复实战。
CSI:统一容器存储接口
在 CSI(Container Storage Interface)出现之前,Kubernetes 的存储是通过 in-tree 卷插件(如 awsElasticBlockStore、glusterfs 等)直接集成在核心代码中的。这种方式的弊端很明显:每新增一种存储后端,都要修改 Kubernetes 主仓库代码,并跟随发版周期,存储厂商的迭代速度被严重拖慢。
CSI 的设计目标,是把存储能力的实现从 Kubernetes 核心中剥离出来,通过一套标准化的 gRPC 接口,让存储厂商可以独立开发、发布和升级自己的驱动。CSI 规范定义了三个核心 gRPC 服务:
- Identity Service:标识驱动信息,返回插件的名称、版本和能力。
- Controller Service:负责卷的创建、删除、快照、扩容等编排操作,通常在集群中以 Deployment 形式运行。
- Node Service:负责把卷挂载到具体节点的 Pod 上,以 DaemonSet 形式运行在每个节点。
一个典型的 CSI 驱动部署包含以下组件:
# CSI 驱动控制器 Deployment 的核心结构(示例)
apiVersion: apps/v1
kind: Deployment
metadata:
name: csi-example-controller
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: csi-example-controller
template:
metadata:
labels:
app: csi-example-controller
spec:
serviceAccountName: csi-example-controller-sa
containers:
- name: csi-provisioner
image: registry.k8s.io/sig-storage/csi-provisioner:v3.6.0
- name: csi-attacher
image: registry.k8s.io/sig-storage/csi-attacher:v4.4.0
- name: csi-driver
image: example/csi-driver:v1.0.0
StorageClass 与动态供给
静态供给需要管理员预先创建 PV,一旦 PVC 的存储需求五花八门,管理成本会急剧上升。动态供给(Dynamic Provisioning)则彻底解决了这个问题:用户只需要声明 PVC,集群会根据 StorageClass 的定义,自动向存储后端申请并创建对应的 PV。
StorageClass 本质上是”存储的模板”,它定义了使用的 provisioner(通常是某个 CSI 驱动)、回收策略、以及给后端传递的参数。
# 定义一个使用 CSI 驱动的 StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: example.csi.k8s.io
parameters:
type: ssd
csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
其中几个关键字段值得注意:
reclaimPolicy:删除 PVC 时卷的处理方式,Delete会同步删除后端卷,Retain则保留数据供人工处理。allowVolumeExpansion:是否允许对已创建的卷进行在线扩容。volumeBindingMode:WaitForFirstConsumer会等到 Pod 真正调度到节点后再创建卷,从而让卷和 Pod 落在同一可用区,避免跨区挂载失败。
声明 PVC 时,只要指定 storageClassName,集群就会自动完成从创建到绑定的全过程:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
storageClassName: fast-ssd
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
# 查看 PVC 是否自动绑定到动态创建的 PV
kubectl get pvc app-data
# 查看对应的 StorageClass 与动态生成的 PV
kubectl get sc
kubectl get pv
卷扩容与快照
有了 CSI 和 StorageClass 的支持,卷扩容和快照也变成了声明式操作,不再需要登录到存储后端手动操作。
当 PVC 使用空间不足时,只要 StorageClass 开启了 allowVolumeExpansion,就可以直接修改 PVC 的容量申请:
# 将 PVC 从 10Gi 扩容到 20Gi
kubectl patch pvc app-data -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'
卷快照则依赖 VolumeSnapshotClass 和 VolumeSnapshot 两个资源对象,可以快速为数据创建一致性快照:
# 创建卷快照
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: app-data-snapshot
spec:
volumeSnapshotClassName: csi-snapshot-class
source:
persistentVolumeClaimName: app-data
Velero:集群备份与恢复
对于生产环境来说,仅有卷快照还不够。一次完整的灾难恢复,除了数据卷,还需要恢复应用的部署清单、配置、Service 等元数据。Velero 正是解决这一问题的利器——它能够备份整个命名空间甚至整个集群的资源对象,并联动 CSI 快照能力备份持久化数据。
Velero 的典型工作流如下:
# 1. 安装 Velero(以 minio 作为对象存储为例)
velero install
--provider aws
--plugins velero/velero-plugin-for-aws:v1.8.0
--bucket velero
--secret-file ./credentials-velero
--use-volume-snapshots=false
--backup-location-config region=minio,s3ForcePathStyle=true,s3Url=http://minio:9000
# 2. 备份一个命名空间
velero backup create app-backup --include-namespaces app
# 3. 查看备份状态
velero backup get
velero backup describe app-backup
# 4. 模拟灾难后恢复
velero restore create --from-backup app-backup
Velero 支持定时备份(Schedule),可以按 cron 表达式周期性执行备份,配合对象存储实现异地容灾,是 K8s 生产环境存储备份恢复的事实标准。
常见问题
Q1:动态供给失败了,PVC 一直处于 Pending 状态怎么办?
首先用 kubectl describe pvc <名称> 查看事件。常见原因有:StorageClass 的 provisioner 对应的 CSI 驱动没有安装或未就绪、后端存储配额不足、WaitForFirstConsumer 模式下没有 Pod 使用该 PVC 导致卷尚未创建等。逐项排查事件信息即可定位。
Q2:reclaimPolicy 的 Delete 和 Retain 该怎么选?
Delete 适合临时数据、测试环境,删 PVC 即释放后端存储,节省成本;Retain 适合重要数据,删除 PVC 后 PV 和数据依然保留,但需要管理员手动清理,否则会产生”孤儿”卷。
Q3:快照和备份有什么区别?
快照通常是存储后端的低成本副本,恢复快但往往只覆盖数据卷,且受限于同一存储系统;Velero 备份则包含资源对象元数据,可以跨集群、跨存储系统恢复,粒度更完整,适合灾难恢复场景。
总结
本文从 CSI 接口出发,梳理了 Kubernetes 存储进阶的三块核心拼图:CSI 让存储驱动标准化、可插拔,StorageClass 让卷供给自动化、声明式,Velero 让集群数据可备份、可恢复。掌握了这套体系,你就能为有状态应用在 K8s 上构建出弹性、可靠且易运维的存储底座。对于生产环境,建议把动态供给 + 定时备份作为默认配置,未雨绸缪永远比亡羊补牢更从容。
下期预告:第 19 天我们将进入流量治理——Ingress Controller 与 Gateway API,看看如何优雅地把集群内部服务对外暴露并精细管控流量。


















暂无评论内容