news 2026/6/4 1:56:58

第 35 篇 k8s之PVC 与 StorageClass:动态存储供应

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
第 35 篇 k8s之PVC 与 StorageClass:动态存储供应

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。


在第 34 篇中,我们学了 emptyDir 和 hostPath。它们解决的是“Pod 内部容器间共享文件”和“访问宿主机特定路径”的问题。但一个最核心的生产需求还没有解决:Pod 重建后,数据如何保留?

如果 Redis 的 Pod 被重新调度到另一台节点上,emptyDir 和 hostPath 都无法将数据带过去。emptyDir 随 Pod 删除而销毁,hostPath 只存在于特定节点上。我们需要一种与 Pod 生命周期解耦、可在集群任意节点访问的持久化存储

这正是 PV(PersistentVolume,持久卷)和 PVC(PersistentVolumeClaim,持久卷声明)的设计目标。在 Docker 生态中,我们通过docker volume create来创建命名卷,容器重启、删除都不会丢失数据。但在 K8s 集群中,管理员不可能为每个应用手动在每台节点上创建 Volume——我们需要一种自动化的动态供给机制。今天这篇,我们就从 PV/PVC 的核心概念讲起,通过贯穿案例的 Redis 持久化存储,深入理解 StorageClass 如何实现“声明即存储”。

一、PV 和 PVC 的抽象模型

1.1 为什么需要 PV 和 PVC?

在第 7 篇 Docker 数据管理中,我们创建 Volume 的命令是docker volume create redis-data,然后在docker run时用-v redis-data:/data挂载。这种方式在单机上工作良好,但在 K8s 集群中有两个致命缺陷:

  • 不跨节点:Pod 重新调度到另一台节点时,新节点上没有这个 Volume。

  • 人工运维:管理员需要提前创建好 Volume,开发者需要知道 Volume 的具体名称和配置。

K8s 的解决方案是将存储抽象为两个独立的对象,实现管理员与开发者的职责分离

  • PV(PersistentVolume):集群管理员准备的存储资源,可以来自 NFS、云存储(AWS EBS、GCE PD)、本地磁盘等。PV 与 Pod 生命周期无关——Pod 被删了,PV 还在。

  • PVC(PersistentVolumeClaim):开发者声明对存储的需求:“我需要 1Gi 空间,读写一次即可”。K8s 自动找匹配的 PV 绑定给这个 PVC。

1.2 用“租房子”来理解 PV 和 PVC

把 K8s 集群想象成一个租房市场:

  • PV是房东已装修好的房源(一套具体的房子,位于某小区某单元),由管理员(中介)提前准备好。

  • PVC是租客的求租需求——“我需要 50 平米、朝南的一居室”。租客不需要知道具体哪套房子,只需要描述需求。

  • K8s 的匹配引擎是中介,自动将合适的房源(PV)匹配给租客需求(PVC)。匹配后,这套房子就归这个租客独占使用。

  • 如果租客搬走了(Pod 删除),PVC 还在,房子仍然保留(PV 保留)。新租客(重建的 Pod)可以通过同一个 PVC 继续使用同一套房子和里面的家具(数据)。

1.3 PV 的三种供给方式

在实际工作中,静态供给只适合极少数固定存储资源已知的场景(比如一个已经部署好的 NFS 服务器)。生产环境的标配是动态供给——你只需要声明“我要 1Gi 的云盘”,StorageClass 自动调用云 API 创建。

二、静态供给:理解 PV 和 PVC 的匹配机制

在进入动态供给之前,先通过一个静态供给的简单示例理解 PV 和 PVC 的绑定关系。

2.1 创建一个 PV

apiVersion: v1 kind: PersistentVolume metadata: name: task-pv-volume spec: capacity: storage: 1Gi accessModes: - ReadWriteOnce hostPath: path: /mnt/data

关键字段:

  • capacity.storage: 1Gi:PV 的容量

  • accessModes: ReadWriteOnce:访问模式,单个节点读写

  • hostPath:在 Minikube 环境中使用 hostPath 模拟真实存储,生产环境会替换为云存储(如awsElasticBlockStore

2.2 创建一个 PVC

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: task-pvc-claim spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi

PVC 不指定具体 PV 名称,只声明需求:“我要 1Gi、单节点读写”。K8s 自动找到匹配的 PV 并绑定。

kubectl apply-ftask-pv.yaml kubectl apply-ftask-pvc.yaml kubectl get pvc

输出:

NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE task-pvc-claim Bound task-pv-volume 1Gi RWO 30s

STATUS=Bound表示 PVC 已成功绑定到task-pv-volume这个 PV。STORAGECLASS列为空,表示这是静态供给,没有用到 StorageClass。

2.3 在 Pod 中使用 PVC

volumes: - name: task-storage persistentVolumeClaim: claimName: task-pvc-claim

Pod 引用 PVC,PVC 绑定 PV,PV 对应物理存储。这是三层引用链——开发者只需关心 PVC,不必知道底层存储的具体位置和类型。如果你删除了这个 Pod,重新创建时引用同一个 PVC,依然能访问到原来的数据。

2.4 访问模式

大多数数据库(MySQL、Redis)需要 RWO 模式。共享文件存储(如 NFS)可以支持 RWX 模式。如果 Pod 被调度到不同节点上,RWO 模式的 PV 将无法在新节点上挂载——这就是为什么数据库这类有状态应用需要用 StatefulSet(第 27 篇)并配合节点亲和性来管理。

三、StorageClass 与动态供给

静态供给的问题很明显:管理员需要预先创建每个 PV,开发者扩容时要找管理员创建新的 PV。当集群中有数百个应用、每个应用都需要存储时,这根本不可行。

StorageClass解决了这个问题。它定义了一个“存储模板”:当 PVC 被创建时,StorageClass 自动调用后端存储的 API 创建 PV,并绑定给 PVC。

3.1 StorageClass 的工作原理

PVC 创建 → StorageClass → Provisioner 调用 API → 自动创建 PV → 绑定 PVC → Pod 挂载

管理员只需要创建 StorageClass 对象(一次性配置),之后开发者创建 PVC 时,PV 会自动生成。这正是“声明式存储”的核心思想——你不再需要关心 PV 是谁创建的、在哪创建的,只需要在 PVC 中声明“我要什么”。

3.2 Minikube 中的 StorageClass

Minikube 默认自带一个 StorageClass:

输出:

NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE standard(default)k8s.io/minikube-hostpath Delete Immediate
  • (default):集群的默认 StorageClass,PVC 不指定storageClassName时自动使用

  • PROVISIONER:负责实际创建存储的组件,minikube-hostpath在宿主机上创建目录模拟真实存储

  • RECLAIMPOLICY: Delete:PVC 被删除时,PV 也被自动删除

  • VOLUMEBINDINGMODE: Immediate:PVC 创建后立即绑定 PV,不需要等待 Pod 调度

3.3 删除策略

Retain策略适用于需要保留数据做审计或恢复的场景。但 Retain 后 PV 变为Released状态,不能被新的 PVC 自动绑定——需要管理员手动清除 PV 中的旧数据并重新标记为Available

3.4 卷绑定模式

WaitForFirstConsumer在云环境中非常重要:如果 PVC 立即创建了可用区 A 的云盘,但 Pod 被调度到可用区 B,Pod 将无法挂载这个云盘。延迟绑定确保了存储资源始终与 Pod 在同一可用区,避免了跨可用区的存储挂载问题。

四、实战:为 Redis 配置动态持久化存储

现在把理论应用到贯穿案例中。为 Redis 创建一个使用动态供给的 PVC,确保 Redis 数据在 Pod 重建后不丢失。

4.1 创建 PVC

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: redis-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi storageClassName: standard

PVC 不指定任何具体的 PV 名称或节点路径,只声明了“我要 1Gi、RWO 模式、使用 standard StorageClass”。剩下的全部自动化——StorageClass 调用 Provisioner 创建 PV,K8s 将 PV 绑定到 PVC。

kubectl apply-fredis-pvc.yaml kubectl get pvc# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE# redis-pvc Bound pvc-a1b2c3d4-e5f6-7890-abcd-ef1234567890 1Gi RWO standard 10s

4.2 部署 Redis 使用 PVC

apiVersion: apps/v1 kind: Deployment metadata: name: redis spec: replicas:1selector: matchLabels: app: redis template: metadata: labels: app: redis spec: containers: - name: redis image: redis:alpine ports: - containerPort:6379volumeMounts: - name: redis-data mountPath: /data volumes: - name: redis-data persistentVolumeClaim: claimName: redis-pvc

重要:如果使用 RWO 模式(单节点读写),请务必将replicas设为 1。Redis Deployment 的多个副本会创建多个 Pod,而 RWO 卷只能挂载到单个节点上——如果两个 Pod 被调度到不同节点,第二个 Pod 将无法挂载同一个 PVC,导致启动失败。多副本有状态应用应使用 StatefulSet,每个 Pod 绑定独立的 PVC。

4.3 验证持久性

# 写入数据kubectlexecdeploy/redis -- redis-clisetcounter100# 删除 Pod(不删除 PVC)kubectl delete pod-lapp=redis# 等待新 Pod 启动kubectl get pods-lapp=redis-w# 验证数据仍然存在kubectlexecdeploy/redis -- redis-cli get counter# "100"

这就是 PVC 持久化的直观体现:Pod 被删了,PV 还在,PVC 还在,数据完好无损。新 Pod 通过同一个 PVC 挂载到同一个 PV,Redis 启动时从 AOF 文件中恢复了之前的键值对。

# 查看自动创建的 PVkubectl getpv# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS# pvc-a1b2c3d4-e5f6-7890-abcd-ef1234567890 1Gi RWO Delete Bound

五、对比 Docker Compose 的存储方式

Docker Compose 的命名卷适合单机场景,但在跨主机、动态供给、访问控制方面有明显的局限性。这正是 K8s PV/PVC 体系的设计价值所在。

六、PVC 扩容

PVC 支持动态扩容(需要 StorageClass 启用allowVolumeExpansion: true):

kubectl patch pvc redis-pvc-p'{"spec":{"resources":{"requests":{"storage":"2Gi"}}}}'# persistentvolumeclaim/redis-pvc patchedkubectl get pvc redis-pvc-w# 等待 CAPACITY 从 1Gi 变为 2Gi

注意:并非所有存储后端都支持扩容,且只能扩容不能缩容。云存储通常支持在线扩容,不会影响正在运行的 Pod。

七、命令速查表

八、本篇总结

  • PV 和 PVC 的关系:PV 是实际的存储资源,PVC 是应用对存储的需求声明。PVC 绑定 PV 后,Pod 通过 PVC 挂载持久化存储。这种抽象实现了管理员与开发者的职责分离。

  • StorageClass 动态供给:当 PVC 指定 StorageClass 时,系统自动调用 Provisioner 创建 PV,无需管理员预先准备存储。这是生产环境的标配。

  • 访问模式与 Pod 副本的关系:RWO 卷只能挂载到单个节点,多副本有状态应用应使用 StatefulSet(后续第 27 篇相关主题的扩展内容),每个 Pod 绑定独立的 PVC。

  • 与 Compose 的演进关系:Compose 的命名卷是单机手动模式,PVC 是集群自动化模式。思路一致(卷的生命周期独立于容器),但 K8s 在规模和自动化程度上提升了几个数量级。

通过本篇,Redis 的数据真正实现了跨 Pod 生命周期的持久化。下一篇——第 36 篇:资源管理:Requests、Limits 与 QoS,我们将学习如何限制 Pod 的 CPU 和内存使用,防止单个 Pod 过度消耗资源影响同节点的其他 Pod,让集群的资源使用更加公平和可预测。

想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/4 1:52:02

如何将网页内容永久保存为电子书:WebToEpub完全指南

如何将网页内容永久保存为电子书:WebToEpub完全指南 【免费下载链接】WebToEpub A simple Chrome (and Firefox) Extension that converts Web Novels (and other web pages) into an EPUB. 项目地址: https://gitcode.com/gh_mirrors/we/WebToEpub 还在为无…

作者头像 李华
网站建设 2026/6/4 1:52:00

推荐系统升级迫在眉睫!当传统CF遇上RAG+Graph Neural AI,这6类业务场景已实现23.7% GMV提升(实测数据脱敏公开)

更多请点击: https://codechina.net 第一章:AI工具与智能推荐整合 现代推荐系统已不再依赖单一协同过滤或内容匹配策略,而是深度集成多模态AI工具,实现从数据理解、特征生成到实时决策的端到端智能化。大语言模型(LLM…

作者头像 李华
网站建设 2026/6/4 1:51:10

小程序毕业设计-基于微信小程序的旅游景点服务小程序基于springboot+微信小程序的旅游景点导览APP的设计与实现小程序(源码+LW+部署文档+全bao+远程调试+代码讲解等)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围:&am…

作者头像 李华
网站建设 2026/6/4 1:50:02

STL到STEP转换终极指南:如何将3D打印模型无缝导入专业CAD软件

STL到STEP转换终极指南:如何将3D打印模型无缝导入专业CAD软件 【免费下载链接】stltostp Convert stl files to STEP brep files 项目地址: https://gitcode.com/gh_mirrors/st/stltostp 你是否曾遇到过这样的困境:精心设计的3D打印模型完成后&am…

作者头像 李华