3. CSI驱动生命周期:驱动注册、节点服务、控制器服务、卷挂载/卸载流程

CSI(Container Storage Interface)驱动的完整生命周期由四个核心阶段构成:驱动注册、节点服务、控制器服务以及卷挂载/卸载。理解每个阶段的职责与交互流程,是诊断版本漂移、规划升级窗口的基础。

关键认知: CSI 驱动以 DaemonSet(节点服务)和 Deployment(控制器服务)两种形态运行在集群中。节点服务负责本地卷操作,控制器服务负责全局编排。两者通过 gRPC 接口与 kubelet 或外部控制器通信。

3.1 驱动注册阶段

驱动注册是 CSI 驱动在 Kubernetes 节点上“自报家门”的过程,确保 kubelet 知道该节点上有哪些卷插件可用。

  • 注册机制: CSI 驱动以 DaemonSet 形式在每个节点上运行一个 node-driver-registrar 边车容器。该容器通过 Unix Socket 与 kubelet 的插件注册目录(通常为 /var/lib/kubelet/plugins_registry)通信。
  • 注册流程:
    1. node-driver-registrar 向 kubelet 发送 NodeGetInfo gRPC 请求,获取驱动名称、节点 ID、最大卷数、拓扑键等信息。
    2. kubelet 将驱动信息写入内部注册表,标记该节点支持该 CSI 驱动。
    3. kubelet 在 /var/lib/kubelet/plugins/<driver-name>/csi.sock 建立 Unix Socket 连接,用于后续卷操作。
  • 版本漂移风险点: 升级 CSI 驱动时,若 node-driver-registrar 版本与 kubelet 版本不兼容,可能导致注册失败或驱动不可用。
升级检查项: 升级前确认 node-driver-registrar 镜像版本与目标 Kubernetes 版本的兼容性矩阵。注册失败时,kubelet 日志中会出现 failed to register plugin 错误。

3.2 节点服务(Node Service)

节点服务运行在每个 Kubernetes 节点上,负责处理与本地存储相关的操作。它通过 gRPC 接口暴露以下 RPC:

RPC 名称 功能描述 升级影响
NodeGetInfo 返回节点 ID、最大卷数、拓扑信息 拓扑键变更可能导致调度失败
NodeGetCapabilities 返回节点服务支持的能力(如卷扩展、拓扑感知) 能力变更影响 kubelet 行为
NodeStageVolume 将卷挂载到节点上的“暂存”目录(全局挂载点) 挂载参数变更可能导致 Pod 启动失败
NodePublishVolume 将卷从暂存目录挂载到 Pod 的具体挂载路径 挂载选项不兼容导致 Pod 挂载超时
NodeUnpublishVolume 卸载 Pod 挂载路径上的卷 卸载失败导致 Pod 删除卡住
NodeUnstageVolume 卸载暂存目录上的卷 残留挂载点影响后续卷挂载

节点服务通常以 DaemonSet 部署,每个 Pod 包含 CSI 驱动主容器和 node-driver-registrar 边车。升级时,DaemonSet 的滚动更新策略会逐个替换 Pod,期间需确保节点上的卷操作不中断。

3.3 控制器服务(Controller Service)

控制器服务是 CSI 驱动的“大脑”,运行在集群的控制平面或工作节点上(通常以 Deployment 部署),负责全局存储编排。它对外暴露以下关键 RPC:

  • 卷创建/删除: CreateVolume / DeleteVolume — 与后端存储系统交互,创建或移除存储卷。
  • 卷挂载/卸载(控制器侧): ControllerPublishVolume / ControllerUnpublishVolume — 将卷附加到指定节点(如云盘挂载到云主机)。
  • 快照操作: CreateSnapshot / DeleteSnapshot — 创建或删除卷快照。
  • 容量与拓扑感知: GetCapacity / ListVolumes — 返回存储池容量和卷列表,供调度器决策。
版本漂移高危区: 控制器服务升级期间,若 CreateVolume 或 ControllerPublishVolume 的请求/响应格式发生变化,正在进行的 PVC 创建或 Pod 调度可能失败。建议在升级前确认所有 PVC 已绑定,且无正在进行的卷操作。

3.4 卷挂载/卸载流程

卷挂载/卸载是 CSI 驱动最核心的执行路径,涉及 kubelet、节点服务、控制器服务的多步协作。以下流程图展示了从 Pod 调度到卷挂载完成的完整链路:

CSI 卷挂载/卸载完整流程 1. Pod 调度到节点 2. kubelet → NodeStageVolume 3. 卷挂载到暂存目录 4. kubelet → NodePublishVolume 5. 卷挂载到 Pod 路径 6. Pod 使用卷 7. Pod 删除 8. kubelet → NodeUnpublishVolume 9. kubelet → NodeUnstageVolume 10. 卷卸载完成 挂载流程关键点 • 暂存目录:/var/lib/kubelet/plugins/ • Pod 路径:/var/lib/kubelet/pods/ • 卸载顺序:先 Unpublish 再 Unstage

挂载流程的详细步骤:

  1. Pod 调度: Kubernetes 调度器将 Pod 分配到某个节点,并确保该节点已注册对应的 CSI 驱动。
  2. NodeStageVolume: kubelet 调用 CSI 驱动的 NodeStageVolume RPC,将卷挂载到节点的全局暂存目录(/var/lib/kubelet/plugins/<driver-name>/<volume-id>/globalmount)。此步骤通常涉及格式化、加密或网络连接。
  3. NodePublishVolume: kubelet 调用 NodePublishVolume RPC,将卷从暂存目录绑定挂载到 Pod 的特定挂载路径(/var/lib/kubelet/pods/<pod-uid>/volumes/<driver-name>/<volume-id>)。
  4. Pod 使用: 挂载完成后,Pod 内的容器即可读写卷。

卸载流程为上述步骤的逆序:

  1. Pod 删除: kubelet 检测到 Pod 被删除,启动卸载流程。
  2. NodeUnpublishVolume: 卸载 Pod 挂载路径上的卷。
  3. NodeUnstageVolume: 卸载暂存目录上的卷,释放后端资源。
升级校准点: 在 CSI 驱动升级过程中,若 NodeStageVolume 或 NodePublishVolume 的挂载选项(如 mountFlags、fsType)发生变更,已运行 Pod 不受影响,但新调度 Pod 可能因挂载参数不匹配而失败。建议升级前记录当前挂载选项,升级后对比验证。

3.5 生命周期状态机

以下 SVG 图展示了 CSI 卷从创建到删除的完整状态转换,帮助理解各阶段之间的依赖关系:

CSI 卷生命周期状态机 卷创建 卷可用 卷已挂载 卷已发布 卷已卸载 卷已删除 状态转换说明 • 卷创建 → 卷可用:CreateVolume 成功 • 卷可用 → 卷已挂载:NodeStageVolume 成功 • 卷已挂载 → 卷已发布:NodePublishVolume 成功 • 卷已发布 → 卷已卸载:NodeUnpublishVolume + NodeUnstageVolume

状态转换中的版本漂移风险:

  • 卷创建 → 卷可用: 若控制器服务升级后 CreateVolume 返回的卷属性(如容量、拓扑)与旧版本不一致,可能导致 PVC 绑定失败。
  • 卷可用 → 卷已挂载: 节点服务升级后,NodeStageVolume 的挂载参数变更可能导致已创建但未挂载的卷无法挂载。
  • 卷已发布 → 卷已卸载: 卸载流程中的 RPC 签名变更可能导致卸载卡住,影响节点维护。
实战建议: 在 CSI 驱动升级前,使用 kubectl get csinodes 确认所有节点已注册驱动;使用 kubectl get volumeattachments 检查是否有正在挂载的卷。升级后,通过 kubectl describe pv <pv-name> 验证卷状态是否正常。