资讯详情

Kubernetes存储入门:PV、PVC、StorageClass核心原理解析

📅 2026/10/9 2:32:01 | 华诺云谱 👁 阅读
Kubernetes存储入门:PV、PVC、StorageClass核心原理解析
1. 存储入门别再被PV、PVC、StorageClass绕晕了接触Kubernetes时间不短了发现存储这块一直是很多人头疼的地方。PV、PVC、StorageClass这几个概念单独看都能理解一放到实际环境里就懵了。这不怪你存储本身链路长、组件多再加上Kubernetes抽象了一层又一层很容易让人绕进去。这篇内容就是把这条链路掰开揉碎讲清楚从底层原理到实际配置再到碰到问题怎么查怎么解一次说完。先说个最朴素的理解方式。把Kubernetes集群想象成一个大仓库PV就是仓库里已经堆好的货架PVC就是你向仓库管理员提交的领货申请单而StorageClass就是那个能根据申请单自动组装新货架的机器。没有StorageClass的时候货架没了得人工去搭有了它申请单一提交机器自动就把新货架造出来了。这么一比喻三个核心对象的关系就清楚了。这套东西解决的核心问题是什么呢最根本的一条Kubernetes要把存储资源和业务应用解耦。你在YAML里写Pod的时候不应该关心底层到底用的是本地磁盘还是网络存储也不应该关心存储空间是20G还是50G这些应该由集群管理员统一规划由存储系统动态分配。这不是Kubernetes矫情而是分布式环境下应用调度到任意节点数据的持久性和可迁移性必须靠一套标准机制来保障。这篇文章适合谁看刚接触Kubernetes、被存储概念搞得一头雾水的学习者正在排查存储相关故障的运维朋友还有需要对接存储给业务提供持久化能力的平台开发都会从里面找到有价值的东西。我尽量把平时文档里不写的东西也翻出来聊聊比如回收策略那些容易踩坑的细节还有动态供给和静态供给怎么选这类实际问题。2. 核心概念拆解PV、PVC、StorageClass到底各管什么事2.1 PV承载真实存储资源的抽象层PVPersistentVolume是存储资源的最终体现它把真实的存储系统包装成一个Kubernetes资源对象。这个底层存储可以是本机磁盘、网络文件系统、云厂商的块存储也可以是分布式存储系统。关键点在于PV是集群级别的资源不隶属于任何命名空间它独立于Pod存在Pod挂掉、重建、删除PV的数据都还在。创建一个PV时核心参数有这几个存储容量capacity、访问模式accessModes、回收策略persistentVolumeReclaimPolicy、存储类storageClassName。这里我多说一句访问模式它决定了这个PV能被多少个节点以什么方式同时挂载。ReadWriteOnce表示只能被一个节点以读写方式挂载ReadOnlyMany表示可以被多个节点同时只读挂载ReadWriteMany则是多个节点同时读写挂载。要命的是这三种模式的可用性完全取决于底层存储实现的不是你在YAML里写什么就一定能用什么。capacity字段在很多人看来就是个摆设因为Kubernetes不会真的去检查底层存储有没有那么大。但你申请PVC的时候Kubernetes是靠这个值做匹配的。换句话说你写着100G底层实际只有50G短期内系统不会报错数据写满就出大事了。所以这个值必须跟实际存储配额对齐千万别编。2.2 PVC业务对存储资源的申请单PVCPersistentVolumeClaim是用户对存储的请求它声明了需要多少容量、什么访问模式、用什么存储类。PVC是命名空间级别的资源跟Pod同生命周期但它绑定的PV可以远超Pod的生命周期。PVC和PV的绑定逻辑值得花点时间理解。Kubernetes会去找满足以下条件的PV容量够用、访问模式匹配、storageClassName一致。如果条件不满足PVC会一直处于Pending状态对应的Pod也就一直起不来。这里有个容易忽略的点如果不设置storageClassName匹配行为取决于集群里是否配置了默认StorageClass。有默认的就走默认的动态供给没有默认的就只能找未绑定且storageClassName为空的静态PV。PVC还有一个让我又爱又恨的特性叫做容量不小于请求。你申请5G系统可能给你绑了一个10G的PV这种情况在静态供给场景下经常发生。业务看到的空间是10G但声明里写的是5G将来扩容量的时候逻辑容易乱。所以静态供给场景下管理员创建PV时就得把容量精确控制在刚好够用的水平宁少勿多。2.3 StorageClass动态供给的自动化引擎StorageClass彻底改变了存储供给的模式。没有它之前管理员必须预先创建好一批PV放着用户申请PVC时从池子里挑一个。有了它PVC一创建系统就会按照StorageClass里定义的模板实时调用底层存储接口去创建一块新存储然后自动绑定全程不需要人工介入。StorageClass的关键配置项包括provisioner供给器对接底层存储的插件、parameters传给供给器的参数比如存储类型、副本数、回收策略等、reclaimPolicy回收策略、allowVolumeExpansion是否允许扩容、mountOptions挂载选项。选对provisioner是StorageClass配置里最重要的决定。云环境里有各自的云盘插件自建的通常用支持CSI的存储插件比如NFS、Ceph RBD、GlusterFS这些。我个人的实践体会是凡是生产环境优先找带CSI接口的存储方案生态成熟、功能齐备、社区活跃出了问题也好排查。至于那些还在用FlexVolume之类老接口的插件能换就尽早换。3. 实战入门从静态供给到动态供给的完整演进3.1 静态供给手动创建PV并绑定PVC静态供给是理解PV、PVC机制最直观的路径适合测试环境和小规模场景。下面用NFS举个例子手把手走一遍。先准备一个NFS服务端导出目录/data/nfs假设服务器IP是192.168.1.100然后在Kubernetes里创建PVapiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv-001 spec: capacity: storage: 20Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: manual nfs: path: /data/nfs server: 192.168.1.100这个PV定义里有几个地方要特别注意。storageClassName写的是manual随便取的名字作用是跟动态供给的StorageClass做区分让静态PV不会被默认StorageClass的PVC误绑。reclaimPolicy用的Retain意思是你删掉PVC后这个PV不会被自动清理数据留着等人工处理这在测试环境里能避免误删数据。接着创建PVCapiVersion: v1 kind: PersistentVolumeClaim metadata: name: nginx-data-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: manualPVC声明的需求是10Gi、ReadWriteOnce、manual类。Kubernetes会去找满足这些条件的PV上面的nfs-pv-001容量20Gi够用访问模式匹配storageClassName一致于是绑定成功。这里能看到容量匹配是大于等于的逻辑你申请10Gi绑定到20Gi的PV是合法的。然后把这个PVC用进PodapiVersion: v1 kind: Pod metadata: name: nginx-storage-test spec: containers: - name: nginx image: nginx:1.25 volumeMounts: - mountPath: /usr/share/nginx/html name: web-data volumes: - name: web-data persistentVolumeClaim: claimName: nginx-data-pvcPod起来后可以先检查一下绑定状态和实际挂载情况。下面这套命令我几乎每次存储实操都会用到kubectl get pv kubectl get pvc kubectl describe pvc nginx-data-pvc kubectl get pod nginx-storage-test -o wide kubectl exec -it nginx-storage-test -- df -h | grep nginx正常情况下describe输出里Phase应该是BoundEvents里能看到成功绑定和挂载的记录。df那一步能看到容器里挂载的容量如果显示的容量是20G而不是10G别慌这就是前面说的容量不小于请求的匹配逻辑在起作用。静态供给最大的问题是运维成本高。每块存储都要人工登记、手工建PV容量规划全靠感觉配多了浪费配少了业务扩个容都费劲。所以静态供给适合做概念验证和测试环境生产环境一般都会切换到动态供给。3.2 动态供给一条StorageClass让存储自动化动态供给是生产环境的标配。核心就两步创建一个StorageClass然后创建PVC存储资源的生命周期管理就自动化了。这里用NFS CSI的provisioner做示例。环境里需要先部署好NFS CSI驱动然后创建StorageClassapiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-csi provisioner: nfs.csi.k8s.io parameters: server: 192.168.1.100 share: /data/nfs mountOptions: nfsvers4.0 reclaimPolicy: Delete allowVolumeExpansion: true volumeBindingMode: Immediate创建好StorageClass后PVC就用它来申请存储apiVersion: v1 kind: PersistentVolumeClaim metadata: name: app-data-pvc spec: accessModes: - ReadWriteOnce storageClassName: nfs-csi resources: requests: storage: 50Gi这一步执行完系统会自动完成存储创建和PV绑定。注意看PVC的Events正常情况下能看到Provisioning成功的记录。想要更快验证效果可以连续创建几个不同大小的PVC然后kubectl get pv会看到每个PVC都有对应的、自动生成的PV容量跟你申请的一模一样。这个容量精确匹配就跟静态供给的可能超额匹配形成了鲜明反差。动态供给还有个强悍的能力容量扩容。如果StorageClass里设置了allowVolumeExpansion: true就可以在线扩容PVC。CSIDriver支持扩容的前提下只需修改PVC的请求容量然后applykubectl patch pvc app-data-pvc -p {spec:{resources:{requests:{storage:80Gi}}}}扩容操作能不能成功取决于底层存储驱动对扩容的支持程度。有的文件系统支持在线扩展有的需要把文件系统先扩到位。NFS CSI在这块一般问题不大。不过我建议扩容完成后还是手动到容器里执行df -h确认一下实际可用容量防止出现PVC状态变了但文件系统没扩的情况。扩容不可逆这件事扩错了方向就真的没办法缩回去了操作前务必确认好目标容量。3.3 默认StorageClass让PVC零配置生效生产环境建议给集群配置一个默认StorageClass。这样用户在PVC里不用写storageClassName系统就会自动走默认的存储类创建存储。设置默认类的方式是给StorageClass加上一个注解apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-csi annotations: storageclass.kubernetes.io/is-default-class: true或者用kubectl命令修改已有对象kubectl patch storageclass nfs-csi -p {metadata:{annotations:{storageclass.kubernetes.io/is-default-class:true}}}设置了默认类之后新创建的PVC如果没写storageClassName就会自动绑定到默认类。这点在生产环境非常重要因为它能防止用户因为忘记写存储类名而导致PVC一直Pending。但同时也要注意一个集群里设置了多个默认类的话Kubernetes会拒绝为不带storageClassName的PVC动态供给所有这类PVC都会Pending。所以默认类务必只保留一个。4. 调参与选型PV回收策略、访问模式、存储类参数的踩坑记录4.1 回收策略三大选择Retain、Delete还是Recycle回收策略定义了PVC被删除后PV和底层存储数据的去向这个决策对数据安全影响极大。Retain策略下PV删除后底层数据完整保留PV进入Released状态。这个状态下的PV不会自动复活管理员需要手动清理数据后重新使用或直接删除。对于重要数据、需要审计留存的场景Retain是最安全的选择。代价是运维成本高释放的PV不能自动接新活。Delete策略下PVC删除会连带删除底层存储卷数据一起消失。这个策略适合临时数据、测试数据或者数据有备份体系兜底的环境。动态供给的StorageClass默认就是Delete这个默认值暗藏风险用户误删PVC整个存储卷连带数据会瞬间被清掉很多存储有多种副本机制但实际上没有备份的话也会是灾难。生产环境如果数据重要强烈建议把Delete改成Retain。Recycle策略是个历史遗留品它会在PV释放后执行清理然后重新进入Available状态。听起来很美但Kubernetes官方已经在逐步淘汰这个机制现代CSI驱动基本不实现了。不要依赖Recycle。4.2 访问模式的常见误导和存储真实能力访问模式这个配置值得提高警惕。很多人在YAML里写了ReadWriteMany就走完全没考虑底层存储是否支持。不同存储系统对多节点挂载的支持差异很大块存储如云盘一般只支持单节点读写文件存储如NFS天生能多节点读写分布式块存储如Ceph RBD经过配置支持多节点多Pod访问但有限制条件。我见过最典型的故障是新上了StatefulSet多个副本Pod要共享数据运维人员把accessMode配置成了ReadWriteMany没确认底层存储实际能力。结果是Pod创建了一半挂载时直接失败Kubernetes调度和挂载插件全军覆没整个应用的可用性被拖垮。判断一个存储能不能支持某种访问模式最靠谱的依据是看CSI驱动文档和对应的StorageClass描述不要光看PV YAML里写了什么。YAML是声明底层不支持就是不支持kubelet挂载时会把问题原原本本暴露出来。4.3 StorageClass参数选择的实际经验StorageClass里的parameters直接决定底层卷的物理形态和服务质量这块配置差异巨大。以Ceph RBD为例常见的参数有pool、imageFeatures、csi.storage.k8s.io/fstype等其中fstype决定新建卷的文件系统类型默认是ext4要改成xfs也能配。云厂商的卷类型参数更多比如类型是高效SSD还是吞吐型HDD这些直接关系账单。实际配置时我给几个建议一是关注参数是否匹配环境Ceph的pool参数如果指向不存在的pool供给会直接失败二是不要随意改fstype除非有明确理由比如要做快照恢复或者对文件系统特性有特定需求三是mountOptions的配置要谨慎配错了会导致挂载失败比如NFS的nfsvers参数不匹配服务端版本整个PVC就Pending了。5. 生产环境下的存储方案StatefulSet场景和灾备注意事项5.1 StatefulSet固定存储与Pod底层挂载逻辑StatefulSet和有状态应用是PV、PVC最典型的落地场景。它的独特之处在于每个副本Pod都能通过volumeClaimTemplates自动创建独立的PVC并且Pod重建后依然绑定到同一个PVC上数据天然不丢。volumeClaimTemplates的写法如下apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql-cluster spec: serviceName: mysql-cluster-svc replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 volumeMounts: - name: data mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: - ReadWriteOnce storageClassName: nfs-csi resources: requests: storage: 20Gi这套机制下的匹配关系很清晰mysql-cluster-0绑data-mysql-cluster-0mysql-cluster-1绑data-mysql-cluster-1以此类推。扩容副本时新Pod会自动带新PVC缩容时删除Pod不会删除PVC这个行为是刻意的因为StatefulSet本身不负责清理存储卷。StatefulSet存储清理往往是个容易忽略的坑。许多人以为直接删掉StatefulSet就能把数据清干净结果Pod没了PVC还在数据还在物理存储上躺着。对于测试环境要彻底清理需要手动删除PVC并确认回收策略的行为认真看StorageClass的Delete配置是否能联动清理卷。5.2 数据备份与容灾别让存储卷变成数据孤岛Kubernetes里的存储卷本质上是一块远程挂载的磁盘空间它本身不等于数据安全。有三件事必须做备份、拷贝、巡检。备份是第一位的事。不管底层是NFS还是分布式存储建议定期把关键数据卷的内容备份到独立的位置。一个常见的思路是用CronJob定期创建PV快照或者直接把数据打包传送到备份存储速度慢一点没关系关键是别把生产卷和备份放同一个存储池否则存储设备单点故障就全完了。拷贝需求来自跨环境迁移比如测试环境要复制一份数据到预生产环境。最简单的方式是把PVC挂到临时Pod上用tar打包后在新环境解包。注意挂载到临时Pod时要选用不同的PVC不要一边写业务一边拷数据数据一致性没法保证。巡检是最容易被忽视的一环。每季度检查一下关键PVC的剩余容量、PV的健康状态、存储节点的使用率把趋势记录下来。有几回我遇到过存储容量被打满导致业务写入hang住的情况就是因为只关注了CPU内存这些常规指标存储这一个维度完全被忽略了。5.3 高可用与多副本设计的前提条件Kubernetes调度本身提供了Pod多副本能力但存储层的多副本能力和高可用取决于存储后端不是Kubernetes能做主的。如果底层是单节点NFS那么所有Kubernetes的存储高可用策略都是无根之木。这种环境下一旦NFS节点宕机全部依赖该存储的业务都会挂掉。生产环境选存储至少要考虑这些点存储后端是否有分布式多副本能力是否支持快照和克隆CSI驱动是否支持在线扩容故障域是否跨可用区。别贪图省事直接用单点存储扛生产将来承担的风险远大于省下的那点运维成本。6. 故障排查手册从PVC的Pending到Pod的挂载失败6.1 PVC卡在Pending状态PVC一直Pending是第一常见的存储故障。排查顺序如下第一步检查StorageClass是否存在且名字拼写正确。这个错误太低频又太致命多数人排查时完全不想看这个结果往往是storageClassName写错了一个字母之类的小问题。看describe PVC的Events就知道提示找不到StorageClass基本就是拼写或者命名空间环境问题。第二步检查事件输出确认是找不到PV还是供给失败。静态供给场景下Pending通常是找不到匹配PV动态供给场景下Pending通常是供给器报错。事件里会指名道姓地给出原因比如授权失败、连接存储失败、参数错误这些。第三步尝试手工执行一下provisioner的操作比如用NFS客户端直接挂载一下存储路径确认网络连通、权限正确、路径存在。很多时候Kubernetes层的问题根源在存储底层绕开Kubernetes直接验证存储往往能大幅缩短排查时间。6.2 Pod挂载PVC时一直ContainerCreating这个情况的典型特征是Pod状态卡在ContainerCreating事件里出现FailedMount。常见原因集中在三点节点上没有安装必要的CSI驱动组件挂载被安全策略阻止底层存储节点网络不通。排查第一步看节点到存储服务器的连通性加权限校验。如果NFS路径权限是root_squash且Pod以非root运行mount就会报Permission denied。第二步看kubelet日志或者节点上的存储挂载日志确认驱动是否正常加载。第三步检查CSI驱动版本是否兼容Kubernetes版本版本不匹配是最容易漏掉的问题很多老集群升级Kubernetes主版本后CSI驱动没跟着升级挂载组件静默失效。6.3 PVC删不掉一直TerminatingPVC删除卡住也是个高频故障。常见原因是PVC被某个Pod或StatefulSet仍引用着或者PV进入Released状态后没有清理Finalizer卡住。排查方式简单直接kubectl describe pvc 看Finalizers和相关事件确认引用的资源清掉必要时手动删除Finalizer但务必先确认引用关系已彻底解除。6.4 容器内存储空间不足的误区最后提一个认知层面的问题。容器内df -h看到的挂载容量和宿主机看到的存储总量是两个完全不同的视角。容器看到的是存储卷的配额宿主机看到的是整个存储池的剩余空间。如果磁盘写满导致业务异常优先确认挂载卷容量是否够用其次再看存储池整体水位。很多人把注意力放在宿主机上结果卷配额早就满了还得绕一大圈才回过神来。7. 从入门到精通的五条实用心得把这套存储体系的实践做了个总结几条经验放这里省得大家重复踩坑。第一先画清楚存储拓扑再动手。PV层的存储后端是什么供给器选谁访问模式和回收策略怎么配拓扑没搞清楚就上生产后面大概率要推倒重来。第二静态供给适合测试动态供给才是生产主流。能用CSI就用CSI能用StorageClass就让系统去创建卷人工介入越少出错的缝隙越少。第三回收策略务必根据数据特性做选择。数据无价的地方坚决用RetainDelete只留给那些可以随时丢掉的数据。宁可多留备份也别心疼那点存储空间。第四节点维护和存储变更前先确认挂载状态。存储节点重启、网络配置变更这类操作要先确认正在运行的业务Pod会不会受影响必要时先驱逐Pod再操作。第五把存储指标纳入日常巡检范围。容量使用率、卷健康状态、CSI驱动版本、节点存储错误这些都要有监控和告警。没有存储维度的可观测性存储故障发现的时候往往已经晚了。我自己在这个领域的教训就是早期的版本只看应用层不看存储层觉得底层是平台的事。等到生产环境的数据库因为存储空间耗尽无法启动时才追悔莫及。从那以后任何Kubernetes集群上线前存储规划都是第一优先级储备容量、监控告警、备份恢复一个都不能少。这套东西越是在生产里摔打得多越能体会透彻。希望这篇内容能帮你少走点弯路把存储这块硬骨头啃下来。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑