Kubernetes存储架构与CSI接口调用实战 - 第1节

1.1 Kubernetes 存储模型演进:从 Docker Volume 到 CSI 的变革

Kubernetes 存储架构的演进,本质上是容器编排平台对存储资源抽象能力不断深化的过程。从早期 Docker 的简单卷挂载,到 Kubernetes 内置的 In-Tree 存储插件,再到如今业界标准的 Container Storage Interface (CSI),每一次变革都解决了特定的核心痛点。

1.1.1 Docker Volume 时代的局限

在 Kubernetes 诞生之前,Docker 提供了基本的 Volume 机制,允许将宿主机目录或外部存储挂载到容器内。然而,这种模式在编排场景下暴露出明显缺陷:

  • 生命周期耦合:Volume 的生命周期与容器绑定,容器销毁后数据难以持久化。
  • 调度感知缺失:Docker 无法根据存储位置调度 Pod,导致跨节点迁移时数据不可达。
  • 存储接口碎片化:每种存储后端(NFS、iSCSI、云盘)都需要独立的客户端工具和配置方式。
关键痛点: Docker Volume 模型假设“存储是宿主机的一部分”,而 Kubernetes 需要“存储是集群资源的一部分”。

1.1.2 Kubernetes In-Tree 存储插件架构

Kubernetes 1.0 引入了 Volume Plugin 机制,将存储驱动直接编译进 kubelet 和 kube-controller-manager 二进制文件中。这种“In-Tree”模式首次实现了存储资源的声明式管理:

组件 职责 示例插件
PV / PVC 存储资源的供给与消费抽象 PersistentVolumeClaim
Attach/Detach 将存储设备挂载到宿主机 aws-ebs, gce-pd
Mount/Unmount 将设备挂载到 Pod 文件系统 nfs, hostPath
Provisioner 动态创建存储卷 cinder, vsphere-volume

In-Tree 模式虽然解决了基本编排问题,但带来了严重的 维护负担:每个存储厂商的代码必须合入 Kubernetes 主干仓库,导致二进制体积膨胀、安全漏洞修复周期长、新功能发布受限于 Kubernetes 版本节奏。

Kubernetes In-Tree 存储插件架构(1.x 时代) kube-controller-manager(内置 Volume Plugin 逻辑) kubelet(内置 Attach/Mount/Unmount 逻辑) AWS EBS (In-Tree 编译) GCE PD (In-Tree 编译) vSphere (In-Tree 编译) ⚠ 每个存储厂商的代码必须合入 Kubernetes 主干仓库,版本耦合严重 新存储后端加入需要等待 Kubernetes 大版本发布,周期长达数月

1.1.3 CSI 的诞生:解耦与标准化

2018 年,Kubernetes 1.13 将 Container Storage Interface (CSI) 提升为 GA(正式可用)。CSI 的核心思想是:将存储驱动从 Kubernetes 核心代码中剥离,通过 gRPC 接口与 kubelet 通信。这一变革带来了三个根本性改善:

  1. 厂商中立:存储厂商只需实现 CSI 规范定义的三个 gRPC 服务(Identity、Controller、Node),无需修改 Kubernetes 源码。
  2. 独立发布:CSI 驱动以 DaemonSet 或 Deployment 形式运行在集群中,可独立升级、回滚,不受 Kubernetes 版本约束。
  3. 功能扩展:支持快照、克隆、扩容、拓扑感知等高级特性,In-Tree 插件难以实现的功能变得标准化。
实践要点: 截至 Kubernetes 1.30,绝大多数 In-Tree 存储插件已被迁移至 CSI 驱动(如 aws-ebs-csi-driver、gce-pd-csi-driver)。生产环境应优先使用 CSI 驱动,避免依赖已弃用的 In-Tree 插件。

1.2 云原生存储的核心挑战

在分布式、动态调度的云原生环境中,存储系统面临与传统虚拟化或物理机时代截然不同的挑战。理解这些挑战,是设计存储架构和选择 CSI 驱动的前提。

1.2.1 挑战一:有状态应用的调度约束

Kubernetes 的调度器默认将 Pod 视为无状态实体,可以调度到任意节点。但使用本地 SSD 或特定可用区云盘的 Pod,必须运行在数据所在的节点上。这种 拓扑约束 要求存储系统必须向调度器暴露位置信息:

  • 延迟绑定:PVC 的 PV 绑定操作推迟到 Pod 调度决策之后,确保存储卷与 Pod 在同一可用区。
  • 拓扑感知调度:CSI 驱动通过 CSINode 和 CSIDriver 对象向调度器报告可访问的拓扑域。

1.2.2 挑战二:持久化数据的生命周期管理

Pod 的 ephemeral 特性与数据的持久化需求存在天然矛盾。云原生存储需要解决:

场景 问题 CSI 解决方案
Pod 重建 新 Pod 可能调度到不同节点,旧数据不可达 PV 的 NodeAffinity + 远程存储(NFS、CephFS)
存储扩容 传统存储扩容需要停机 CSI 的 ControllerExpandVolume 在线扩容
数据备份 分布式环境下一致性快照困难 CSI 快照 + VolumeSnapshotClass 策略
灾难恢复 跨集群数据迁移缺乏标准接口 CSI 克隆 + Velero 等备份工具集成

1.2.3 挑战三:性能与可观测性

云原生存储的 I/O 路径比传统架构更长:应用程序 → 容器文件系统 → CSI 节点驱动 → 存储网络 → 存储后端。每个环节都可能成为瓶颈:

  • IOPS 与延迟:CSI 驱动在用户态处理 gRPC 调用,相比内核态 In-Tree 插件存在额外开销。
  • 监控缺失:传统存储的 Prometheus Exporter 需要适配 CSI 指标格式(如 csi_volume_stats)。
  • QoS 保障:多租户场景下,如何限制单个 Pod 的存储吞吐量仍是 CSI 规范的待完善领域。
云原生存储 I/O 路径与挑战 应用 Pod 容器文件系统 CSI Node Driver 存储网络 核心挑战 1. 调度约束:存储卷位置必须与 Pod 调度节点匹配(拓扑感知) 2. 生命周期:Pod 重建后数据可达性、在线扩容、快照一致性 3. 性能开销:gRPC 用户态调用 vs 内核态 In-Tree 插件的延迟差异 4. 可观测性:CSI 指标标准化不足,多租户 QoS 缺乏原生支持

1.2.4 挑战四:安全与多租户隔离

在共享集群中,不同团队或应用的存储资源必须严格隔离:

  • 存储类(StorageClass)隔离:通过 allowedTopologies 和 mountOptions 限制特定租户只能使用特定存储后端。
  • 卷加密:CSI 驱动支持在存储层启用加密(如 LUKS、云盘加密),但密钥管理需要与 Kubernetes 的 Secret 或外部 KMS 集成。
  • 访问控制:RBAC 规则需要精细到 VolumeAttachment 和 CSIDriver 对象的操作权限。
常见陷阱: 部分 CSI 驱动默认允许跨命名空间的 PV 访问。生产环境务必通过 StorageClass 的 reclaimPolicy 和 volumeBindingMode 明确隔离策略,避免数据泄露。

1.3 本章小结