目录
Please enable Javascript to view the contents

K8s存储-CSI架构详解

 ·  ☕ 5 分钟

系列导航

本系列从 K8s 存储模型入手,逐步展开到 CSI 插件实现与云原生存储全景。

① 概念 → ② Volume 生命周期 → ③ CSI 架构 → ④ FlexVolume 演进 → ⑤ 对比 → ⑥ 排障 ‖ ⑦ 开发 → ⑧ 高级特性 → ⑨ 演进展望

顺序文章定位
概念与入门基础——K8s 存储模型、PV/PVC/StorageClass、Volume 分类树
Volume 生命周期全解析全貌——两阶段处理、动态/静态供应
本篇 - CSI 架构详解标准——gRPC 三服务、Sidecar 模式、External Components
FlexVolume 与 CSI 演进演进——FlexVolume 原理、CSI 设计思想
存储方案对比与选型选型——主流 CSI 插件横向对比 + 决策树
排障思路与常用命令运维——工具链 + 场景排查 + 性能
核心路径 ↑扩展展望 ↓
CSI 插件开发指南扩展——从零开发一个 CSI 插件
高级特性详解进阶——快照、克隆、扩容、拓扑感知
云原生存储演进与展望展望——容器原生存储、DPU 卸载、未来方向

重要

CSI(Container Storage Interface)是跨容器编排器的存储接口标准。核心设计:用 gRPC 定义三组服务(Identity / Controller / Node),通过 Sidecar 模式与 K8s 解耦,使存储插件独立于 K8s 主版本发布和升级。


1. CSI 是什么

CSI 是由 Kubernetes、Mesos、Cloud Foundry 联合制定的容器存储接口标准。它定义了一套 gRPC 接口,存储厂商只需实现一次,即可适配所有容器编排平台。

维度CNI(网络)CSI(存储)
接口形式可执行文件 + 环境变量 + stdin/stdoutgRPC
调用方kubelet 直接 forkkubelet + Sidecar 组件
生命周期Pod 创建/销毁Volume 创建/删除/挂载/卸载/快照/扩容
插件部署二进制 + DaemonSet容器化(Deployment + DaemonSet)

2. 三组 gRPC 服务

CSI 规范定义了三组服务,分别处理不同层级的操作:

2.1 Identity Service(身份服务)

接口说明
GetPluginInfo返回插件名称和版本
GetPluginCapabilities返回插件支持的能力(Controller 服务、Topology)
Probe健康检查

Identity Service 由 CSI 插件本身实现,无论是 Controller 还是 Node 组件都需要响应。

2.2 Controller Service(控制器服务)

在集群级别运行(Deployment),负责 Volume 的创建、删除、挂接/卸接:

接口说明触发方
CreateVolume创建底层存储资源external-provisioner
DeleteVolume删除底层存储资源external-provisioner
ControllerPublishVolumeAttach:将存储挂接到节点external-attacher
ControllerUnpublishVolumeDetach:从节点卸接存储external-attacher
ControllerExpandVolume在线扩容底层存储external-resizer
CreateSnapshot创建快照external-snapshotter
DeleteSnapshot删除快照external-snapshotter

2.3 Node Service(节点服务)

在每个节点上运行(DaemonSet),负责 Volume 的挂载/卸载:

接口说明触发方
NodeStageVolume将块设备格式化并挂载到全局目录kubelet
NodeUnstageVolume从全局目录卸载kubelet
NodePublishVolumebind mount 到 Pod 容器目录kubelet
NodeUnpublishVolume从 Pod 容器目录卸载kubelet
NodeExpandVolume扩容文件系统kubelet
NodeGetCapabilities返回 Node 服务能力kubelet
Controller Service 管的是"存储资源"(创建/删除/Attach),Node Service 管的是"节点上的挂载"(Stage/Publish/Mount)。两阶段处理 = ControllerPublish(Attach)+ NodeStage+NodePublish(Mount)。

3. Sidecar 模式

CSI 插件不直接与 K8s API 交互。K8s 社区提供了一组 External Components(Sidecar),负责监听 K8s API 并调用 CSI gRPC 接口:

K8s API Server
  ↓ 监听 PVC/VolumeAttachment/VolumeSnapshot 等 CRD
External Components(Sidecar)
  ├── external-provisioner    → 监听 PVC,调 CreateVolume/DeleteVolume
  ├── external-attacher       → 监听 VolumeAttachment,调 ControllerPublish/Unpublish
  ├── external-snapshotter    → 监听 VolumeSnapshot,调 CreateSnapshot/DeleteSnapshot
  ├── external-resizer        → 监听 PVC 扩容请求,调 ControllerExpandVolume
  └── node-driver-registrar   → 向 kubelet 注册 CSI 插件
  ↓ gRPC
CSI Plugin(Identity + Controller + Node)
  ↓
底层存储(Ceph / NFS / 云盘 / ...)

3.1 各 Sidecar 职责

Sidecar监听对象调用 CSI 接口部署位置
external-provisionerPVCCreateVolume / DeleteVolumeController Pod
external-attacherVolumeAttachmentControllerPublish / UnpublishController Pod
external-snapshotterVolumeSnapshotCreateSnapshot / DeleteSnapshotController Pod
external-resizerPVC(容量变更)ControllerExpandVolumeController Pod
node-driver-registrarkubelet 注册NodeGetInfo / NodeGetCapabilitiesNode Pod(DaemonSet)
liveness-probe健康检查Probe两个 Pod 都有

4. 部署模式

CSI 插件通常部署为两个组件:

4.1 Controller 组件(Deployment)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 简化示例
apiVersion: apps/v1
kind: Deployment
metadata:
  name: csi-controller
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: csi-plugin          # CSI 插件(Controller + Identity 服务)
          image: csi-driver:v1.0
          args: ["--endpoint=unix:///csi/csi.sock"]
        - name: csi-provisioner     # Sidecar:动态供应
          image: csi-provisioner:v3.0
          args: ["--csi-address=/csi/csi.sock"]
        - name: csi-attacher        # Sidecar:Attach/Detach
          image: csi-attacher:v4.0
          args: ["--csi-address=/csi/csi.sock"]
        - name: csi-snapshotter     # Sidecar:快照
          image: csi-snapshotter:v6.0
          args: ["--csi-address=/csi/csi.sock"]
        - name: csi-resizer         # Sidecar:扩容
          image: csi-resizer:v1.0
          args: ["--csi-address=/csi/csi.sock"]

4.2 Node 组件(DaemonSet)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: csi-node
spec:
  template:
    spec:
      containers:
        - name: csi-plugin          # CSI 插件(Node + Identity 服务)
          image: csi-driver:v1.0
          args: ["--endpoint=unix:///csi/csi.sock"]
          securityContext:
            privileged: true        # 需要 mount/格式化权限
          volumeMounts:
            - name: plugin-dir
              mountPath: /csi
            - name: mount-dir
              mountPath: /var/lib/kubelet
              mountPropagation: Bidirectional
        - name: node-driver-registrar  # Sidecar:向 kubelet 注册
          image: csi-node-driver-registrar:v2.0
          args: ["--csi-address=/csi/csi.sock"]
      volumes:
        - name: plugin-dir
          hostPath: { path: /var/lib/kubelet/plugins/csi-driver }
        - name: mount-dir
          hostPath: { path: /var/lib/kubelet, type: Directory }
Controller Pod 跑在任意节点,负责集群级操作(创建/删除/Attach)。Node Pod 跑在每个节点上(DaemonSet),负责本地操作(Mount/Unmount)。两者通过同一镜像不同启动参数实现。

5. 完整调用链

以动态供应一个云盘 Volume 为例:

1. 用户创建 PVC(storageClassName=fast)
2. external-provisioner 监听到 PVC → 调 CSI CreateVolume
3. CSI 插件调用云 API 创建云盘 → 返回 Volume ID
4. external-provisioner 创建 PV 对象 → PVC 绑定
5. Pod 被调度到 Node-A
6. AD Controller 创建 VolumeAttachment 对象
7. external-attacher 监听到 → 调 CSI ControllerPublishVolume(Attach)
8. CSI 插件将云盘挂接到 Node-A → 返回成功
9. kubelet 调 CSI NodeStageVolume(格式化 + 挂载到全局目录)
10. kubelet 调 CSI NodePublishVolume(bind mount 到容器目录)
11. Pod Ready,容器可读写 Volume

6. CSI 与 K8s 版本兼容

CSI SpecK8s 版本主要特性
v0.31.13+基础供应、Attach/Mount
v1.01.13+GA,稳定接口
v1.11.14+拓扑感知、卷扩容
v1.21.15+快照 GA
v1.31.16+卷克隆
v1.5+1.18+单节点多卷

参考链接

分享

Hex
作者
Hex
CloudNative Developer