4、CSI存储插件架构:CSI规范概述、CSI Driver组件分解(Identity/Controller/Node)、CSI与Kubelet交互流程
4.1 CSI规范概述
Container Storage Interface(CSI)是CNCF定义的行业标准接口,旨在使存储供应商(如Ceph、NFS、云厂商块存储)能够以统一的插件形式接入Kubernetes。CSI规范将存储生命周期管理从Kubernetes核心代码中解耦,使得存储驱动的开发、部署和升级不再依赖Kubernetes版本发布周期。
- 声明式接口:Kubernetes通过gRPC调用CSI Driver,完成卷的创建、挂载、卸载、删除等操作。
- 三组件分离:Identity、Controller、Node三个独立gRPC服务,分别负责身份认证、控制面操作、节点本地操作。
- 无状态与可插拔:CSI Driver以DaemonSet或Deployment形式运行,不修改Kubernetes核心二进制。
CSI规范定义了三个主要的gRPC服务接口,每个接口包含一组RPC方法。下表列出了各服务的关键方法及其用途:
| gRPC服务 | 关键RPC方法 | 用途说明 |
|---|---|---|
| Identity | GetPluginInfo |
返回Driver名称、版本、供应商信息 |
GetPluginCapabilities |
声明Driver支持的能力(如卷扩展、快照、拓扑感知) | |
Probe |
健康检查,确认Driver是否正常运行 | |
| Controller | CreateVolume |
在存储后端创建卷(如云盘、Ceph RBD image) |
DeleteVolume |
删除存储后端的卷 | |
ControllerPublishVolume |
将卷挂载到指定节点(如附加云盘到虚拟机) | |
ControllerUnpublishVolume |
从节点卸载卷 | |
ListVolumes |
列出存储后端所有卷 | |
CreateSnapshot |
创建卷的快照 | |
DeleteSnapshot |
删除快照 | |
| Node | NodeStageVolume |
在节点上准备卷设备(如挂载到全局目录) |
NodePublishVolume |
将卷挂载到Pod的指定路径 | |
NodeUnpublishVolume |
从Pod路径卸载卷 | |
NodeUnstageVolume |
清理节点上的卷设备 | |
NodeGetCapabilities |
返回节点服务支持的能力 |
4.2 CSI Driver组件分解:Identity / Controller / Node
一个完整的CSI Driver由三个独立的gRPC服务组件构成,它们通常运行在同一个Pod中,但通过不同的Unix Socket或端口暴露。这种分离设计使得控制面操作(如创建卷)与数据面操作(如挂载卷)可以独立扩展和升级。
4.2.1 Identity服务
Identity服务是所有CSI Driver必须实现的基础服务。它负责向Kubernetes(或外部编排器)报告Driver的身份信息、能力集和健康状态。Kubernetes的kubelet和external-provisioner等sidecar容器会在启动时调用GetPluginInfo和GetPluginCapabilities来验证Driver的兼容性。
4.2.2 Controller服务
Controller服务运行在控制面,负责与存储后端API交互,执行卷的生命周期管理操作。它通常不直接接触节点上的设备文件。Kubernetes通过external-provisioner、external-attacher等sidecar容器将PVC/PV的变化转换为对Controller服务的gRPC调用。
4.2.3 Node服务
Node服务运行在每个Kubernetes节点上,负责执行卷在节点本地的挂载操作。它直接操作设备文件、文件系统挂载点、符号链接等。kubelet通过Unix Socket与Node服务通信,完成Pod的卷挂载和卸载。
4.3 CSI与Kubelet交互流程
当Pod被调度到某个节点后,kubelet负责将Pod中声明的CSI卷挂载到容器内。整个交互流程分为三个阶段:Stage(阶段挂载)、Publish(发布挂载)、Unpublish/Unstage(卸载清理)。
4.3.1 挂载流程(Stage & Publish)
- kubelet调用NodeStageVolume:kubelet通过Unix Socket向CSI Node服务发送
NodeStageVolume请求,包含卷ID、挂载参数、访问模式等。Node服务将卷设备挂载到节点的全局 staging 路径(如/var/lib/kubelet/plugins/kubernetes.io/csi/pv/{pvname}/globalmount)。 - kubelet调用NodePublishVolume:Stage完成后,kubelet调用
NodePublishVolume,将卷从 staging 路径绑定挂载到Pod的特定路径(如/var/lib/kubelet/pods/{podUID}/volumes/kubernetes.io~csi/{volname}/mount)。 - 容器启动:kubelet将Pod的卷挂载路径映射到容器内,启动容器。
4.3.2 卸载流程(Unpublish & Unstage)
- kubelet调用NodeUnpublishVolume:Pod删除或迁移时,kubelet先调用
NodeUnpublishVolume,解除Pod路径上的绑定挂载。 - kubelet调用NodeUnstageVolume:Unpublish完成后,kubelet调用
NodeUnstageVolume,从全局 staging 路径卸载卷设备。 - 清理:如果卷不再被任何Pod使用,kubelet可能触发Controller服务的
ControllerUnpublishVolume和DeleteVolume。
- kubelet与CSI Node服务之间的通信通过Unix Socket进行,Socket文件通常位于
/var/lib/kubelet/plugins/{drivername}/csi.sock。 - Stage和Publish的分离设计允许同一个卷被多个Pod共享(如ReadWriteMany),只需一次Stage,多次Publish。
- 如果CSI Driver不支持
NodeStageVolume(通过NodeGetCapabilities声明),kubelet会跳过Stage阶段,直接调用Publish。
4.4 总结与最佳实践
- CSI规范通过Identity、Controller、Node三个gRPC服务实现存储插件的标准化,使得存储供应商可以独立开发驱动。
- Controller服务运行在控制面,负责卷的创建/删除/附加/快照等操作;Node服务运行在每个节点,负责卷的本地挂载/卸载。
- kubelet通过Unix Socket与CSI Node服务交互,执行Stage→Publish的挂载流程,以及Unpublish→Unstage的卸载流程。
- Stage和Publish的分离设计是CSI实现卷共享和高性能挂载的关键。
- 始终使用官方或经过CNCF认证的CSI Driver,避免使用已废弃的in-tree卷插件。
- 为CSI Driver的Controller组件配置合适的资源限制和健康检查,避免控制面操作超时。
- 监控CSI Node服务的Socket文件状态,确保kubelet与Driver之间的通信畅通。
- 在部署CSI Driver时,仔细阅读供应商文档,确认其支持的CSI能力(如卷扩展、拓扑约束、快照等)。