【Rook / CSI】CSI 规范与 K8s 接线:Controller、Node 与 sidecar

💡 原文中文,约10500字,阅读约需25分钟。
📝

内容提要

本文介绍Kubernetes CSI存储规范,核心是将存储插件分为Controller(集群级供给)和Node(节点级挂载)两类。K8s通过external-provisioner等sidecar组件将API对象转换为CSI RPC调用。文章详细梳理了PVC从创建到Pod挂载的完整调用链,强调PVC Bound不等于挂载成功,排障时需区分供给、挂载和I/O问题所在层级。

🔎

延伸解读

PVC Pending 与 MountFailed 的排障分界

文章强调,PVC Pending 和 Pod MountFailed 通常对应不同的 CSI RPC 和进程。Pending 多源于 Controller 侧供给问题,如 StorageClass provisioner 名不匹配、Secret 错误或后端配额不足;而 MountFailed 多源于 Node 侧 Stage/Publish 失败,如设备 map、SELinux 或内核模块问题。排障时应先根据现象定位到具体阶段,再检查对应日志,避免将所有存储故障归因于 Ceph 集群。

sidecar 版本与 CRD 对齐的隐性成本

Kubernetes 通过 sidecar 将 API 对象转换为 CSI RPC,但 sidecar 与 CSI 驱动、CRD(如 VolumeSnapshot)的版本耦合常被忽视。文章指出,即使驱动实现了 CreateSnapshot,若集群未安装匹配的快照 CRD 和 controller,用户会在 API 层直接失败。这种版本错位是生产环境常见的编排税,升级时需人工核对 release notes 和资源版本,缺乏统一健康信号。

PVC Bound 不等于挂载成功

文章明确区分了供给、挂载和 I/O 三个层面。PVC Bound 仅表示 provisioner 路径走通或静态 PV 绑定完成,并不代表 NodePublish 已成功。Pod 运行且卷已挂载才覆盖 Stage/Publish 阶段。排障时需根据 Events、VolumeAttachment 状态和 kubelet 日志判断具体失败环节,避免误诊。

Q&A

CSI 规范为什么要把存储插件分为 Controller 和 Node 两类?

因为集群级操作(如供给、删除、扩容)不需要在每个节点上运行,而节点级挂载必须靠近 kubelet。Controller 插件以 Deployment 形式运行,负责供给等集群级操作;Node 插件以 DaemonSet 形式运行,负责在节点上准备设备和挂载。

Kubernetes 中 external-provisioner 的作用是什么?

external-provisioner 是 CSI sidecar 之一,它监视 PersistentVolumeClaim(PVC)对象,当发现未绑定的 PVC 时,调用 CSI Controller 的 CreateVolume RPC 创建卷,成功后创建 PV 并绑定 PVC。

PVC 处于 Bound 状态是否意味着 Pod 一定能挂载成功?

不一定。PVC Bound 只说明 provisioner 路径走通(或静态 PV 已绑定),并不代表 NodePublishVolume 已成功。Pod 挂载成功还需要 NodeStageVolume 和 NodePublishVolume 都成功执行。

在 CSI 中,NodeStageVolume 和 NodePublishVolume 有什么区别?

NodeStageVolume 将卷准备到节点级 staging 路径,通常每个节点每卷只执行一次,失败常见于设备 map、多路径、密钥或内核模块问题;NodePublishVolume 将卷从 staging 挂载到 Pod 的 target_path,失败常见于目标路径、SELinux、bind-mount 问题。

Kubernetes CSI 是何时 GA 的?

Kubernetes CSI 在 v1.13 版本 GA,于 2019 年 1 月 15 日宣布。

使用 CSI-Addons 扩展有什么代价?

CSI-Addons 提供了额外的 CRD 和 sidecar 来表达 VolumeReplication、Network Fencing 等操作,但代价是增加了 CRD/控制器版本管理的复杂度,排障坐标系变长。Rook 将其视为可选功能,需要额外部署 controller 并设置 deployCsiAddons: true。

PVC 一直 Pending 可能是什么原因?

可能原因包括:StorageClass provisioner 名与集群中 Driver 名不一致、Secret 或 mon endpoint 错误、后端配额或池不存在等。此时应检查 external-provisioner 和 CSI Controller 的日志,而不是 kube-scheduler 日志。

静态供给与动态供给在 CSI 调用链上有什么区别?

静态供给时,用户预先创建指向已有 RBD image 或 CephFS 路径的 PV,PVC 绑定后仍会走 Node Stage/Publish,但跳过 CreateVolume。动态供给则先由 external-provisioner 调用 CreateVolume 创建卷,再绑定 PV。

🏷️

标签

➡️

继续阅读