3、CSI架构详解:CSI规范、Node Plugin与Controller Plugin职责
Container Storage Interface(CSI)是 Kubernetes 与存储系统之间的标准接口规范。理解 CSI 架构是进行卷挂载参数调优和性能基准测试的前提。本节将深入剖析 CSI 规范的核心理念,并详细拆解 Node Plugin 与 Controller Plugin 的职责边界。
3.1 CSI 规范概述
CSI 规范定义了一组 gRPC 接口,使得存储供应商(如 EBS、Ceph、NFS)只需实现一个插件,即可被任何支持 CSI 的容器编排系统(Kubernetes、Mesos、Nomad)调用。其核心设计原则是解耦控制面与数据面:
- 控制面(Controller):负责卷的创建、删除、快照、扩容等生命周期管理操作,通常运行在 Kubernetes 控制节点上。
- 数据面(Node):负责将卷挂载到具体的工作节点,并暴露给 Pod 使用,运行在每个工作节点上。
CSI 规范将插件拆分为三个核心组件,其中两个是本节重点:
| 组件 | 身份标识 | 部署位置 | 核心职责 |
|---|---|---|---|
| Controller Plugin | CSI 控制器服务 | 控制平面(通常以 Deployment 运行) | 卷生命周期管理(创建/删除/快照/扩容)、卷拓扑感知 |
| Node Plugin | CSI 节点服务 | 每个工作节点(以 DaemonSet 运行) | 卷挂载/卸载、设备格式化、Stage/Publish 操作 |
| Identity Plugin | CSI 身份服务 | 随 Controller 或 Node 部署 | 插件信息查询、能力宣告(如是否支持卷扩容) |
关键概念: CSI 规范中,Controller Plugin 和 Node Plugin 通过 gRPC 协议与 Kubernetes 的
external-provisioner 和 node-driver-registrar 等 sidecar 容器通信,而非直接与 kubelet 交互。
3.2 Controller Plugin 职责详解
Controller Plugin 是存储系统的大脑,负责所有不涉及具体节点挂载路径的操作。它通常以 Deployment 形式部署,并具备高可用性。
3.2.1 核心 RPC 接口
Controller Plugin 必须实现以下关键 gRPC 方法:
CreateVolume:在存储后端创建指定大小的卷,并返回卷 ID 和属性。DeleteVolume:根据卷 ID 删除存储后端的卷。ControllerPublishVolume:将卷附加(Attach)到指定节点。对于块存储(如 EBS),这一步对应云 API 的 AttachVolume 操作。ControllerUnpublishVolume:将卷从节点上分离(Detach)。CreateSnapshot/DeleteSnapshot:创建和删除卷快照。ControllerExpandVolume:在线扩容卷(需 Identity Plugin 宣告支持)。
3.2.2 职责边界
| 职责 | 说明 | 性能影响 |
|---|---|---|
| 卷创建/删除 | 调用存储后端 API 分配或释放存储空间 | 高延迟操作,通常涉及网络 IO 和存储分配 |
| 卷附加/分离 | 将块设备映射到指定节点的操作系统 | 影响 Pod 调度延迟,是调优重点之一 |
| 卷拓扑管理 | 确保卷创建在 Pod 所在可用区(如 AWS AZ) | 影响调度成功率,不直接影响 IO 性能 |
| 快照管理 | 创建时间点拷贝,用于备份或恢复 | 快照创建期间可能影响卷 IO 性能 |
调优提示: Controller Plugin 的
ControllerPublishVolume 操作是卷挂载路径中的关键瓶颈。如果存储后端 API 响应慢,会导致 Pod 启动延迟。建议监控该操作的 P99 延迟,并考虑使用异步附加模式(如果存储支持)。
3.3 Node Plugin 职责详解
Node Plugin 是存储系统的双手,负责在具体的工作节点上执行卷的挂载、格式化、卸载等底层操作。它以 DaemonSet 形式运行在每个节点上,确保 kubelet 可以调用本地 CSI 节点服务。
3.3.1 核心 RPC 接口
NodeStageVolume:在节点上执行卷的全局挂载(Stage)。对于块设备,这一步通常包括:格式化(如果未格式化)、挂载到全局 staging 路径(如/var/lib/kubelet/plugins/kubernetes.io/csi/pv/<volume-id>/globalmount)。NodeUnstageVolume:卸载全局 staging 路径。NodePublishVolume:将卷从 staging 路径绑定挂载到 Pod 的容器路径。这一步创建最终的挂载点,并应用挂载参数(如mountOptions)。NodeUnpublishVolume:卸载 Pod 路径的绑定挂载。NodeGetVolumeStats:返回卷的容量使用情况(已用/可用空间)。
3.3.2 职责边界
| 职责 | 说明 | 性能影响 |
|---|---|---|
| 设备格式化 | 在 NodeStageVolume 中执行 mkfs 操作 |
格式化大容量卷(如数 TB)耗时较长 |
| 全局挂载(Stage) | 将块设备挂载到节点级 staging 目录 | 影响 Pod 启动时间,但通常较快 |
| 绑定挂载(Publish) | 将 staging 路径绑定到 Pod 的容器路径 | 极快,主要受 mount 系统调用影响 |
| 挂载参数应用 | 应用 mountOptions(如 noatime, nodelalloc) |
直接影响运行时 IO 性能,是调优核心 |
常见误区: 很多工程师误以为挂载参数调优只需修改 StorageClass 的
mountOptions 即可。实际上,Node Plugin 的 NodeStageVolume 和 NodePublishVolume 实现中,可能硬编码了某些参数,或者忽略了用户传入的参数。必须验证 CSI 驱动是否真正透传了挂载选项。
3.4 CSI 架构总览图
下图展示了 CSI 架构中 Controller Plugin 与 Node Plugin 的协作关系,以及它们与 Kubernetes 核心组件(kubelet、external-provisioner、external-attacher)的交互流程:
3.5 卷挂载流程:Controller 与 Node 的协作
一个完整的卷挂载流程(从 PVC 创建到 Pod 使用)涉及 Controller Plugin 和 Node Plugin 的紧密协作。以下是标准流程:
- 卷创建(Controller):external-provisioner 监听到 PVC 创建,调用 Controller Plugin 的
CreateVolume在存储后端创建卷。 - 卷附加(Controller):external-attacher 监听到 PV 与 Pod 的调度绑定,调用 Controller Plugin 的
ControllerPublishVolume将卷附加到目标节点。 - 节点阶段挂载(Node):kubelet 调用 Node Plugin 的
NodeStageVolume,在节点上格式化并挂载卷到全局 staging 路径。 - 节点发布挂载(Node):kubelet 调用 Node Plugin 的
NodePublishVolume,将卷从 staging 路径绑定挂载到 Pod 的容器路径,并应用挂载参数。
性能基准测试关注点: 步骤 2(ControllerPublishVolume)和步骤 3(NodeStageVolume)是卷挂载延迟的主要贡献者。步骤 4(NodePublishVolume)虽然快,但挂载参数(如
noatime、data=ordered)在此步骤生效,直接影响后续 IO 性能。
3.6 职责对比总结
| 维度 | Controller Plugin | Node Plugin |
|---|---|---|
| 部署模式 | Deployment(通常 1-3 副本) | DaemonSet(每个节点 1 副本) |
| 核心操作 | Create/Delete/Attach/Detach/Snapshot | Stage/Unstage/Publish/Unpublish |
| 与存储后端交互 | 通过管理 API(如 AWS SDK、Ceph mgr) | 通过数据路径(如 iSCSI、NFS 客户端) |
| 性能敏感度 | 影响 Pod 调度和卷创建延迟 | 影响 Pod 启动延迟和运行时 IO 性能 |
| 挂载参数控制 | 不直接控制挂载参数 | 在 NodePublishVolume 中应用挂载参数 |
| 故障域 | 控制面故障影响所有卷操作 | 单节点故障仅影响该节点 Pod |
学习路径建议: 在后续章节中,我们将重点围绕 Node Plugin 的
NodePublishVolume 进行挂载参数调优实验,并使用 fio 等工具对 Controller Plugin 的附加延迟和 Node Plugin 的挂载延迟进行基准测试。理解本节架构是后续所有调优操作的基础。