当前位置: 首页 > news >正文

第 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 思维 !

http://www.jsqmd.com/news/945881/

相关文章:

  • 售后完善的幼儿园公司排名 - mypinpai
  • Transformer中MLP的事实存储机制与优化实践
  • AI社交整合不是选工具,而是建神经网络:MIT实验室验证的3层认知协同架构(附可运行Docker镜像)
  • 点云去噪优化:统计滤波+体素滤波+半径滤波优化去噪
  • 别再手动焊矩阵键盘了!用STM32F103C8T6驱动74HC165扩展16个按键(附完整CubeMX配置)
  • EduCoder实训答案查询网站是怎么建起来的?从想法到上线的技术栈分享
  • 别再让空压机‘抽风’了!手把手教你设置SMC继电器的迟滞模式(附压力值计算)
  • FPGA调试避坑:ILA核的OOC综合模式,为什么你的时钟约束总对不上?
  • GNN与XGBoost融合的野火风险评估框架解析
  • DeepONet非线性算子学习实战指南:从理论到应用的完整解决方案
  • 深度解析:技术型中小企业如何实现差异化增长
  • 技术笔记:20260603
  • 告别重复编码:用快马平台aigc自动生成vue组件,提升开发效率
  • 面试潜规则⑥:面试官桌下那张“评估表”,到底在打什么分?
  • 2026年地图制作靠谱品牌推荐,哪家更权威? - mypinpai
  • 河北工程测量多少钱?三友测绘价格实惠 - mypinpai
  • STL缩略图终极解决方案:Windows资源管理器中的3D模型即时预览
  • 《从0到1带你Obsidian接入DeepSeek》
  • 从CrystalMaker到WPS PPT:我是如何把复杂的晶体学数据变成一张清晰科普图的
  • YOLOv3推理时,置信度、类别概率和NMS到底怎么‘打架’?一个Debug案例讲清楚
  • 告别构建卡顿:为Jenkins配置国内镜像源与Maven私服的全流程指南(基于PHPStudy环境)
  • 第 36 篇 k8s之资源管理:Requests、Limits 与 QoS
  • 迅为RK3568开发板扫码远程控制探索神奇820集原创视频教程
  • LangChain 实战指南:从调用模型到构建 AI 应用
  • 2026年宠物粮压块机性价比排名,多少钱合理? - mypinpai
  • 小程序毕业设计-基于微信小程序的个性化音乐系统基于springboot+微信小程序的在线音乐个性化推荐APP的设计与实现(源码+LW+部署文档+全bao+远程调试+代码讲解等)
  • 终极宝可梦存档管理指南:7个PKSM核心功能让你轻松掌控所有世代游戏
  • FANUC CNC数据采集实战:从API连接到关键参数获取的完整避坑指南(C++版)
  • HyperMesh网格划分许可不够用?一变多技术让1个License同时支撑多个前处理任务
  • STM32G030C8T6实战驱动包:OLED界面+温湿度/DHT11/超声波/舵机/步进电机/ESP8266全接入