2. CSI 规范基础:Container Storage Interface 核心概念与架构

Container Storage Interface (CSI) 是 Kubernetes 生态中存储接入的事实标准。它定义了一套 gRPC 接口,让存储厂商(如 Ceph、NFS、vSphere、云厂商块存储)以统一方式接入容器编排平台。本章聚焦 CSI 的核心概念、卷生命周期以及 Node/Controller 插件的职责划分。

2.1 CSI 核心概念

CSI 规范将存储操作抽象为三个核心角色:Controller Plugin、Node Plugin 和 Identity Plugin。每个角色负责不同的操作域,通过 gRPC 服务暴露给容器编排系统(CO)。

角色 gRPC 服务 主要职责 部署位置
Controller Plugin ControllerServer 卷的创建/删除、快照、扩容、挂载/卸载(控制面) Master/Control Plane 节点
Node Plugin NodeServer 卷在节点上的挂载/卸载、设备格式化、Stage/Publish 每个 Worker 节点
Identity Plugin IdentityServer 插件元信息、探活、驱动能力声明 与 Controller/Node 同进程
关键理解:Controller 插件负责“存储系统侧”操作(如创建卷、快照),Node 插件负责“主机侧”操作(如挂载到 Pod 所在节点)。这种分离使得存储控制面与数据面可以独立扩展。

2.2 卷生命周期:从创建到删除

CSI 规范定义了卷的完整生命周期,分为 Provisioning、Attach/Detach、Mount/Unmount、Deprovisioning 四个阶段。下图展示了核心流程与状态转换:

CSI 卷生命周期流程 CSI 卷生命周期流程 1. Provisioning CreateVolume 2. Attach ControllerPublishVolume 3. Mount NodeStageVolume + NodePublishVolume 卷使用中 4. Unmount NodeUnpublishVolume + NodeUnstageVolume 5. Detach ControllerUnpublishVolume 6. Deprovisioning DeleteVolume 说明: • Provisioning/Deprovisioning 由 Controller 插件处理,不涉及 Node 节点。 • Attach/Detach 由 Controller 插件处理,将卷映射到节点(如 iSCSI 登录、FC 映射)。 • Mount/Unmount 由 Node 插件处理,在节点上格式化、挂载到 Pod 路径。 • 卷使用中阶段,Pod 可正常读写;删除 Pod 后触发 Unmount → Detach → Deprovisioning。

2.3 Node 插件 vs Controller 插件

CSI 规范将插件职责严格分离,避免单点瓶颈和权限过度集中。下表对比了两类插件的核心差异:

维度 Controller 插件 Node 插件
部署方式 Deployment / StatefulSet(通常 1~2 副本) DaemonSet(每个 Worker 节点 1 个 Pod)
权限范围 需要存储系统管理员权限(创建/删除卷、快照) 仅需节点本地权限(挂载、格式化、设备操作)
网络可达性 必须能访问存储后端 API(如 Ceph MON、vCenter) 通常只需访问本地设备或 iSCSI/iSER 网络
关键 RPC CreateVolume, DeleteVolume, ControllerPublishVolume, ControllerUnpublishVolume, CreateSnapshot, ListSnapshots, ExpandVolume NodeStageVolume, NodePublishVolume, NodeUnstageVolume, NodeUnpublishVolume, NodeGetVolumeStats, NodeExpandVolume
状态持久化 通常依赖存储后端自身状态,或使用 CO 的 PV/PVC 对象 依赖节点本地状态文件(如 /var/lib/kubelet/plugins/…)
实践要点:在自动化测试中,Controller 插件测试需要模拟存储后端(如使用 mock 存储 API),而 Node 插件测试需要真实的块设备或文件系统环境。建议将两类测试用例分开编写,Controller 测试可完全在 CI 容器中运行,Node 测试需要挂载 /dev 和 /sys 等主机路径。

2.4 Identity 插件与能力声明

Identity 插件是 CSI 驱动的基础服务,负责向 CO 报告驱动元数据和能力。其核心 RPC 包括:

  • GetPluginInfo:返回驱动名称、版本、厂商信息。
  • GetPluginCapabilities:声明驱动支持的功能,如卷扩容、快照、拓扑感知、卷克隆等。
  • Probe:健康检查,CO 定期调用以确认驱动存活。

能力声明直接影响 CO 的行为。例如,如果驱动未声明 EXPAND_VOLUME 能力,Kubernetes 不会向该驱动发送 ControllerExpandVolume 请求。

// 示例:GetPluginCapabilities 返回的能力列表
capabilities:
  - service:
      type: CONTROLLER_SERVICE
  - volume_expansion:
      type: ONLINE  // 支持在线扩容
  - volume_conditions: {}  // 支持卷健康状态报告
  - topology: {}  // 支持拓扑感知调度

2.5 卷挂载的详细步骤:Stage vs Publish

CSI 规范将挂载过程拆分为 Stage 和 Publish 两个阶段,这是为了支持多个 Pod 共享同一个卷(如 ReadWriteMany)时的复用优化。

CSI 卷挂载阶段:Stage + Publish CSI 卷挂载阶段:Stage + Publish 存储后端 Ceph / NFS / vSphere Stage 目录 /var/lib/kubelet/plugins/…/stage/ Publish 目录 Pod 挂载路径 阶段详解: 1. NodeStageVolume:将卷挂载到节点上的“暂存目录”(全局挂载点)。 例如:将 iSCSI 设备格式化并挂载到 /var/lib/kubelet/plugins/…/stage/。 2. NodePublishVolume:从暂存目录创建 bind mount 到 Pod 的容器路径。 例如:mount --bind /stage/pvc-xxx /var/lib/kubelet/pods/<pod-uid>/volumes/… 优势:多个 Pod 共享同一卷时,只需一次 Stage,多次 Publish,减少后端操作。
常见误区:不要将 Stage 和 Publish 混淆为“挂载两次”。Stage 是全局准备(格式化+挂载到暂存点),Publish 是绑定挂载到 Pod 命名空间。卸载时先 Unpublish(解除 bind mount),再 Unstage(卸载暂存点)。如果跳过 Unstage 直接删除设备,可能导致节点文件系统损坏。

2.6 多后端适配的关键抽象

CSI 规范通过统一的 gRPC 接口屏蔽了后端差异。对于自动化测试而言,需要关注以下适配点:

  • 卷命名与标签:不同后端对卷名长度、字符集、标签键值对的支持不同(如 AWS EBS 限制 255 字符,Ceph RBD 支持更长)。
  • 挂载选项:NFS 需要 nfsvers=4.1,iSCSI 需要 chap_auth,CephFS 需要 secretfile。
  • 拓扑约束:某些后端(如本地 SSD)只能绑定到特定节点,CSI 通过 ACCESSIBILITY_CONSTRAINTS 能力声明。
  • 快照与克隆:部分后端不支持快照(如简单 NFS),测试用例需要根据能力声明动态跳过。
后端类型 典型 CSI 驱动 测试关注点
块存储(RBD) ceph-csi-rbd iSCSI 多路径、CHAP 认证、扩容后文件系统 resize
文件存储(CephFS) ceph-csi-cephfs 子卷隔离、quota 限制、跨节点共享
NFS nfs-csi 挂载选项(noatime, hard/soft)、权限映射
云厂商块存储 ebs-csi-driver / gce-pd-csi-driver 拓扑感知调度、卷类型(gp3/io2)、加密
测试策略建议:在自动化测试框架中,将 CSI 驱动能力声明作为测试用例的“前置条件”。例如,只有驱动声明了 EXPAND_VOLUME 才执行扩容测试;只有声明了 CREATE_SNAPSHOT 才执行快照测试。这样可以一套测试代码适配多个后端。