2. CSI 核心概念:三大服务接口定义与职责
CSI(Container Storage Interface)是容器编排系统(Kubernetes、Mesos、Nomad 等)与存储系统之间的标准插件协议。CSI 规范将存储驱动的功能抽象为 三个独立的 gRPC 服务:Identity、Controller 和 Node。每个服务负责存储生命周期中不同阶段的职责,这种分层设计使得驱动可以按需实现,降低了开发复杂度。
2.1 三大服务全景图
下图展示了三个服务在 Kubernetes 集群中的部署位置与调用关系。Controller 服务通常运行在控制平面(Deployment),Node 服务运行在每个工作节点(DaemonSet),Identity 服务则通常与 Controller 或 Node 服务共存。
2.2 Identity Service:驱动身份与能力声明
Identity 服务是 CSI 驱动的身份证,负责向容器编排系统报告插件的基本信息、支持的能力以及健康状态。该服务是所有 CSI 驱动必须实现的接口。
| RPC 方法 | 方向 | 功能描述 | 必选/可选 |
|---|---|---|---|
GetPluginInfo |
CO → Plugin | 返回驱动名称、版本、厂商信息 | 必选 |
GetPluginCapabilities |
CO → Plugin | 返回驱动支持的能力集(如 Controller 服务、卷扩展、快照等) | 必选 |
Probe |
CO → Plugin | 健康检查,返回驱动是否就绪 | 必选 |
GetPluginCapabilities 返回的 Capability 列表决定了 CO(Container Orchestrator)是否会调用 Controller 或 Node 服务的特定方法。例如,如果驱动不支持快照,CO 就不会调用 CreateSnapshot。务必准确声明能力,避免 CO 调用未实现的方法导致错误。
2.3 Controller Service:存储控制平面
Controller 服务运行在集群的控制平面,负责存储卷的生命周期管理,包括创建、删除、挂载到节点、快照、扩容等操作。该服务通常与后端存储系统(如 Ceph、NFS 服务器、云存储 API)直接交互。
| RPC 方法 | 功能描述 | 典型使用场景 |
|---|---|---|
CreateVolume |
创建存储卷,返回卷 ID、容量、属性 | PVC 创建时触发 |
DeleteVolume |
删除指定卷 | PVC 删除时触发 |
ControllerPublishVolume |
将卷挂载到指定节点(节点级准备) | Pod 调度到节点后触发 |
ControllerUnpublishVolume |
从节点卸载卷 | Pod 从节点移除时触发 |
ListVolumes |
列出所有卷及其状态 | Kubernetes 卷状态同步 |
GetCapacity |
返回存储系统的可用容量 | 调度器决策卷放置位置 |
CreateSnapshot |
创建卷的快照 | 数据备份与恢复 |
DeleteSnapshot |
删除快照 | 快照生命周期管理 |
ControllerExpandVolume |
在线扩容卷 | PVC 扩容请求 |
2.4 Node Service:节点级卷操作
Node 服务运行在每个工作节点上,负责将卷挂载到 Pod 的文件系统。它执行实际的 mount、unmount、格式化等操作,是 CSI 驱动与节点操作系统交互的桥梁。
| RPC 方法 | 功能描述 | 执行时机 |
|---|---|---|
NodeStageVolume |
将卷挂载到节点的“暂存目录”(全局挂载点) | Pod 调度到节点后,在容器启动前 |
NodeUnstageVolume |
从暂存目录卸载卷 | Pod 停止后,卷不再被任何 Pod 使用 |
NodePublishVolume |
将卷挂载到 Pod 的专用挂载路径 | 容器启动时 |
NodeUnpublishVolume |
从 Pod 路径卸载卷 | 容器停止时 |
NodeGetVolumeStats |
返回卷的使用统计(容量、inode 等) | Kubernetes 定期采集指标 |
NodeExpandVolume |
在节点侧扩展卷的文件系统 | 卷扩容后,在节点上执行 resize |
NodeGetCapabilities |
返回 Node 服务支持的能力 | CO 发现阶段 |
- Stage(暂存):将卷挂载到节点的全局路径(如
/var/lib/kubelet/plugins/kubernetes.io/csi/pv/<volume-id>/globalmount),供该节点上所有使用此卷的 Pod 共享底层设备。 - Publish(发布):将卷从暂存路径绑定挂载到 Pod 的专用路径(如
/var/lib/kubelet/pods/<pod-id>/volumes/kubernetes.io~csi/<volume-id>/mount),实现 Pod 级别的隔离。
2.5 三大服务职责对比
| 维度 | Identity Service | Controller Service | Node Service |
|---|---|---|---|
| 部署位置 | 控制平面 / 工作节点 | 控制平面 | 每个工作节点 |
| 是否必选 | 是 | 否(推荐实现) | 是 |
| 核心职责 | 身份声明、能力报告、健康检查 | 卷的创建/删除/挂载/快照/扩容 | 卷的节点级挂载/卸载/统计 |
| 与存储后端交互 | 通常不直接交互 | 直接调用存储 API | 通过文件系统/设备接口操作 |
| 调用频率 | 低(启动时、周期性探测) | 中(PVC 创建/删除时) | 高(Pod 调度/停止时) |
| Kubernetes 组件 | kubelet / external-provisioner | external-provisioner / external-attacher | kubelet |
2.6 接口调用流程示例
以下是一个典型的 PVC 创建到 Pod 挂载的完整流程,展示了三个服务如何协同工作:
- Identity 探测:kubelet 调用
Probe确认驱动就绪,调用GetPluginCapabilities获取支持的能力。 - Controller 创建卷:external-provisioner 调用
CreateVolume,后端存储创建卷并返回卷 ID。 - Controller 挂载到节点:external-attacher 调用
ControllerPublishVolume,将卷关联到目标节点。 - Node 暂存:kubelet 调用
NodeStageVolume,将卷挂载到节点的暂存目录。 - Node 发布:kubelet 调用
NodePublishVolume,将卷绑定挂载到 Pod 的挂载路径。 - Pod 使用:容器启动,通过挂载路径读写数据。
NodePublishVolume,驱动需要能够安全地处理重复挂载请求,避免产生重复的挂载点或文件系统损坏。
2.7 gRPC 接口定义示例
以下是一个简化的 CSI Identity 服务 protobuf 定义,展示了接口的签名和参数结构:
syntax = "proto3";
package csi.v1;
service Identity {
// 返回插件名称、版本、厂商信息
rpc GetPluginInfo(GetPluginInfoRequest)
returns (GetPluginInfoResponse) {}
// 返回插件支持的能力集
rpc GetPluginCapabilities(GetPluginCapabilitiesRequest)
returns (GetPluginCapabilitiesResponse) {}
// 健康检查,返回驱动是否就绪
rpc Probe(ProbeRequest)
returns (ProbeResponse) {}
}
message GetPluginInfoRequest {
// 当前版本无必填参数,保留扩展
}
message GetPluginInfoResponse {
string name = 1; // 驱动名称,如 "csi.example.com"
string vendor_version = 2; // 驱动版本,如 "1.0.0"
map<string, string> manifest = 3; // 附加元数据
}
message ProbeResponse {
bool ready = 1; // true 表示驱动就绪
}
Controller 和 Node 服务的 protobuf 定义类似,篇幅所限不再展开。完整的 CSI 规范 protobuf 文件可以在 CSI 官方仓库 中找到。
- CSI 三大服务(Identity、Controller、Node)构成了存储驱动的完整功能边界。
- Identity 服务是驱动的“身份证”,必须实现,用于声明身份和能力。
- Controller 服务是“存储大脑”,负责卷的创建、删除、挂载到节点等控制面操作。
- Node 服务是“执行者”,负责在节点上完成实际的挂载、卸载和统计工作。
- 理解这三个服务的职责划分,是开发 CSI 驱动的第一步,也是设计存储系统集成方案的基础。