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 | 最新 |
六、总结
今天我们深入探讨了:
- CSI 的诞生背景 —— 解决了 in-tree 插件无法独立升级、存储厂商代码合入困难等核心问题。
- CSI 的架构设计 —— 通过 Identity/Controller/Node 三个标准 gRPC 接口,将存储驱动从 K8s 核心中解耦。
- 实战部署 NFS CSI Driver —— 从 Helm 安装到 Pod 使用,完整演示了 CSI 驱动的生命周期。
- 主流存储方案对比 —— 根据集群规模和场景,给出了从 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 生产环境踩坑实录















暂无评论内容