CSI存储变更门禁:自动化性能基准测试与故障排查 - 第2节

CSI 规范概述:从 in-tree 到标准接口的演进

Kubernetes 早期通过 in-tree 存储插件直接与存储后端通信。每个存储厂商都需要将代码合入 Kubernetes 主干,导致发布周期长、二进制膨胀、厂商锁定风险高。CSI(Container Storage Interface)规范由 Kubernetes、Mesos、Cloud Foundry 等社区联合制定,旨在将存储驱动从容器编排平台中解耦,形成一个标准化的插件接口。

核心目标:CSI 定义了一组 gRPC 接口,让存储厂商只需实现一个符合规范的驱动程序,即可被任何支持 CSI 的容器编排平台(Kubernetes、Mesos、Nomad 等)直接调用,无需修改平台核心代码。

CSI 规范版本与关键里程碑

版本 发布时间 关键特性
v0.1.0 2017-06 初始草案,定义 Identity、Controller、Node 三大 RPC 服务
v1.0.0 2018-12 GA 版本,Kubernetes v1.13 默认启用 CSI 功能
v1.5.0 2021-06 引入 Volume Group Snapshot、Volume Clone 等高级特性
v1.9.0 2023-12 增强拓扑感知调度、多挂载能力、健康监控
SRE 视角:CSI v1.0 是生产可用的分水岭。如果你的集群版本低于 v1.13,需要升级 Kubernetes 才能原生支持 CSI。当前主流 CSI 驱动(如 AWS EBS CSI、Ceph RBD CSI)均要求 CSI spec ≥ v1.1。

Container Storage Interface 核心概念

CSI 规范围绕三个核心 RPC 服务构建,每个服务对应不同的职责域:

三大 RPC 服务

服务名称 端点 核心方法 职责
Identity CSI-Driver-Socket GetPluginInfo, Probe, GetPluginCapabilities 驱动身份识别、能力声明、健康探测
Controller CSI-Driver-Socket CreateVolume, DeleteVolume, ControllerPublishVolume, CreateSnapshot, ListSnapshots 卷的生命周期管理(创建/删除/快照/扩容)
Node CSI-Driver-Socket NodePublishVolume, NodeUnpublishVolume, NodeGetVolumeStats, NodeExpandVolume 节点级卷挂载/卸载、状态上报、在线扩容

关键概念术语

  • Volume(卷):存储单元,对应块设备或文件系统。CSI 支持静态预置和动态预置两种模式。
  • Volume Capability(卷能力):声明卷的访问模式(单节点读写、多节点只读、多节点读写)和挂载类型(块设备、文件系统)。
  • Topology(拓扑):描述存储后端在集群中的物理/逻辑位置(如 zone、rack),用于指导调度器将 Pod 调度到离存储最近的节点。
  • Secrets(密钥):CSI 规范允许在 RPC 请求中传递 Kubernetes Secret,用于存储后端认证(如 Ceph 的 keyring、NFS 的认证凭据)。
  • Volume Attributes(卷属性):创建卷时传递的键值对参数,由 CSI 驱动自行解析(如文件系统类型、副本数、性能 tier)。
常见误区:CSI 规范本身不定义数据面加密、压缩、去重等特性。这些功能由存储后端实现,CSI 驱动仅负责将 Kubernetes 的请求转换为后端 API 调用。不要期望 CSI 驱动能“自动”提供存储后端不具备的能力。

CSI 驱动与 Kubernetes 集成原理

Kubernetes 通过 CSI Sidecar 容器 模式实现与 CSI 驱动的集成。每个 CSI 驱动 Pod 通常包含多个容器:CSI 驱动主容器 + 若干 Kubernetes 官方提供的 Sidecar。Sidecar 负责将 Kubernetes 的存储操作(如 PVC 创建、Pod 调度)转换为 CSI RPC 调用。

集成架构总览

CSI 驱动与 Kubernetes 集成架构 CSI 驱动与 Kubernetes 集成架构 Kubernetes 控制面 kube-apiserver kube-controller-manager kube-scheduler PV / PVC / StorageClass CSI Sidecar 容器组 external-provisioner external-attacher external-resizer external-snapshotter node-driver-registrar CSI 驱动 Identity 服务 Controller 服务 Node 服务 存储后端 SDK 存储后端 Ceph / AWS EBS / NFS / vSphere Watch PVC/PV gRPC CSI 调用 REST / iSCSI / NFS

Sidecar 容器职责详解

Sidecar 名称 监听资源 调用的 CSI 方法 典型场景
external-provisioner PersistentVolumeClaim CreateVolume, DeleteVolume 动态预置:PVC 创建时自动调用后端创建卷
external-attacher VolumeAttachment ControllerPublishVolume, ControllerUnpublishVolume 将卷挂载到指定节点(如 iSCSI 登录、FC 映射)
external-resizer PersistentVolumeClaim (spec.resources.requests.storage) ControllerExpandVolume 在线扩容:PVC 修改存储大小后触发后端扩容
external-snapshotter VolumeSnapshot / VolumeSnapshotContent CreateSnapshot, DeleteSnapshot, ListSnapshots 创建/删除卷快照,用于备份和恢复
node-driver-registrar Node 启动时注册 GetPluginInfo, NodeGetInfo 向 kubelet 注册 CSI 驱动,上报节点拓扑信息

CSI 驱动部署模式

CSI 驱动在 Kubernetes 中以 DaemonSet + StatefulSet(或 Deployment)组合方式部署:

  • Controller 组件(StatefulSet/Deployment):运行 Identity 和 Controller 服务,通常部署 2 个副本保证高可用。负责卷的创建、删除、快照等控制面操作。
  • Node 组件(DaemonSet):在每个 Kubernetes 节点上运行,提供 Node 服务。负责卷的挂载、卸载、格式化、指标采集等数据面操作。
生产建议:Controller 组件应设置 podAntiAffinity 确保跨节点调度;Node 组件必须设置 hostNetwork: true 和 privileged: true,因为需要访问宿主机设备(如 /dev 下的块设备)和挂载命名空间。

CSI 驱动与 kubelet 的交互流程

Pod 挂载 CSI 卷的完整流程 Pod 挂载 CSI 卷的完整流程 ① PVC 创建 用户创建 PVC ② 动态预置 external-provisioner ③ 卷创建 CSI Controller.CreateVolume ④ PV 绑定 PV 与 PVC 绑定 ⑤ Pod 调度 kube-scheduler ⑥ 卷挂载 external-attacher ⑦ 节点挂载 CSI Node.NodePublishVolume ⑧ Pod 启动 卷已挂载到 Pod 路径 关键说明 • 步骤 ①-④ 由 Controller 组件完成,不涉及具体节点。 • 步骤 ⑤-⑧ 由 Node 组件在 Pod 调度到的节点上完成。 • 如果卷已存在(静态预置),跳过步骤 ②-③,直接从步骤 ④ 开始。 • 卷卸载流程与挂载相反:先 NodeUnpublishVolume,再 ControllerUnpublishVolume,最后 DeleteVolume。

CSI 驱动健康检查与故障排查要点

  • Probe 接口:kubelet 定期调用 CSI 驱动的 Probe 方法检查驱动健康状态。如果返回非 OK 状态,kubelet 会标记该节点为 NodeWithFaultyCSIDriver,阻止新 Pod 调度到该节点。
  • 日志采集:CSI 驱动日志通常输出到 stdout/stderr,可通过 kubectl logs -n <namespace> <csi-driver-pod> -c <csi-driver-container> 查看。Sidecar 容器日志同样重要,建议统一采集到日志平台。
  • 常见故障模式:
    • 卷挂载超时:检查节点网络连通性、存储后端防火墙规则、iSCSI/NFS 客户端配置。
    • 卷创建失败:检查 StorageClass 参数、存储后端配额、CSI 驱动权限。
    • 拓扑不匹配:检查 CSI 驱动上报的拓扑键与节点标签是否一致。