☰
K8s持久化存储实战:从PV/PVC到StorageClass动态供给与排错指南
2026/10/11 15:59:11 网站建设 项目流程

1. 从“Pod一重启数据就没了”说起:为什么K8s需要PV与PVC

先聊一个我碰到过很多次的场景。刚开始把应用往Kubernetes里迁的时候,很多人会想当然地以为,只要把容器跑起来就完事了。直到某天某个数据库实例或者某个上传图片的服务一重启,数据全丢了,才意识到问题的严重性。

Kubernetes的Pod默认是“一次性”的存在,容器文件系统跟随Pod生命周期,Pod被删除、被重新调度到别的节点、或者节点宕机之后重新拉起,之前写在容器可写层里的数据就全部归零。这不是某个节点的问题,也不是集群配置错了,而是K8s的设计哲学决定了的:Pod是无状态的、可随时重建的“空壳”,一切用户数据都应该放到Pod之外。

那直接挂一个云硬盘或者NFS到某个节点的某个目录,再把宿主机的路径映射到容器里行不行?能行,但很丑。你会面临几个问题:Pod被调度到其他节点时,宿主机目录不一定还在;不同节点上同一路径下的数据不互通;你需要为每台节点手工准备存储目录,稍微一扩容就乱套;更别提存储类型一换,比如从本地盘换到云盘,你的YAML里所有hostPath都得跟着改。

Kubernetes给出的标准答案是PV与PVC。这两个对象把“存储资源”和“存储使用”彻底拆开。PV全称PersistentVolume,是集群层面的一块持久化存储,它由管理员预先创建,或者由StorageClass动态供应,本质上是“存储资源池里的一格”。PVC全称PersistentVolumeClaim,是用户提交的存储申请,它声明我需要多大的空间、什么访问模式,K8s负责把符合条件的PV和PVC绑定。Pod再通过PVC去挂载,就像租房客拿着租房合同入住,不需要关心房子是谁建的、水管怎么走的。

这套抽象的价值,用一句大实话总结就是:你在YAML里写的是“给我5Gi存储”,而不是“给我/export/data目录下的5Gi空间”。前者是声明式需求,后者是具体实现。声明式的好处是,底层存储换成云盘、换成NFS、换成本地SSD,上层应用根本感知不到。这是K8s生态里最普及的一层抽象,也是每个做云原生的人绕不开的基础课。

2. PV详解:集群里的“存储资源池”

要真正理解PV/PVC,不能只背YAML字段。先看看一个PV对象完整长什么样,然后把每个关键点掰开揉碎讲清楚。

apiVersion: v1 kind: PersistentVolume metadata: name: pv-storage-001 spec: capacity: storage: 10Gi volumeMode: Filesystem accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: standard nfs: server: 192.168.1.100 path: "/nfs/data/pv001"

这块PV声明了:它是一个10Gi的存储卷,访问模式为单节点读写,回收策略是Retain,对应的StorageClass叫standard,底层存储后端是某台NFS服务器的某个路径。

2.1 PV的四种生命周期状态

PV创建之后,并不一定立刻就能被使用。K8s会给每个PV维护一个状态机,四个状态分别是:

  • Available:PV就绪,等待PVC来绑定。就像一套空置的房子,正在挂牌出租。
  • Bound:PV已经被某个PVC绑定了,这个PVC和PV之间的绑定关系是“一对一”的,不能共享。一旦绑定,这套房子就进入出租状态,别人不能再申请。
  • Released:PVC被删除了,但PV还没有执行后续的回收动作。可以理解为租客退租了,房子空出来但还没打扫,暂时不可租。
  • Failed:PV在自动回收时失败,比如底层存储后端报错,卷就成了这个状态。这种卷基本需要管理员人工介入了。

有个非常容易误解的地方:Released状态不代表PV马上能被下一个PVC使用。Retain策略下的Released卷,即使空间是空的、数据也没了,K8s也不会自动把它重新置回Available。必须由管理员手动处理,比如把PV的claimRef清掉,才能重新进入可用池。这个细节我在第6部分排查章节还会再提。

2.2 访问模式:单机读写还是多机共享

访问模式是PV/PVC匹配时最容易出错的一环。很多人只知道填ReadWriteOnce,却搞不清楚它到底约束了什么。

Kubernetes的访问模式(Access Modes)作用于“节点”层面,而不是“Pod”层面。我单独解释一下这句话的意思:

  • ReadWriteOnce(RWO):卷只能被一个节点以读写方式挂载。注意是“一个节点”,不是“一个Pod”。如果同一个节点上有两个Pod都用了这个卷,是允许的;但如果你有两个副本被调度到不同节点,第二个Pod就会挂载失败。这种模式最典型的场景是云硬盘,比如云厂商的块存储一般只能挂到一个节点上。
  • ReadOnlyMany(ROX):多个节点可以同时以只读方式挂载。适合配置类数据、文档库这种所有人只读不改的场景。
  • ReadWriteMany(RWX):多个节点可以同时读写。NFS、CephFS这类分布式文件系统支持这种模式,也是多副本应用共享数据的首选。
  • ReadWriteOncePod(RWOP):这是后来新增的精细模式,约束的是“一个Pod”,比RWO更严格。即使两个Pod恰好被调度到同一个节点,也不能同时挂载同一个卷。一般用于需要严格单实例访问的存储,比如某些数据库卷。

我在实际配置中的建议是:能选RWO就尽量选RWO,因为云厂商的块存储、本地盘的性能都优于网络文件共享。只有在明确需要多副本共享读写的场景,比如多个Web前端要共享上传目录、多个Worker要写同一个结果目录,才考虑RWX。很多人在没有共享需求时硬上NFS,把网络的瓶颈和单点故障引进来,反而得不偿失。

2.3 回收策略:数据到底要不要留

PV创建时必须指定persistentVolumeReclaimPolicy,它决定PVC删除后,卷里的数据怎么处理。三个可选值:

  • Retain:保留数据。PV进入Released状态,底层存储中的数据原封不动,需要管理员手工处理。这是最安全、也是生产环境最推荐的策略,因为数据库、文件服务这类数据太宝贵,自动删除不可控。
  • Delete:删除数据。PVC删除后,K8s会调用底层存储的删除接口把卷连带数据一起删掉。这种策略一般配合动态供给使用,云硬盘、NFS子目录都能自动清理。优点是不用手工运维,缺点是如果误删PVC,数据就彻底没了。
  • Recycle:这个策略早已被废弃,它只是简单地执行rm -rf清空目录再重新置为Available,安全性和隔离性都不行,云存储基本上都不支持。新版本的K8s里基本见不到了。

有一个细节值得注意:回收策略是在PV上配置的,不是你每次创建PVC时临时指定的。所以管理员在创建PV的时候,就要想清楚同样的卷在PVC消失之后是留还是删。留的话,需要容灾备份和人工清理流程;删的话,需要确保底层存储能够执行删除动作,否则会出现PV里写着Delete但实际删不掉,卡在Failed状态的尴尬局面。

3. PVC详解:用户侧的“存储申请单”

PV站在管理员视角描述存储资源,PVC则站在用户视角描述存储需求。PVC的YAML通常比PV短很多,因为它不需要关心存储后端的细节。

apiVersion: v1 kind: PersistentVolumeClaim metadata: name:>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询