2. CSI 架构解析:三大组件的职责划分

Container Storage Interface (CSI) 是 Kubernetes 与存储后端之间的标准插件接口。CSI 规范将存储插件的逻辑拆分为三个独立的 gRPC 服务:Controller Plugin、Node Plugin 和 Identity Service。这种拆分使得控制面操作与数据面操作可以独立部署、独立升级,并适配不同的 Kubernetes 调度与运行环境。

2.1 整体架构概览

下图展示了 CSI 插件在 Kubernetes 集群中的部署位置与通信关系。Controller Plugin 通常以 Deployment 形式运行在控制节点上,Node Plugin 以 DaemonSet 形式运行在每个工作节点上,Identity Service 则作为公共接口嵌入在两个 Plugin 中。

CSI 整体架构:三大组件与通信关系 Kubernetes 控制面 kube-controller-manager external-provisioner external-attacher external-resizer external-snapshotter Controller Plugin gRPC Server (Unix Socket) CreateVolume DeleteVolume ControllerPublishVolume ControllerUnpublishVolume CreateSnapshot / DeleteSnapshot 存储后端 SAN / NAS 分布式存储 云存储 API 本地存储 gRPC 调用 存储 API Node Plugin gRPC Server (Unix Socket) NodePublishVolume NodeUnpublishVolume NodeGetVolumeStats kubelet Pod 生命周期管理 VolumeManager Mount/Unmount 操作 gRPC 调用 挂载/卸载 Identity Service:嵌入 Controller & Node Plugin 中
关键设计原则:Controller Plugin 与 Node Plugin 通过 Unix Domain Socket 与 Kubernetes 组件通信,不依赖网络 TCP 连接,降低了安全风险与网络故障面。Identity Service 为两个 Plugin 提供统一的元数据查询能力。

2.2 三大组件职责详解

组件 部署方式 核心 RPC 接口 职责描述
Controller Plugin Deployment(通常 1~2 副本) CreateVolume, DeleteVolume, ControllerPublishVolume, ControllerUnpublishVolume, CreateSnapshot, DeleteSnapshot, ListVolumes 负责存储卷的生命周期管理:创建、删除、挂载到节点、快照等控制面操作。与存储后端 API 直接交互。
Node Plugin DaemonSet(每个节点 1 副本) NodePublishVolume, NodeUnpublishVolume, NodeGetVolumeStats, NodeExpandVolume 负责节点级别的卷挂载、卸载、统计信息收集。操作本地文件系统和设备。
Identity Service 嵌入 Controller 和 Node Plugin 中 GetPluginInfo, GetPluginCapabilities, Probe 提供插件元数据:名称、版本、支持的能力集、健康检查。Kubernetes 通过 Probe 判断插件是否存活。

2.3 Controller Plugin 深度解析

Controller Plugin 是 CSI 架构中的“大脑”,负责所有控制面操作。它通过 gRPC 接口接收来自 Kubernetes 外部控制器(external-provisioner、external-attacher 等)的请求,然后调用存储后端的 API 完成实际操作。

2.3.1 核心接口与调用流程

  • CreateVolume / DeleteVolume:创建和删除存储卷。external-provisioner 监听 PVC 对象,当发现新的 PVC 时调用 CreateVolume,将返回的 VolumeId 绑定到 PV 上。
  • ControllerPublishVolume / ControllerUnpublishVolume:将卷挂载到指定节点(例如:将云硬盘挂载到云主机)。external-attacher 负责调用此接口。
  • CreateSnapshot / DeleteSnapshot:创建和删除卷快照。external-snapshotter 负责调用。
  • ListVolumes / ControllerExpandVolume:卷列表查询和在线扩容。
适配要点:移植 CSI 驱动时,Controller Plugin 需要实现存储后端的所有控制面 API。如果后端不支持快照,则应在 GetPluginCapabilities 中声明不支持,Kubernetes 将自动禁用快照功能。

2.4 Node Plugin 深度解析

Node Plugin 运行在每个 Kubernetes 工作节点上,负责将存储卷挂载到 Pod 的文件系统。它直接与 kubelet 交互,kubelet 在 Pod 调度到节点后调用 Node Plugin 完成挂载操作。

2.4.1 核心接口与调用流程

  • NodePublishVolume:将卷挂载到 Pod 的挂载路径。kubelet 在 Pod 启动前调用此接口,传入目标路径和挂载选项。
  • NodeUnpublishVolume:卸载卷。Pod 删除时 kubelet 调用此接口。
  • NodeGetVolumeStats:返回卷的容量使用情况(已用空间、总空间等)。kubelet 定期调用以更新 PV 的指标。
  • NodeExpandVolume:节点级别的卷扩容(文件系统扩展)。

2.4.2 挂载流程示例

// NodePublishVolume 典型实现步骤
1. 检查目标挂载路径是否存在,不存在则创建
2. 根据 volume_context 获取存储后端连接信息
3. 调用存储后端 API 或系统命令挂载设备
   - 块存储:mount /dev/sdb /var/lib/kubelet/pods/xxx/volumes/...
   - 文件存储:mount -t nfs 192.168.1.100:/share /var/lib/kubelet/...
4. 设置挂载选项(只读、noexec 等)
5. 返回成功状态给 kubelet
常见陷阱:Node Plugin 必须处理节点重启后的卷状态恢复。如果节点异常重启,kubelet 会重新调用 NodePublishVolume,插件需要能够识别已挂载的设备并返回成功,而不是重复挂载导致错误。

2.5 Identity Service 深度解析

Identity Service 是 CSI 插件的基础元数据服务,必须同时嵌入 Controller Plugin 和 Node Plugin 中。Kubernetes 在注册 CSI 驱动时首先调用 Identity Service 获取插件信息。

2.5.1 核心接口

RPC 接口 返回值 用途
GetPluginInfo name, vendor_version, manifest Kubernetes 通过此接口获取插件名称和版本,用于注册和日志标识。
GetPluginCapabilities 支持的能力列表(Controller, Node, VolumeExpansion, Snapshot 等) Kubernetes 根据能力列表决定启用哪些外部控制器。例如不支持 Snapshot 则不会启动 external-snapshotter。
Probe ready 状态 健康检查接口。Kubernetes 定期调用,如果返回 not ready 则标记插件不可用。

2.6 组件间通信机制

CSI 插件与 Kubernetes 组件之间通过 gRPC over Unix Domain Socket 进行通信。每个 Plugin 启动时监听一个 Unix Socket 文件,Kubernetes 组件通过该 Socket 调用 RPC 接口。

CSI 组件间通信机制:gRPC over Unix Domain Socket kubelet gRPC 客户端 Unix Socket 连接 Unix Domain Socket /var/lib/kubelet/plugins/ csi-xxx/csi.sock 仅本地进程间通信,无网络开销 Node Plugin gRPC 服务端 Unix Socket 监听 通信安全与隔离机制 • Socket 文件权限:仅 root 和 kubelet 用户可访问 • 不经过网络栈,避免 TCP 攻击面 • 每个 CSI 驱动使用独立的 Socket 路径,互不干扰

2.7 组件职责对比总结

对比维度 Controller Plugin Node Plugin Identity Service
运行位置 控制节点(可调度到任意节点) 每个工作节点 嵌入 Controller 和 Node Plugin
与谁通信 external-provisioner/attacher/resizer/snapshotter kubelet Kubernetes CSI 注册机制
操作对象 存储后端 API(创建/删除卷) 本地文件系统和设备(挂载/卸载) 插件自身元数据
故障影响 无法创建/删除卷,已有卷不受影响 该节点无法挂载/卸载卷 插件无法注册,Kubernetes 拒绝使用
移植工作量 高(需对接存储后端 API) 中(需处理本地挂载逻辑) 低(固定模板,少量配置)
移植建议:开始移植 CSI 驱动时,建议先实现 Identity Service 和 Probe 接口,确保插件能被 Kubernetes 识别。然后实现 Node Plugin 的 NodePublishVolume/NodeUnpublishVolume,使 Pod 能够挂载卷。最后实现 Controller Plugin 的完整控制面逻辑。这种渐进式开发方式可以尽早验证插件的基本可用性。