如果只运行无状态服务,Kubernetes存储问题似乎并不突出;一旦数据库、消息队列、日志系统、模型文件或研发环境进入集群,存储插件就会变成稳定性的关键环节。CSI的全称是Container Storage Interface,它不是某一种存储产品,而是一套让容器编排系统与存储厂商解耦的接口规范。对Kubernetes来说,CSI让集群可以用相对统一的方式创建卷、挂载卷、扩容卷、快照卷,并把云盘、分布式存储、本地盘等能力接入Pod生命周期。
很多排障现场会把问题简单归因于“PVC一直Pending”或“Pod挂载失败”,但真正需要判断的是:请求停在控制面,还是停在节点侧;是存储后端不可用,还是驱动注册、权限、拓扑、容量、访问模式不匹配。理解CSI机制,可以让平台团队在设计存储类、制定应用规范和处理事故时更有把握。更多Kubernetes基础能力可以结合Kubernetes容器专题持续梳理。

CSI解决的核心问题
在CSI普及之前,很多存储插件以树内插件方式内置在Kubernetes代码中。这样做的缺点很明显:存储厂商接入要跟随Kubernetes版本发布,插件修复与集群升级耦合,云厂商和企业内部存储难以快速演进。CSI把存储能力抽象为标准接口,让存储驱动以独立组件运行,Kubernetes只需要通过统一接口调用。
从平台视角看,CSI主要解决三类问题:
- 解耦:Kubernetes不再把每一种存储插件都放在核心代码里。
- 标准化:卷创建、删除、挂载、卸载、扩容等动作有清晰接口。
- 可运维:驱动组件以Pod形式运行,可独立升级、观测和回滚。
这也是容器存储从“能挂载”走向“可治理”的基础。若团队正在补齐容器运行时、镜像、网络与存储知识,可以把本文与Docker与容器基础中的内容一起理解。
CSI组件如何协作
一个典型CSI驱动通常包含控制器侧组件和节点侧组件。控制器侧负责与存储后端交互,例如创建云盘、删除卷、创建快照、处理扩容;节点侧运行在每个需要使用存储的节点上,负责把已经分配好的卷挂载到宿主机路径,再交给Pod使用。
常见组件包括:
- CSI Controller:处理卷创建、删除、扩容、快照等控制面动作。
- CSI Node:处理节点上的挂载、卸载、格式化和路径准备。
- external-provisioner:监听PVC,根据StorageClass触发卷创建。
- external-attacher:处理需要Attach的块设备绑定流程。
- external-resizer:处理PVC扩容请求。
- node-driver-registrar:把节点插件注册给kubelet。
这里容易混淆的是:Kubernetes并不会直接理解每一种存储后端的细节,它根据PV、PVC、StorageClass等对象表达需求,再由CSI侧车组件把需求转换为驱动调用。驱动再去访问云厂商API、企业存储阵列或分布式存储集群。
从PVC到Pod挂载的流程
当应用声明PVC后,Kubernetes会根据StorageClass决定是否动态创建PV。如果StorageClass使用某个CSI驱动,external-provisioner会调用控制器侧接口创建后端卷,并生成PV对象。随后调度器根据Pod、PVC和拓扑信息选择节点;如果卷需要先附着到节点,external-attacher会触发Attach流程;最后节点上的CSI Node执行挂载动作,kubelet再把卷路径注入容器。

一个简化的PVC与StorageClass配置如下:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-block
provisioner: example.com/csi-driver
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-volume
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-block
resources:
requests:
storage: 100Gi
这里有两个字段尤其重要。allowVolumeExpansion决定PVC是否允许扩容;volumeBindingMode: WaitForFirstConsumer会等Pod出现并参与调度后再绑定卷,适合有可用区、机架或节点拓扑限制的存储。很多跨可用区挂载失败,本质上是卷先创建在错误区域,再被Pod调度到不兼容节点。
设计StorageClass时看哪些维度
StorageClass不是简单命名,它会影响成本、性能和可用性。平台团队至少需要明确以下维度:
| 维度 | 需要确认的问题 | 常见风险 |
|---|---|---|
| — | — | — |
| 性能 | IOPS、吞吐、延迟是否满足业务 | 数据库使用低性能盘导致抖动 |
| 访问模式 | 是否支持单节点读写或多节点读写 | 多副本Pod误用ReadWriteOnce |
| 拓扑 | 卷是否受可用区、机架、节点限制 | Pod与卷不在同一拓扑域 |
| 扩容 | 是否支持在线扩容 | 扩容后文件系统未生效 |
| 回收 | 删除PVC后卷是保留还是删除 | 误删数据或遗留成本 |
对生产集群,建议把StorageClass分为默认类、性能类、共享类、归档类,而不是所有工作负载共用一个默认存储。默认类应服务于普通应用,数据库和中间件要显式选择更合适的存储类。
CSI常见故障怎么定位
CSI故障要按链路分段,而不是只看Pod事件。第一步看PVC状态,判断是否完成绑定;第二步看PV和StorageClass,确认驱动名称、容量、访问模式、回收策略;第三步看控制器组件日志,确认后端卷是否创建;第四步看节点插件和kubelet日志,判断是否卡在Attach、Mount或文件系统处理。

常用命令包括:
kubectl describe pvc data-volume
kubectl get pv
kubectl describe pod app-0
kubectl get pods -n kube-system | grep csi
kubectl logs -n kube-system deploy/csi-controller -c csi-provisioner
如果PVC长时间Pending,优先检查StorageClass是否存在、provisioner名称是否匹配、存储配额是否耗尽、拓扑约束是否与节点匹配。如果Pod卡在ContainerCreating,重点查看Pod事件中是否有MountVolume、AttachVolume相关错误,再检查对应节点上的CSI Node Pod。若同一个节点多个Pod都挂载失败,问题更可能在节点插件、内核模块、挂载工具或宿主机路径。
生产实践建议
生产环境不要只关注“CSI驱动能安装成功”。更重要的是形成标准:驱动版本与Kubernetes版本要有兼容矩阵;StorageClass命名要能体现性能和用途;重要PVC要有备份、快照和恢复演练;监控中要纳入PVC Pending数量、挂载失败次数、卷扩容失败、存储后端容量和延迟。
对于有状态应用,还应把副本调度、PodDisruptionBudget、节点维护流程和存储拓扑一起设计。单独把数据库Pod做成多副本,并不等于获得高可用;如果底层卷只能在单可用区读写,调度策略必须尊重这一事实。容器存储的成熟度,最终体现为故障发生时能否快速判断边界、保护数据并恢复服务。
小结
CSI是什么?它是Kubernetes连接外部存储系统的标准插件机制。它把卷创建、挂载、扩容和快照等动作从Kubernetes核心代码中拆出来,让不同存储后端以统一方式接入集群。理解CSI,不只是记住几个组件名,而是掌握PVC、PV、StorageClass、控制器插件、节点插件和存储后端之间的协作关系。对于运行数据库、中间件、日志、AI数据集和企业应用的集群,CSI是必须纳入架构设计和日常运维的关键能力。
常见问题
CSI 和 StorageClass 是什么关系?
CSI 是 Kubernetes 对接外部存储系统的插件接口,StorageClass 则是用户声明动态供给参数的资源对象。StorageClass 通常引用某个 CSI provisioner,由它完成卷创建、挂载、扩容等操作。
CSI 故障会影响已经运行的 Pod 吗?
取决于故障位置。控制器故障可能影响新卷创建和扩容,节点插件故障可能影响挂载、卸载和新 Pod 启动。已挂载并正常读写的卷可能短期不受影响,但故障恢复和节点迁移会存在风险。
排查 CSI 问题为什么要同时看 Kubernetes 和存储后端?
因为 CSI 是连接层,错误可能来自 PVC、StorageClass、CSI 控制器、节点插件、云盘或存储阵列权限与配额。只看 Kubernetes 事件可能看到的是表层失败,真正根因可能在存储后端。
转载请注明出处:https://www.cloudnative-tech.com/p/7379/