K8s 系列 | 第 14 天:CSI 存储插件与生产存储选型指南


title: K8s 系列 | 第 14 天:CSI 存储插件与生产存储选型指南
tags:
– Kubernetes
– K8s系列
– CSI
– Storage
– DevOps
– 存储插件
– 生产运维


K8s 系列 | 第 14 天:CSI 存储插件与生产存储选型指南

第 14/30 天


一、引言

在之前的文章中,我们深入学习了 Kubernetes 存储体系的核心概念——PersistentVolume(PV)、PersistentVolumeClaim(PVC)、StorageClass 以及动态存储供给。然而,随着存储技术的不断演进,Kubernetes 内部原生的 in-tree 存储插件(代码直接编译在 kube-controller-manager 中)逐渐暴露出维护困难、升级耦合、扩展性不足等问题。为此,业界推出了 CSI(Container Storage Interface)——一个标准化的存储插件接口协议,彻底改变了 K8s 与存储系统的集成方式。

今天我们将深入解析 CSI 的工作原理,并通过实战部署一个 CSI 驱动(以 NFS CSI Driver 为例),最后全面对比主流生产存储方案,帮助你为生产集群做出正确的存储选型决策。


二、CSI 是什么?为什么需要它?

2.1 In-tree 插件的痛点

在 CSI 出现之前,Kubernetes 的存储插件以 in-tree 方式嵌入核心代码仓库。这意味着:

  • 升级存储驱动必须升级整个 K8s 集群 —— 哪怕只是修复一个 NFS 驱动的 bug,也得等待 K8s 大版本发布。
  • 不同存储厂商的代码合入 K8s 核心仓库 —— 审查流程漫长,代码质量参差不齐。
  • 仅支持有限的存储后端 —— 新增一种存储系统要等社区合入。

2.2 CSI 的核心思想

CSI 将存储驱动从 K8s 核心代码中解耦出来,定义为三个标准的 gRPC 服务

服务 作用
Identity Service 标识驱动名称、能力、版本信息
Controller Service 负责卷的创建、删除、快照、扩容等控制面操作
Node Service 负责将卷挂载到节点上、格式化、卸载等节点面操作

每个 CSI 驱动以独立的 Pod 运行在容器中,通过 Unix Domain Socket 与 kubelet 通信。这意味着:

  • 存储驱动可以独立升级 —— 像部署普通应用一样更新 CSI 驱动。
  • 任何存储系统都能成为 CSI 驱动 —— 厂商只需实现三个 gRPC 接口。
  • Kubernetes 核心代码不再膨胀 —— 存储逻辑完全外置。

2.3 CSI 架构概览

┌─────────────────────────────────────┐
│            kube-controller-manager   │
│  ┌──────────────┐                   │
│  │ AttachDetach │──gRPC──▶ CSI      │
│  │   Controller  │       Controller │
│  └──────────────┘       (external)  │
├─────────────────────────────────────┤
│  kubelet (每个 Node)                 │
│  ┌──────────┐                      │
│  │ Device   │──gRPC──▶ CSI Node    │
│  │ Manager  │       (external)     │
│  └──────────┘                      │
└─────────────────────────────────────┘
          │
          ▼
    ┌──────────┐
    │ 存储后端   │
    │ (NFS/CEPH │
    │  /AWS EBS │
    │  /vSphere)│
    └──────────┘

CSI 架构中,Sidecar 容器扮演着关键的桥接角色:

  • external-provisioner:监听 PVC 创建事件,调用 CSI Controller 的 CreateVolume
  • external-attacher:监听 VolumeAttachment,调用 CSI Controller 的 ControllerPublishVolume
  • external-resizer:监听 PVC 扩容请求,调用 CSI Controller 的 ControllerExpandVolume
  • external-snapshotter:监听 VolumeSnapshot 对象,调用 CSI Controller 的 CreateSnapshot

这些 Sidecar 与 CSI 驱动运行在同一个 Pod 中,形成一个功能完备的 CSI 驱动单位。


三、实战:部署 NFS CSI Driver

下面我们通过部署 NFS CSI Driver,演示一个完整的 CSI 驱动从安装到使用的全过程。

3.1 前提条件

已有运行中的 Kubernetes 集群(版本 1.20+),以及一台 NFS 服务器(假设 IP 为 192.168.1.100)。

3.2 部署 NFS CSI Driver

# 添加 Helm 仓库
helm repo add csi-driver-nfs https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/master/charts
helm repo update

# 安装 NFS CSI Driver
helm install csi-driver-nfs csi-driver-nfs/csi-driver-nfs 
  --namespace kube-system 
  --version v4.9.0

# 验证驱动状态
kubectl -n kube-system get pods -l app=csi-driver-nfs

预期输出:

NAME                                    READY   STATUS    RESTARTS   AGE
csi-driver-nfs-controller-0             4/4     Running   0          45s
csi-driver-nfs-node-abcde               3/3     Running   0          45s
csi-driver-nfs-node-fghij               3/3     Running   0          45s

注意:Controller Pod 有 4 个容器(NFS 驱动 + provisioner + attacher + resizer 三个 Sidecar),Node Pod 有 3 个容器(NFS 驱动 + node-driver-registrar + livenessprobe)。

3.3 创建 StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
  server: 192.168.1.100          # NFS 服务器地址
  share: /exported/path          # NFS 共享路径
  # 可选参数
  mountPermissions: "0777"
reclaimPolicy: Retain
volumeBindingMode: Immediate
allowVolumeExpansion: true

3.4 使用动态供给创建 PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc-test
spec:
  accessModes:
    - ReadWriteMany        # NFS 支持 RWX 模式
  storageClassName: nfs-csi
  resources:
    requests:
      storage: 10Gi
kubectl apply -f nfs-pvc.yaml
kubectl get pvc nfs-pvc-test

3.5 挂载到 Pod 中使用

apiVersion: v1
kind: Pod
metadata:
  name: nfs-test-pod
spec:
  containers:
    - name: app
      image: nginx:alpine
      volumeMounts:
        - name: nfs-storage
          mountPath: /data
  volumes:
    - name: nfs-storage
      persistentVolumeClaim:
        claimName: nfs-pvc-test
kubectl exec nfs-test-pod -- df -h /data
kubectl exec nfs-test-pod -- touch /data/test-$(date +%s).txt

如果以上命令都成功,说明 NFS CSI Driver 已经正常工作。


四、主流生产存储方案对比

生产环境中选择存储方案时,需要考虑性能、可靠性、成本、运维复杂度等多个维度。以下是主流方案的对比:

存储方案 类型 访问模式 性能 适用场景 运维复杂度
NFS (CSI) 文件存储 RWX 中等,受网络影响 共享文件、静态内容、CI/CD 缓存 ⭐⭐ 低
Ceph RBD 块存储 RWO/RWX(需CSI) 数据库、有状态应用 ⭐⭐⭐⭐⭐ 高
CephFS 文件存储 RWX 中等 共享文件系统 ⭐⭐⭐⭐⭐ 高
Longhorn 分布式块 RWO/RWX 中等 小型 K8s 集群、边缘 ⭐⭐⭐ 中
Rook-Ceph 块/文件/对象 三者皆可 生产环境大规模 ⭐⭐⭐⭐⭐ 高
OpenEBS 块存储 RWO/RWX 中等偏上 有状态工作负载 ⭐⭐⭐ 中
AWS EBS (CSI) 块存储 RWO 极高 (SSD) AWS 云原生应用 ⭐ 低
AWS EFS (CSI) 文件存储 RWX 中等 共享存储、Serverless ⭐ 低
Azure Disk (CSI) 块存储 RWO Azure 云原生 ⭐ 低
GCE PD (CSI) 块存储 RWO GCP 云原生 ⭐ 低
vSphere CSI 块存储 RWO 已有 VMware 环境 ⭐⭐ 低中

4.1 选型建议

小型集群/开发测试(1-10 节点):

推荐 NFS CSI + Longhorn 组合
├── NFS CSI:日志、备份、静态文件(低成本共享)
└── Longhorn:数据库、有状态应用(内置 UI 管理简单)

生产环境(10-50 节点):

推荐 Rook-Ceph(块 + 文件双通道)
├── RBD:数据库(MySQL/PostgreSQL)、消息队列(Kafka)
├── CephFS:共享存储、ML 训练数据、CI artifacts
└── 对象(S3-compatible):备份、媒资存储

云原生环境:

推荐云厂商原生 CSI + 自建 Ceph
├── 核心数据库 → 云厂商块存储 CSI(EBS/Azure Disk)
├── 共享文件 → 云厂商文件存储 CSI(EFS/Azure Files)
└── 跨云灾备 → Rook-Ceph 作为第二存储层

4.2 Ceph RBD 快速示例

如果需要更强的功能和性能,可以使用 Ceph RBD CSI:

# 先通过 Rook 部署 Ceph 集群,然后创建 StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: rook-ceph-block
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
  clusterID: rook-ceph
  pool: replicapool
  imageFormat: "2"
  imageFeatures: layering
  csi.storage.k8s.io/fstype: ext4
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
reclaimPolicy: Delete
allowVolumeExpansion: true

五、CSI 常见问题与排查

5.1 PVC 一直处于 Pending 状态

# 检查 CSI Controller Pod 日志
kubectl -n kube-system logs -l app=csi-driver-nfs-controller -c nfs

# 检查事件
kubectl describe pvc <pvc-name>

常见原因:存储后端不可达、StorageClass 参数错误、CSI 驱动版本与 K8s 版本不兼容。

5.2 Pod 挂载卷失败

# 检查 Node 上的 CSI 驱动日志
kubectl -n kube-system logs -l app=csi-driver-nfs-node -c nfs

# 查看 kubelet 日志(在节点上)
journalctl -u kubelet -n 100 | grep -i csi

常见原因:节点缺少必要的内核模块(如 nfs-common)、SELinux/AppArmor 限制、挂载参数错误。

5.3 卷扩容失败

# 确保 StorageClass 已开启 allowVolumeExpansion
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-csi
allowVolumeExpansion: true  # 关键!

5.4 CSI 驱动版本与 K8s 版本兼容性

K8s 版本 最低 CSI 版本 建议 CSI 版本
1.20-1.22 CSI v1.2 CSI v1.5+
1.23-1.25 CSI v1.5 CSI v1.6+
1.26-1.28 CSI v1.6 CSI v1.9+
1.29+ CSI v1.9 最新

六、总结

今天我们深入探讨了:

  1. CSI 的诞生背景 —— 解决了 in-tree 插件无法独立升级、存储厂商代码合入困难等核心问题。
  2. CSI 的架构设计 —— 通过 Identity/Controller/Node 三个标准 gRPC 接口,将存储驱动从 K8s 核心中解耦。
  3. 实战部署 NFS CSI Driver —— 从 Helm 安装到 Pod 使用,完整演示了 CSI 驱动的生命周期。
  4. 主流存储方案对比 —— 根据集群规模和场景,给出了从 NFS → Longhorn → Rook-Ceph → 云厂商 CSI 的选型路径。

选型共识: 小型集群用 NFS CSI + Longhorn 经济实惠;生产环境选择 Rook-Ceph 提供统一的块/文件/对象存储;云原生环境优先使用云厂商原生 CSI 驱动,降低运维成本。


下期预告

📌 第 15 天:污点与容忍度(Taints & Tolerations)—— 掌控 Pod 调度

我们将深入 Kubernetes 调度系统的核心机制之一:污点与容忍度。你将学会如何用 Taints 标记特殊节点(GPU、SSD 专属节点、管理面隔离),以及如何用 Tolerations 让符合条件的 Pod 突破调度限制,实现真正的精细化调度控制。


📚 系列目录
– 第 1 天:Kubernetes 是什么?核心概念与架构全景解析
– 第 2 天:手把手搭建你的第一个 K8s 集群
– 第 3 天:Pod 详解:生命周期的秘密
– 第 4 天:Deployment 与 ReplicaSet
– 第 5 天:Service 与网络基础
– 第 6 天:Namespace 与资源配额
– 第 7 天:ConfigMap 与 Secret
– 第 8 天:Volume 与 PersistentVolume
– 第 9 天:StorageClass 与动态存储供给
– 第 10 天:StatefulSet:有状态应用
– 第 11 天:Ingress 与 Ingress Controller
– 第 12 天:NetworkPolicy
– 第 13 天:Headless Service 与服务发现
– 第 14 天:CSI 存储插件与生产存储选型指南 ← 本文
– 第 15 天:污点与容忍度 —— 掌控 Pod 调度(即将发布)
– …
– 第 30 天:K8s 生产环境踩坑实录

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容