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)通信。 - 注册流程:
node-driver-registrar向 kubelet 发送NodeGetInfogRPC 请求,获取驱动名称、节点 ID、最大卷数、拓扑键等信息。- kubelet 将驱动信息写入内部注册表,标记该节点支持该 CSI 驱动。
- 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 调度到卷挂载完成的完整链路:
挂载流程的详细步骤:
- Pod 调度: Kubernetes 调度器将 Pod 分配到某个节点,并确保该节点已注册对应的 CSI 驱动。
- NodeStageVolume: kubelet 调用 CSI 驱动的
NodeStageVolumeRPC,将卷挂载到节点的全局暂存目录(/var/lib/kubelet/plugins/<driver-name>/<volume-id>/globalmount)。此步骤通常涉及格式化、加密或网络连接。 - NodePublishVolume: kubelet 调用
NodePublishVolumeRPC,将卷从暂存目录绑定挂载到 Pod 的特定挂载路径(/var/lib/kubelet/pods/<pod-uid>/volumes/<driver-name>/<volume-id>)。 - Pod 使用: 挂载完成后,Pod 内的容器即可读写卷。
卸载流程为上述步骤的逆序:
- Pod 删除: kubelet 检测到 Pod 被删除,启动卸载流程。
- NodeUnpublishVolume: 卸载 Pod 挂载路径上的卷。
- NodeUnstageVolume: 卸载暂存目录上的卷,释放后端资源。
升级校准点: 在 CSI 驱动升级过程中,若
NodeStageVolume 或 NodePublishVolume 的挂载选项(如 mountFlags、fsType)发生变更,已运行 Pod 不受影响,但新调度 Pod 可能因挂载参数不匹配而失败。建议升级前记录当前挂载选项,升级后对比验证。
3.5 生命周期状态机
以下 SVG 图展示了 CSI 卷从创建到删除的完整状态转换,帮助理解各阶段之间的依赖关系:
状态转换中的版本漂移风险:
- 卷创建 → 卷可用: 若控制器服务升级后
CreateVolume返回的卷属性(如容量、拓扑)与旧版本不一致,可能导致 PVC 绑定失败。 - 卷可用 → 卷已挂载: 节点服务升级后,
NodeStageVolume的挂载参数变更可能导致已创建但未挂载的卷无法挂载。 - 卷已发布 → 卷已卸载: 卸载流程中的 RPC 签名变更可能导致卸载卡住,影响节点维护。
实战建议: 在 CSI 驱动升级前,使用
kubectl get csinodes 确认所有节点已注册驱动;使用 kubectl get volumeattachments 检查是否有正在挂载的卷。升级后,通过 kubectl describe pv <pv-name> 验证卷状态是否正常。