2. CSI 架构总览:三大核心组件及其职责
Container Storage Interface (CSI) 是 Kubernetes 与外部存储系统之间的标准插件接口。理解 CSI 的架构是进行多集群存储调优的基础。CSI 规范将存储插件的职责拆分为三个独立的组件:Controller Plugin、Node Plugin 和 Sidecar Container。这种解耦设计使得存储插件的开发、部署和升级更加灵活,且不影响集群核心组件。
2.1 三大核心组件职责对比
| 组件 | 部署位置 | 核心 gRPC 服务 | 主要职责 | 生命周期 |
|---|---|---|---|---|
| Controller Plugin | 任意节点(通常作为 Deployment 运行) | ControllerServer |
卷的创建/删除、快照、克隆、扩容、发布/取消发布到节点 | 集群级别,全局唯一或少量副本 |
| Node Plugin | 每个工作节点(作为 DaemonSet 运行) | NodeServer |
卷的挂载/卸载、格式化、分区、设备发现、节点级统计 | 节点级别,每节点一个实例 |
| Sidecar Container | 与 Controller/Node Plugin 同 Pod | 无(调用 Kubernetes API) | 监听 Kubernetes 资源事件、调用 CSI 驱动、管理卷生命周期 | 与主容器同生命周期 |
2.2 Controller Plugin:控制面的核心
Controller Plugin 负责所有不需要直接访问节点存储设备的操作。它通常以 Deployment 形式部署,具有集群范围的视图。其核心接口定义在 csi.ControllerServer gRPC 服务中。
- 卷管理:
CreateVolume/DeleteVolume— 在后端存储系统(如 Ceph、NFS、云盘)上实际分配或释放存储资源。 - 卷发布:
ControllerPublishVolume/ControllerUnpublishVolume— 将卷附加(attach)到指定节点,使节点能够访问该卷。 - 快照与克隆:
CreateSnapshot/DeleteSnapshot/CreateVolumeFromSnapshot— 支持数据保护与快速恢复。 - 容量感知:
GetCapacity— 返回存储池的剩余容量,供调度器做容量感知调度。
CreateVolume 请求过慢,会导致 Pod 调度阻塞。建议为 Controller Plugin 配置独立的资源配额(CPU/Memory),并启用 gRPC 连接池复用。
2.3 Node Plugin:数据面的执行者
Node Plugin 运行在每个工作节点上,以 DaemonSet 形式部署。它负责将卷实际挂载到 Pod 的文件系统路径中。其核心接口定义在 csi.NodeServer gRPC 服务中。
- 节点级卷操作:
NodePublishVolume/NodeUnpublishVolume— 执行实际的 mount 操作,将块设备或文件系统挂载到目标路径。 - 阶段挂载:
NodeStageVolume/NodeUnstageVolume— 在全局命名空间(如/var/lib/kubelet/plugins/)中准备卷,然后进行发布。 - 节点状态:
NodeGetCapabilities/NodeGetInfo— 返回节点支持的卷类型、最大挂载数、拓扑信息等。 - 卷统计:
NodeGetVolumeStats— 提供卷的已用空间、inode 使用量等指标,用于kubectl top和 HPA。
NodePublishVolume 调用是同步的,如果挂载操作超时(默认 30 秒),Kubelet 会重试并可能导致 Pod 启动延迟。务必确保 Node Plugin 的挂载逻辑高效,且后端存储的挂载路径无 I/O 阻塞。
2.4 Sidecar Container:Kubernetes 与 CSI 的桥梁
Sidecar Container 是 Kubernetes CSI 架构中特有的组件。它并不是 CSI 规范的一部分,而是 Kubernetes 社区提供的一组辅助容器,用于将 CSI 驱动与 Kubernetes 原生资源对象(如 PersistentVolumeClaim、VolumeAttachment)进行联动。
常见的 Sidecar 容器包括:
| Sidecar 名称 | 监听资源 | 调用的 CSI 方法 | 核心功能 |
|---|---|---|---|
csi-provisioner |
PersistentVolumeClaim |
CreateVolume / DeleteVolume |
自动创建/删除 PersistentVolume |
csi-attacher |
VolumeAttachment |
ControllerPublishVolume / ControllerUnpublishVolume |
将卷附加/分离到节点 |
csi-resizer |
PersistentVolumeClaim (修改容量) |
ControllerExpandVolume |
在线扩容卷 |
csi-snapshotter |
VolumeSnapshot / VolumeSnapshotContent |
CreateSnapshot / DeleteSnapshot |
创建/删除卷快照 |
csi-node-driver-registrar |
无(通过 Unix Socket 注册) | NodeGetInfo |
向 Kubelet 注册 Node Plugin 的 Unix Socket 路径 |
2.5 组件交互流程与架构图
下图展示了 CSI 三大组件在 Kubernetes 集群中的部署位置与交互关系。Controller Plugin 与 Sidecar 容器运行在同一个 Pod 中(通常作为 Deployment),Node Plugin 与 csi-node-driver-registrar 运行在另一个 Pod 中(作为 DaemonSet)。
2.6 接口调用流程示例
以创建一个 PVC 并挂载到 Pod 为例,三大组件的完整调用链如下:
- 用户创建 PVC → API Server 写入 etcd。
- csi-provisioner (Sidecar) 监听到 PVC 事件,调用 Controller Plugin 的
CreateVolumegRPC 方法。 - Controller Plugin 向存储后端发送创建卷请求,返回卷 ID 和属性。
- csi-provisioner 创建
PersistentVolume对象,绑定到 PVC。 - 调度器 将 Pod 调度到某个节点,创建
VolumeAttachment对象。 - csi-attacher (Sidecar) 监听到
VolumeAttachment,调用ControllerPublishVolume将卷附加到节点。 - Kubelet 在节点上调用 Node Plugin 的
NodeStageVolume和NodePublishVolume,完成最终挂载。
CreateVolume 和 ControllerPublishVolume 的耗时。建议将 Controller Plugin 部署在离存储后端最近的集群中,或使用 gRPC 长连接减少握手开销。
2.7 多集群环境下的组件部署策略
| 组件 | 单集群部署 | 多集群部署(推荐) | 说明 |
|---|---|---|---|
| Controller Plugin | 1 个 Deployment,1-2 副本 | 每个集群独立部署,或集中部署在管理集群 | 集中部署可减少存储后端连接数,但增加网络延迟 |
| Node Plugin | DaemonSet,每节点 1 个 | 每个集群的每个节点独立部署 | 必须本地部署,因为挂载操作需要访问节点设备 |
| Sidecar Container | 与 Controller/Node Plugin 同 Pod | 与 Controller/Node Plugin 同 Pod | 部署策略跟随主容器 |
VolumeAttachment 的拓扑约束确保卷被附加到正确的节点。