2. CSI 核心概念:三大服务接口定义与职责

CSI(Container Storage Interface)是容器编排系统(Kubernetes、Mesos、Nomad 等)与存储系统之间的标准插件协议。CSI 规范将存储驱动的功能抽象为 三个独立的 gRPC 服务:Identity、Controller 和 Node。每个服务负责存储生命周期中不同阶段的职责,这种分层设计使得驱动可以按需实现,降低了开发复杂度。

核心原则:Identity 服务是必选的,Controller 和 Node 服务根据存储系统的架构(集中式 vs. 分布式)可以选择性实现。Kubernetes 要求至少实现 Identity + Node 服务才能注册为有效的 CSI 驱动。

2.1 三大服务全景图

下图展示了三个服务在 Kubernetes 集群中的部署位置与调用关系。Controller 服务通常运行在控制平面(Deployment),Node 服务运行在每个工作节点(DaemonSet),Identity 服务则通常与 Controller 或 Node 服务共存。

CSI 三大服务架构与调用关系 Kubernetes 集群 控制平面(Control Plane) Controller Service CreateVolume / DeleteVolume ControllerPublish / ControllerUnpublish ListVolumes / GetCapacity / CreateSnapshot Identity Service GetPluginInfo / GetPluginCapabilities / Probe 外部存储系统 SAN / NAS / 分布式存储 / 云存储 通过 Controller 服务管理卷 工作节点(Worker Node) Node Service NodePublishVolume / NodeUnpublishVolume NodeStageVolume / NodeUnstageVolume NodeGetVolumeStats / NodeExpandVolume Identity Service GetPluginInfo / GetPluginCapabilities / Probe 本地挂载点 /var/lib/kubelet/pods/.../volumes/ 通过 Node 服务将卷挂载到 Pod gRPC 调用 gRPC 调用

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 扩容请求
注意:Controller 服务是可选的。如果你的存储系统是“临时存储”或“设备直通”类型(如本地 SSD),不需要创建/删除卷,则可以不实现 Controller 服务。但大多数生产级存储驱动都会实现。

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 vs. Publish 的区别:
  • 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 挂载的完整流程,展示了三个服务如何协同工作:

  1. Identity 探测:kubelet 调用 Probe 确认驱动就绪,调用 GetPluginCapabilities 获取支持的能力。
  2. Controller 创建卷:external-provisioner 调用 CreateVolume,后端存储创建卷并返回卷 ID。
  3. Controller 挂载到节点:external-attacher 调用 ControllerPublishVolume,将卷关联到目标节点。
  4. Node 暂存:kubelet 调用 NodeStageVolume,将卷挂载到节点的暂存目录。
  5. Node 发布:kubelet 调用 NodePublishVolume,将卷绑定挂载到 Pod 的挂载路径。
  6. Pod 使用:容器启动,通过挂载路径读写数据。
开发建议:在实现 Node 服务时,务必处理好幂等性。Kubelet 可能会重复调用 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 驱动的第一步,也是设计存储系统集成方案的基础。