摘要

容器本质上具有临时性,Pod 重启后其中的数据便会丢失。为了在 Pod、节点乃至集群之间持久保存数据,Kubernetes 引入了持久卷(PersistentVolume, PV)和持久卷声明(PersistentVolumeClaim, PVC)的存储抽象体系。这一体系将存储资源的供应与使用解耦,使基础设施管理员能够预置存储,而应用开发者无需关心底层存储细节即可按需申请存储资源。

早期的 Kubernetes 采用 in-tree 存储插件模式,插件代码直接嵌入 Kubernetes 核心代码仓库,导致存储厂商的迭代必须跟随 Kubernetes 发版周期,严重制约了存储生态的发展。容器存储接口(Container Storage Interface, CSI)的诞生彻底改变了这一局面。CSI 是由 CNCF 推出的标准化存储插件框架,它将存储系统与 Kubernetes 解耦,使存储服务以插件形式接入集群,无需修改 Kubernetes 核心代码。从 Kubernetes 1.13 开始,CSI 已成为官方推荐的存储插件实现方式。

本文将从 Kubernetes 存储的基础概念出发,深入剖析 PV 与 PVC 的核心原理、生命周期管理、静态与动态供应机制,然后详细解读 CSI 架构的设计理念与核心组件,并通过主流 CSI 驱动的实战案例(AWS EBS、Longhorn、Rook-Ceph)展示完整的部署配置流程。最后,文章将探讨存储性能调优、故障排查、安全控制以及 AI/ML 场景下的存储演进趋势,帮助读者构建从理论到实践的完整知识体系。

关键词:Kubernetes 存储、PersistentVolume、PersistentVolumeClaim、StorageClass、Container Storage Interface (CSI)、动态供应、卷快照、卷克隆、存储性能优化

一、Kubernetes 存储基础

1.1 从 Volumes 到 PersistentVolumes

Kubernetes 的存储抽象经历了一个渐进式的演进过程。最基础的存储单元是 Volume。Volume 直接定义在 Pod 的 spec 中,生命周期与 Pod 绑定——Pod 创建时 Volume 随之创建,Pod 销毁时 Volume 也随之销毁。常见的 Volume 类型包括 emptyDir、hostPath、configMap、secret 等,适用于临时数据存储和配置注入场景。

然而,对于数据库、消息队列、日志系统等有状态应用,Volume 的生命周期显然无法满足需求。数据需要在 Pod 重启、重新调度甚至集群升级后仍然保留,这正是 PersistentVolume(PV)和 PersistentVolumeClaim(PVC)要解决的核心问题。

PV 是集群中的一块存储资源,由管理员预先供应或通过 StorageClass 动态创建,其生命周期独立于任何使用它的 Pod。PVC 则是用户对存储的请求,类似于 Pod 消耗 Node 资源,PVC 消耗 PV 资源。PV 和 PVC 的引入使应用程序和开发者能够以声明式的方式请求存储资源,而无需处理存储设施的底层细节。

1.2 PV/PVC 核心概念

PersistentVolume(PV)

PV 是一个集群级别的资源对象,不属于任何命名空间。PV 的 spec 中封装了底层存储的实现细节,包括存储容量、访问模式、存储类名称、回收策略以及具体的后端配置(如 NFS 服务器地址、iSCSI 目标等)。PV 可以理解为一份存储资源的“资源广告”,向集群宣告“我有 100Gi 的存储空间,支持 RWO 访问模式”。

PersistentVolumeClaim(PVC)

PVC 是一个命名空间级别的资源对象,代表用户对存储资源的需求。PVC 的 spec 中指定了所需存储的最小容量、期望的访问模式以及可选的 StorageClass 名称。当 PVC 被创建时,Kubernetes 的 PV 控制器会尝试将其与一个满足条件的可用 PV 进行绑定。绑定完成后,Pod 即可通过引用 PVC 来使用该存储卷。

StorageClass

StorageClass 是一个集群级别的资源对象,由管理员创建,定义了不同服务质量(QoS)和备份策略的存储类型模板。StorageClass 的核心字段包括:

  • provisioner:指定用于动态创建 PV 的存储插件

  • parameters:传递给 provisioner 的参数,如磁盘类型、副本数等

  • reclaimPolicy:PVC 删除后 PV 的处理策略(Delete 或 Retain)

  • volumeBindingMode:卷绑定模式(Immediate 或 WaitForFirstConsumer)

  • allowVolumeExpansion:是否允许卷扩容

1.3 PV 的生命周期

PV 的生命周期包含四个状态阶段:

状态 含义
Available PV 已创建且可用,尚未绑定任何 PVC
Bound PV 已与某个 PVC 绑定
Released PVC 已被删除,但 PV 上的数据尚未回收
Failed 自动回收失败

PV 从创建到销毁的完整生命周期包括三个核心环节:供应(Provisioning) 、绑定(Binding) 和 回收(Reclaiming) 。供应环节决定 PV 的创建方式(静态或动态),绑定环节由 PV 控制器负责将 PVC 与匹配的 PV 进行关联,回收环节则定义 PVC 删除后 PV 的处理策略。回收策略主要有两种:Retain 策略保留 PV 和数据供管理员手动处理,Delete 策略则自动删除 PV 及其底层存储资产。Recycle 策略(简单擦除数据)已被废弃,官方建议使用动态供应替代。

1.4 访问模式详解

Kubernetes PV 支持四种访问模式,决定了存储卷如何被挂载到 Pod 上:

访问模式 缩写 说明
ReadWriteOnce RWO 卷可以被单个节点以读写方式挂载
ReadOnlyMany ROX 卷可以被多个节点以只读方式挂载
ReadWriteMany RWX 卷可以被多个节点以读写方式挂载
ReadWriteOncePod RWOP 卷可以被单个 Pod 以读写方式挂载(K8s v1.27+)

需要特别注意的是,并非所有存储类型都支持所有访问模式。块存储(如 AWS EBS、GCE Persistent Disk)通常仅支持 RWO,而分布式文件系统(如 NFS、CephFS)则支持 RWX。一个 PVC 只能使用一种访问模式。

1.5 静态供应与动态供应

PV 的供应方式分为静态供应和动态供应两种。

静态供应(Static Provisioning)

静态供应由管理员预先创建一批 PV 对象,每个 PV 明确指定底层存储的详细信息(如 NFS 服务器的地址和导出路径)。当用户创建 PVC 时,PV 控制器会从可用的 PV 池中查找与 PVC 请求(容量、访问模式、StorageClass)匹配的 PV 进行绑定。

静态供应适用于以下场景:

  • 使用已有的存储资产(如已存在的 NFS 共享、SAN LUN)

  • 需要精确控制 PV 与底层存储的映射关系

  • 存储后端不支持动态供应

动态供应(Dynamic Provisioning)

动态供应通过 StorageClass 实现按需自动创建 PV。当用户创建 PVC 并指定了 StorageClass 时,如果集群中没有匹配的静态 PV,StorageClass 中指定的 provisioner 会自动调用底层存储 API 创建新的存储卷和对应的 PV 对象。

动态供应的优势在于:

  • 消除管理员手动创建 PV 的运维负担

  • 实现存储资源的按需分配,提高资源利用率

  • 与云原生理念一致,基础设施即代码

  • 动态供应是生产环境中推荐的首选方式

二者的核心区别在于:静态供应是“先有 PV,后有 PVC”的预分配模式,而动态供应是“PVC 触发 PV 自动创建”的按需模式。无论哪种方式,最终 PVC 都会绑定到一个 PV 上。

二、StorageClass 深入解析

2.1 StorageClass 的核心作用

StorageClass 在 Kubernetes 存储体系中扮演着承上启下的关键角色。对下,它定义了如何调用具体的存储插件(provisioner)以及传递哪些参数;对上,它为用户提供了选择不同存储类型(如高性能 SSD、低成本 HDD、分布式存储等)的抽象接口。

StorageClass 的核心设计目标是为管理员提供一种能力:能够提供在容量和访问模式之外具有不同属性(如性能、备份策略、加密要求)的 PV,同时无需向用户暴露存储实现细节。

2.2 StorageClass 字段详解

一个完整的 StorageClass YAML 示例如下:

yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd-storage
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  encrypted: "true"
  iops: "16000"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
mountOptions:
  - debug
  - noatime

各字段的含义如下:

  • provisioner(必需):指定用于创建 PV 的存储插件名称。对于云环境,可以是 ebs.csi.aws.com(AWS EBS)、pd.csi.storage.gke.io(GCE PD)、disk.csi.azure.com(Azure Disk)等;对于自建环境,可以是 rancher.io/local-pathdriver.longhorn.io 等。

  • parameters:传递给 provisioner 的键值对参数,具体支持哪些参数取决于所使用的 CSI 驱动。

  • reclaimPolicy:PVC 删除后 PV 的处理策略,默认为 Delete。Retain 策略下 PV 会进入 Released 状态,需要管理员手动清理。

  • volumeBindingMode:卷绑定模式,有两种取值:

    • Immediate(默认):PVC 创建后立即进行 PV 供应和绑定,无论 Pod 是否已调度。

    • WaitForFirstConsumer:PV 的创建和绑定延迟到第一个使用该 PVC 的 Pod 被调度时再进行。这种模式对于拓扑感知存储(如本地 SSD、区域性云磁盘)尤其重要,可以确保 PV 创建在 Pod 所调度的节点所在区域。

  • allowVolumeExpansion:是否允许 PVC 扩容。设置为 true 时,用户可以通过修改 PVC 的 storage 字段来触发底层存储卷的扩容。

  • mountOptions:挂载卷时传递给 mount 命令的额外选项。

2.3 默认 StorageClass 的配置

通过 storageclass.kubernetes.io/is-default-class: "true" 注解,可以将某个 StorageClass 设置为集群的默认存储类。设置了默认 StorageClass 后,创建 PVC 时不指定 storageClassName 字段,Kubernetes 会自动使用默认 StorageClass 进行动态供应。

2.4 多 StorageClass 的设计模式

在生产环境中,推荐创建多个 StorageClass 以满足不同工作负载的存储需求。常见的设计模式包括:

  • 高性能存储类:使用 SSD 或 NVMe 后端,配置高 IOPS,适用于数据库、缓存等延迟敏感型应用。

  • 低成本存储类:使用 HDD 后端,适用于归档、日志存储等对性能要求不高的场景。

  • 高可用存储类:配置多副本或跨区域复制,适用于关键业务数据。

  • 本地存储类:使用节点本地磁盘,提供极低延迟但无跨节点高可用,适用于临时高性能计算场景。

通过为不同 StorageClass 配置不同的 reclaimPolicy、volumeBindingMode 和参数,管理员可以构建精细化的存储服务体系。

三、CSI 架构深度解析

3.1 从 In-tree 到 Out-of-tree:CSI 的演进背景

在 CSI 出现之前,Kubernetes 采用 in-tree 存储插件模式。所谓 in-tree,即存储插件的代码直接嵌入 Kubernetes 核心代码仓库中,与 kubelet、kube-controller-manager 等核心组件一同进行统一构建、编译和发布。这种模式存在几个根本性问题:

  • 耦合严重:存储厂商的插件迭代必须跟随 Kubernetes 的发版周期。一个新功能的发布可能需要等待数月甚至更长时间。

  • 代码膨胀:随着支持的存储类型越来越多,Kubernetes 核心代码库日益臃肿。

  • 安全风险:存储插件代码运行在核心组件进程中,任何一个插件的 bug 都可能影响整个集群的稳定性。

  • 社区压力:Kubernetes 维护者需要审核大量存储相关的 PR,分散了对核心功能的关注。

CSI 的诞生正是为了解决这些问题。CSI 是 CNCF 推出的标准化存储插件框架,其核心设计思想是通过定义统一的 gRPC 接口规范,允许存储厂商以 out-of-tree 方式开发自定义存储插件,无需将插件源码嵌入 Kubernetes 源码仓库,从而实现存储功能的独立构建、编译和发布。

3.2 CSI 规范概述

CSI 规范定义了容器编排系统(CO,Container Orchestrator)与存储系统之间的标准接口。任何遵循 CSI 规范的存储插件都可以与任何支持 CSI 的容器编排系统(包括 Kubernetes、Mesos、Swarm 等)配合工作。

CSI 的核心是定义了一组 gRPC 服务接口,包括:

  • Identity Service:用于 CO 识别插件的身份和能力(如插件名称、支持的 CSI 版本、是否支持卷扩容等)。

  • Controller Service:用于 CO 管理存储卷的生命周期,包括创建卷、删除卷、将卷挂载到节点、从节点卸载卷、创建快照、恢复快照等。

  • Node Service:用于 CO 在节点级别管理卷的挂载和卸载,包括将卷准备好供 Pod 使用(Stage/Unstage)以及将卷发布到特定 Pod(Publish/Unpublish)。

CSI 驱动需要实现这些接口中与自身能力相关的部分。例如,一个仅支持块存储的驱动可能不需要实现 NodeStageVolume(如果其存储系统不需要在发布前进行额外的 staging 步骤)。

3.3 CSI 架构组件

一个典型的 CSI 驱动在 Kubernetes 中部署为一组 Pod,主要包括控制器插件和节点插件两大组件。

控制器插件(Controller Plugin)

控制器插件运行在 Deployment 中,负责处理存储卷的管理操作。它通常与多个 CSI sidecar 容器协同工作:

Sidecar 组件 功能 监控的资源
External Provisioner 监控 PVC 对象,触发 CreateVolume 调用 PVC
External Attacher 监控 VolumeAttachment 对象,触发 ControllerPublishVolume 调用 VolumeAttachment
External Snapshotter 监控 VolumeSnapshot 对象,触发 CreateSnapshot 调用 VolumeSnapshot
External Resizer 监控 PVC 的扩容请求,触发 ControllerExpandVolume 调用 PVC
External Health Monitor 监控卷的健康状态 PV/PVC

这些 sidecar 容器以“边车”模式运行在控制器 Pod 中,它们负责监听 Kubernetes API 服务器上的特定资源变化,并通过 gRPC 调用 CSI 驱动的 Controller Service 接口来完成相应的存储操作。

节点插件(Node Plugin)

节点插件以 DaemonSet 的形式部署在每个 Worker 节点上,负责处理本节点上的卷挂载操作。节点插件的核心任务包括:

  • 将存储卷附加(attach)到节点(对于需要节点级别设备映射的存储类型)

  • 将存储卷挂载(mount)到 Pod 的文件系统中

  • 在 Pod 停止时执行卸载(umount)和分离(detach)操作

节点插件同样与 sidecar 容器配合工作。Node Driver Registrar 是一个关键的 sidecar,它负责向 kubelet 注册 CSI 驱动,使 kubelet 能够调用节点插件的 Node Service 接口来执行卷的挂载和卸载。

3.4 CSI 工作流程详解

从 Pod 创建到存储卷挂载完成的完整 CSI 工作流程如下:

  1. PVC 创建阶段:用户创建 PVC(可能指定了 StorageClass)。External Provisioner sidecar 监听到 PVC 创建事件,调用 CSI 驱动的 CreateVolume gRPC 方法。CSI 驱动与底层存储 API 交互,创建实际的存储卷(如云磁盘、NFS 导出等)。

  2. PV 创建阶段:CSI 驱动返回卷的信息(卷 ID、容量、访问模式等),External Provisioner 据此创建对应的 PV 对象。PV 控制器将 PVC 与该 PV 绑定。

  3. Pod 调度阶段:调度器根据 Pod 的资源需求和节点约束(包括卷的拓扑约束)选择合适的节点。

  4. 卷附加阶段:AD 控制器创建 VolumeAttachment 对象。External Attacher sidecar 监听到该对象,调用 CSI 驱动的 ControllerPublishVolume 方法,将存储卷附加到目标节点(对于块存储而言,这意味着将云磁盘挂载到云服务器的块设备)。

  5. 卷 Stage 阶段:kubelet 调用 CSI 节点驱动的 NodeStageVolume 方法,将附加到节点的块设备格式化并挂载到一个全局 staging 路径。

  6. 卷 Publish 阶段:kubelet 调用 CSI 节点驱动的 NodePublishVolume 方法,将 staging 路径绑定挂载(bind mount)到 Pod 的指定目录。

  7. Pod 删除阶段:当 Pod 被删除时,上述过程逆向执行:NodeUnpublishVolume、NodeUnstageVolume、ControllerUnpublishVolume,最后调用 DeleteVolume 删除存储卷(如果 PVC 的 reclaimPolicy 为 Delete)。

3.5 CSIDriver 对象

Kubernetes 引入了 CSIDriver 资源对象来捕获关于集群上部署的 CSI 驱动的元信息。CSIDriver 对象告诉 Kubernetes 如何与该 CSI 驱动交互:

yaml

apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
  name: ebs.csi.aws.com
spec:
  attachRequired: true
  podInfoOnMount: true
  volumeLifecycleModes:
    - Persistent
    - Ephemeral
  • attachRequired:指示在挂载卷之前是否需要执行附加操作。块存储通常需要,NFS 等共享存储则不需要。

  • podInfoOnMount:如果为 true,kubelet 会在调用 NodePublishVolume 时将 Pod 信息(如 Pod 名称、命名空间、UID 等)传递给 CSI 驱动。

  • volumeLifecycleModes:声明驱动支持的卷生命周期模式,包括 Persistent(持久卷)和 Ephemeral(临时卷)。

四、主流 CSI 驱动对比与实战

4.1 CSI 驱动的生态概览

CSI 生态已经非常成熟。截至 2026 年初,Kubernetes 官方文档列出的 CSI 驱动涵盖了几乎所有主流存储系统,包括云服务商的块存储和文件存储(AWS EBS、GCE PD、Azure Disk、Azure File)、开源分布式存储(Ceph、Longhorn、OpenEBS)、企业存储(NetApp、Portworx、vSphere)以及网络文件系统(NFS、SMB)等。

选择 CSI 驱动时,通常面临两种路径的抉择:

  • 云托管路径:使用云服务商提供的 CSI 驱动(如 AWS EBS CSI、Azure Disk CSI),适用于云托管集群。

  • 云无关路径:使用开源存储系统(如 Rook-Ceph、Longhorn、OpenEBS),适用于本地部署和自管理集群。

4.2 主流开源存储方案对比

对于裸金属、本地部署或混合云环境,开源分布式存储系统是核心选择。根据架构设计,这些方案可以分为两大阵营:

  • 共享存储架构:各节点贡献本地磁盘组成分布式存储池,数据跨节点复制以实现高可用。代表产品包括 Rook-Ceph、Longhorn、OpenEBS Mayastor。

  • 本地存储架构:卷固定在数据所在节点,无数据复制,性能最优但无跨节点高可用。代表产品包括 TopoLVM、OpenEBS Local PV。

下表对当前主流的三个开源方案进行详细对比:

维度 Longhorn Rook-Ceph OpenEBS
当前版本 v1.11.0 v1.19 基于 SPDK 的高性能引擎
CNCF 状态 孵化中(Incubating) 已毕业(Graduated) 孵化中
架构模式 微服务式:每个卷独立控制器 分布式对象存储 + RBD/CephFS 多种引擎可选
资源消耗 较低(约 300MB RAM/节点基线) 较高(推荐 3+ 专用节点) 视引擎而定
管理界面 内置 Web UI 通过 Rook 工具,无内置 UI 通过 Operator
卷副本 默认 3 副本,可配置 灵活配置(Pool 级别) 视引擎而定
快照/克隆 ✅ 支持 ✅ 支持 ✅ 支持
卷扩容 ✅ 在线扩容 ✅ 在线扩容 ✅ 在线扩容
备份支持 ✅ NFS/S3 备份 ✅ RBD 导出 ✅ Velero 集成
适用场景 中小规模、追求易用性 大规模、企业级存储 混合场景、边缘计算

Longhorn 由 Rancher Labs 开发,是目前最容易上手的 Kubernetes 原生分布式块存储系统。它采用微服务架构,每个卷有独立的控制器,故障隔离性强——一个卷的控制器崩溃只影响该卷而非整个集群。Longhorn 的 Web UI 提供了卷管理、快照调度、备份配置等可视化功能。资源消耗方面,Longhorn 每个 Worker 节点基线约消耗 300MB 内存(不计卷副本占用)。

Rook-Ceph 是 CNCF 已毕业的项目,也是最成熟的方案。Ceph 作为底层的分布式存储系统,以高可靠性和丰富的企业级特性著称,但运维复杂度也相应较高。Rook 简化了 Ceph 在 Kubernetes 上的部署和管理,通过 Operator 模式自动化处理 Ceph 集群的生命周期运维。Ceph 同时提供 RBD(块存储)和 CephFS(文件存储)两种存储类型,均通过 CSI 驱动暴露给 Kubernetes。

OpenEBS 的特点是提供多种存储引擎以适应不同场景。其新一代基于 SPDK 的高性能引擎 Mayastor 针对 NVMe 设备优化,可提供极低延迟。同时 OpenEBS 也提供轻量级的 Local PV 引擎,适合边缘计算等资源受限场景。

4.3 AWS EBS CSI 驱动实战

AWS EBS CSI 驱动是云上部署最常用的块存储驱动之一。以下将展示完整的部署和配置流程。

部署 CSI 驱动

在 EKS 集群中,最简便的方式是通过 EKS 附加组件(Add-on)安装:

bash

aws eks create-addon --cluster-name my-cluster --addon-name aws-ebs-csi-driver

对于自管理 Kubernetes 集群,可以通过 Helm 部署:

bash

helm repo add aws-ebs-csi-driver https://kubernetes-sigs.github.io/aws-ebs-csi-driver
helm upgrade --install aws-ebs-csi-driver aws-ebs-csi-driver/aws-ebs-csi-driver \
  --namespace kube-system \
  --set enableVolumeScheduling=true \
  --set enableVolumeResizing=true \
  --set enableVolumeSnapshot=true
IAM 权限配置

EBS CSI 驱动需要 IAM 权限才能调用 AWS EC2 API 管理 EBS 卷。在 EKS 中推荐使用 IAM Roles for Service Accounts(IRSA):

bash

eksctl create iamserviceaccount \
  --name ebs-csi-controller-sa \
  --namespace kube-system \
  --cluster my-cluster \
  --attach-policy-arn arn:aws:iam::aws:policy/service-role/AmazonEBSCSIDriverPolicy \
  --approve
创建 StorageClass

yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-gp3
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
parameters:
  type: gp3
  encrypted: "true"
  iops: "16000"
  throughput: "500"
reclaimPolicy: Delete
使用 PVC 测试

yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-gp3
  resources:
    requests:
      storage: 10Gi

4.4 Longhorn CSI 驱动实战

安装 Longhorn

bash

helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace
配置 StorageClass

yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-replicated
provisioner: driver.longhorn.io
reclaimPolicy: Delete
allowVolumeExpansion: true
parameters:
  numberOfReplicas: "3"
  staleReplicaTimeout: "2880"
  fromBackup: ""
  fsType: ext4

4.5 Rook-Ceph 部署要点

Rook-Ceph 适用于大规模生产环境,但部署复杂度较高。核心步骤包括:

  1. 安装 Rook Operator:kubectl create -f crds.yaml -f common.yaml -f operator.yaml

  2. 创建 Ceph 集群:配置 mon 节点数量、存储设备选择、网络配置等

  3. 部署 CSI 驱动:Rook Operator 会自动部署 Ceph CSI 驱动

  4. 创建 StorageClass:分别针对 RBD(块存储)和 CephFS(文件存储)创建对应的 StorageClass

Rook-Ceph 适合需要企业级存储特性(如多站点复制、纠删码、精细 QoS)的大规模生产环境。

五、高级存储功能

5.1 卷快照(Volume Snapshot)

卷快照是 CSI 提供的一项高级功能,允许用户在特定时间点对存储卷的状态进行快照,以便后续恢复或克隆。CSI 通过 VolumeSnapshot 和 VolumeSnapshotContent 两个 CRD 来实现快照功能。

使用快照功能需要预先安装 CSI Snapshot Controller。创建快照的流程如下:

  1. 确保 StorageClass 对应的 CSI 驱动支持快照功能

  2. 部署 Snapshot Controller 和对应的 CRD

  3. 创建 VolumeSnapshotClass,指定快照的驱动和删除策略

  4. 通过 VolumeSnapshot 对象触发快照创建

yaml

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: my-volume-snapshot
spec:
  volumeSnapshotClassName: my-snapshot-class
  source:
    persistentVolumeClaimName: my-pvc

创建快照后,可以从快照恢复出新的 PVC:

yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: restored-pvc
spec:
  dataSource:
    name: my-volume-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

5.2 卷克隆(Volume Clone)

卷克隆功能允许从现有的 PVC 直接创建一个新的副本卷,新卷中预置了源卷的所有数据。与快照不同,克隆是直接复制源卷的数据,不经过快照对象这一中间环节。

yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cloned-pvc
spec:
  dataSource:
    name: source-pvc
    kind: PersistentVolumeClaim
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi

卷克隆的核心价值在于:

  • 快速环境复制:为测试或开发环境快速复制生产数据

  • 数据隔离:克隆卷与源卷相互独立,修改不会相互影响

  • 零停机迁移:在业务不中断的情况下完成数据迁移

需要注意的是,克隆卷的容量不能小于源卷的容量,CSI 驱动必须支持 CLONE_VOLUME 能力。

5.3 卷扩容(Volume Expansion)

Kubernetes 支持对 PVC 进行在线扩容,前提是底层 StorageClass 设置了 allowVolumeExpansion: true。扩容操作非常简单:

bash

kubectl patch pvc my-pvc -p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'

扩容的注意事项包括:

  • 扩容只能增加容量,不能缩小

  • 对于某些存储类型(如块存储),扩容可能需要 Pod 重启

  • 扩容操作由 External Resizer sidecar 处理

  • 文件系统扩容通常在底层存储扩容后自动执行

六、性能优化与故障排查

6.1 存储性能优化策略

选择合适的 StorageClass

性能优化的第一步是选择合适的存储类型。对于 IOPS 敏感型应用(如数据库、实时分析),应选择 SSD/NVMe 后端的高性能存储类;对于容量敏感型应用(如日志归档),选择低成本存储类更为合理。

使用 WaitForFirstConsumer 绑定模式

默认的 Immediate 绑定模式可能导致 PV 在 Pod 调度之前就被创建,如果 Pod 最终调度到不同的可用区,可能会产生跨区域的网络延迟。使用 WaitForFirstConsumer 可以确保 PV 创建在 Pod 所在区域,减少 I/O 延迟。

调优挂载参数

通过 StorageClass 的 mountOptions 字段可以传递优化参数:

yaml

mountOptions:
  - noatime      # 不更新文件访问时间,减少写操作
  - nodiratime   # 不更新目录访问时间
  - rw           # 读写模式
监控存储利用率

使用 Prometheus 和 Grafana 监控 PVC 的使用趋势,设置容量告警以防止存储空间耗尽。

6.2 常见故障排查指南

PVC 处于 Pending 状态

PVC 长时间处于 Pending 状态是最常见的存储故障。排查步骤如下:

  1. 检查 StorageClass 是否存在kubectl get storageclass,确认 PVC 引用的 StorageClass 名称正确

  2. 检查动态供应器是否正常运行:查看 CSI 控制器 Pod 的状态和日志

  3. 检查 PV 匹配情况kubectl get pv,查看是否有满足条件的 PV

  4. 检查资源配额:确认命名空间的 ResourceQuota 未限制存储请求

Pod 无法挂载 PVC

当 Pod 出现 FailedAttachVolume 或 FailedMount 事件时:

  1. 检查 CSI 节点插件状态kubectl get pods -n kube-system | grep csi,确认 DaemonSet 在每个节点上正常运行

  2. 检查节点间的网络连通性:CSI 驱动与存储后端之间的网络必须通畅

  3. 验证 IAM/认证配置:对于云存储,确认 ServiceAccount 有正确的权限

  4. 检查 PV 和 PVC 的绑定状态kubectl describe pvc <name> 查看事件信息

存储性能骤降

如果应用启动正常但后续性能明显下降,建议通过禁用持久化来定位问题。若禁用后性能恢复正常,说明问题出在 PVC 层。此时可以尝试更换 StorageClass 或调整 Pod 的探针参数(如增加 initialDelaySeconds)。

卷扩容失败

卷扩容失败通常与 CSI 驱动的能力有关。确保 StorageClass 设置了 allowVolumeExpansion: true,且 CSI 驱动支持 EXPAND_VOLUME 能力。

6.3 诊断工具与命令

bash

# 查看 PV/PVC 状态
kubectl get pv,pvc

# 查看 PVC 详情(含事件)
kubectl describe pvc <pvc-name>

# 查看 CSI 组件状态
kubectl get pods -n kube-system | grep csi

# 查看 VolumeAttachment 对象
kubectl get volumeattachments

# 查看 PV 详细配置
kubectl get pv <pv-name> -o yaml

七、存储安全与多租户

7.1 RBAC 权限控制

在多租户 Kubernetes 环境中,存储资源的安全管理至关重要。建议遵循最小权限原则,通过 RBAC 限制对 PV 和 PVC 的操作权限:

  • 普通用户应仅能在其命名空间内创建和管理 PVC,无权操作 PV 级别的资源

  • 使用 Role 和 RoleBinding 进行命名空间级别的权限控制

  • 使用 ClusterRole 和 ClusterRoleBinding 控制集群管理员对 PV/StorageClass 的访问

yaml

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: tenant-a
  name: pvc-manager
rules:
- apiGroups: [""]
  resources: ["persistentvolumeclaims"]
  verbs: ["get", "list", "create", "update", "delete"]
- apiGroups: [""]
  resources: ["persistentvolumes"]
  verbs: ["get", "list"]  # 只能查看,不能创建或删除

7.2 资源配额(ResourceQuota)

使用 ResourceQuota 限制每个命名空间的存储总量,防止某个租户过度消耗存储资源:

yaml

apiVersion: v1
kind: ResourceQuota
metadata:
  name: storage-quota
spec:
  hard:
    requests.storage: 100Gi
    persistentvolumeclaims: "10"

7.3 加密存储

对于敏感数据,应在存储层面启用加密。大多数云 CSI 驱动支持加密参数:

  • AWS EBS:在 StorageClass 中设置 encrypted: "true" 和可选的 kmsKeyId

  • Azure Disk:支持 SSE(服务端加密)

  • GCE PD:支持客户管理的加密密钥(CMEK)

7.4 备份与灾难恢复

对于关键业务数据,必须建立备份和灾难恢复机制。Velero 是 Kubernetes 生态中最成熟的备份工具,可以备份集群资源和 PV 数据到对象存储(如 AWS S3、MinIO),并支持在灾难时进行完整恢复。

Longhorn 提供了内置的备份功能,可以将卷快照备份到 NFS 或 S3 兼容的对象存储,并支持跨集群的灾难恢复卷。

八、未来趋势与展望

8.1 AI/ML 工作负载对存储的挑战

2026 年,AI 工作负载已成为 Kubernetes 增长的主要驱动力。AI 训练任务通常运行数天或数周,需要持续向 GPU 提供 TB 级别的数据。传统的 CSI 架构最初设计面向短暂、无状态的容器场景,在面对 AI/ML 工作负载时暴露出一些局限性:数据加载时间过长影响 GPU 利用率、大规模数据集的编排管理复杂、共享数据集的版本控制和缓存策略欠缺等。

行业正在积极应对这些挑战。解决方案包括:数据感知调度器(将计算调度到数据所在位置)、RDMA 加速的共享存储、分层缓存架构等。

8.2 边缘计算与轻量存储

随着边缘 Kubernetes 的普及,轻量级存储解决方案的需求日益迫切。边缘环境资源受限,网络连接可能不稳定,需要能够在低资源占用下运行的存储方案。K3s 等轻量级发行版对 Local PV 和 Longhorn 的支持日趋成熟。

8.3 CSI 规范的持续演进

CSI 规范本身也在不断演进。VolumeAttributesClass 是 Kubernetes 1.31 引入的新功能,允许在卷的生命周期中动态修改卷属性(如 IOPS 限制、吞吐量),无需重建 PV。这将为存储资源的弹性伸缩提供更多灵活性。

同时,Kubernetes 核心代码正在持续“瘦身”——存储功能已经迁移到 CSI,运行时迁移到 CRI,网络迁移到 CNI,使 Kubernetes 能够从大规模数据中心扩展到边缘设备和 AI 专用硬件。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐