一文读懂k8s的pv与pvc原理
核心思想:解耦与抽象
Kubernetes 的设计哲学是解耦。就像 Pod 抽象了计算资源(CPU、内存),让应用无需关心它具体运行在哪个物理节点上一样,PV 和 PVC 的目的是抽象存储资源,让应用(Pod)无需关心存储的后端细节(如 NFS、云盘、本地盘等)。
1. 核心概念定义
PV (PersistentVolume) - 持久卷
是什么:集群中的一块网络存储,由集群管理员预先创建和配置好的资源。它是集群级别的资源,就像节点(Node)一样,不属于任何命名空间。
好比什么:就像是物理磁盘或者云硬盘本身。它有大小、访问模式(如 ReadWriteOnce、ReadOnlyMany 等)和具体的后端存储类型(如 NFS 路径、云存储盘 ID)。
状态:PV 有自己的生命周期,包括
Available
(可用)、Bound
(已绑定)、Released
(已释放)、Failed
(失败)等。
PVC (PersistentVolumeClaim) - 持久卷声明
是什么:用户(应用开发者)对存储的一个“请求”。它声明了需要多大的存储空间、需要的访问模式是什么。
好比什么:就像是Pod 向集群提交的“申请单”,上面写着:“我需要一个 10Gi 大小、可以读写的高速磁盘”。它不关心这个磁盘具体是什么、在哪里,只关心它的规格。
状态:PVC 是命名空间级别的资源。它通常处于
Pending
(等待绑定)、Bound
(已绑定到PV)状态。
StorageClass (SC) - 存储类
是什么:PV 的创建模板和动态供给器。它定义了如何按需动态创建 PV,以及创建 PV 的属性(类型、参数等)。
好比什么:就像是磁盘的“产品目录”。用户不需要管理员预先创建好特定的硬盘,只需要在申请单(PVC)上注明“我要目录里的那种SSD云盘”,系统就会自动根据目录里的说明(StorageClass)去创建一块对应的硬盘(PV)。
作用:实现了存储供给的动态性(Dynamic Provisioning),这是现代云环境下的最佳实践。
2. 工作原理与流程
PV 和 PVC 的交互遵循着“绑定(Binding)”机制。整个过程可以分为两种模式:
模式一:静态供给 (Static Provisioning)
集群管理员预先创建一批 PV 在集群中,供用户使用。
管理员创建 PV:管理员分析集群的存储需求,提前在 Kubernetes 中创建多个 PV 对象,这些 PV 对象包含了实际存储后端的详细信息(如
nfs.path
,nfs.server
)。用户创建 PVC:用户在部署应用时,创建一个 PVC,指定所需的存储大小和访问模式(如
storage: 10Gi
,accessModes: ReadWriteOnce
)。Kubernetes 进行绑定:
Kubernetes 的 PersistentVolume Controller 会持续监控所有的 PVC 和 PV。
它找到一个处于
Available
状态且满足 PVC 大小和访问模式要求的 PV。找到后,它将这个 PV 和 PVC 绑定在一起。此时 PV 状态变为
Bound
,PVC 状态也变为Bound
。
Pod 使用 PVC:用户在 Pod 的
volumes
字段中引用这个已经绑定成功的 PVC 名称。Pod 被调度到某个节点后,kubelet 会根据 PVC 找到对应的 PV,然后根据 PV 的描述(如 NFS)去挂载真正的存储到节点上,最后映射到 Pod 的容器中。
静态供给的缺点:需要管理员预先规划和管理 PV,不够灵活,容易造成资源浪费(PV 太大)或不足(PV 太小)。
模式二:动态供给 (Dynamic Provisioning) - 现代主流方式
集群管理员无需预先创建 PV,而是预先创建好 StorageClass。用户提交 PVC 时,系统自动按需创建合适的 PV。
管理员创建 StorageClass:管理员创建一个或多个 StorageClass,其中定义了供给者 (Provisioner)(例如
aws-ebs
,azure-disk
,nfs-client
)和参数(如磁盘类型io1
, 区域zone
等)。用户创建 PVC:用户在创建 PVC 时,必须在
storageClassName
字段中指定一个已存在的 StorageClass 名称。这相当于在申请单上指明了“我要按哪个产品目录来制作我的磁盘”。Kubernetes 动态创建 PV:
PersistentVolume Controller 检测到新的 PVC 要求动态存储。
它找到 PVC 指定的 StorageClass。
Controller 会调用该 StorageClass 中指定的 Provisioner 插件(通常是 CSI 驱动)。
Provisioner 插件接收到请求后,会实际地去调用底层存储系统(如 AWS、GCP、Ceph)的 API,真正创建一块存储空间。
创建成功后,Provisioner 会自动在 Kubernetes 中创建一个对应的 PV 对象,并立即将这个新创建的 PV 与用户的 PVC 进行绑定。
Pod 使用 PVC:此后的步骤与静态供给完全相同。
动态供给的优点:完全自动化,按需分配,无需预先创建和管理 PV,极大地提高了效率和灵活性。
3. 生命周期
一个 PV 的生命周期可能如下:
供给 (Provisioning):静态(管理员创建)或动态(StorageClass 创建)。
绑定 (Binding):PVC 找到并绑定到一个 PV。绑定是一对一的映射关系。
使用 (Using):Pod 正在使用该存储卷。
释放 (Releasing):Pod 使用完毕,删除 PVC。根据 PV 的
persistentVolumeReclaimPolicy
(回收策略)决定后续动作:Retain(保留):默认策略。PV 变为
Released
状态,但底层存储数据依然保留。管理员可以手动清理数据并重新使用该 PV。Delete(删除):自动删除 PV 对象并同时调用相关插件删除底层存储资产(如删除云硬盘)。动态供给的 PV 通常默认此策略。
Recycle(回收)(已废弃):基本不再使用,曾用于执行
rm -rf /volume/*
来清理数据,不安全。
清理/回收 (Reclaiming):对于
Retain
的 PV,管理员可以手动处理,删除旧 PV 对象并重新创建,使其回到Available
状态。
4. 总结与类比
为了让你更好地理解,我们用一个打印店的例子来类比:
Kubernetes 概念 | 打印店类比 | 解释 |
---|---|---|
物理存储 (NFS, Cloud Disk) | 纸张仓库 | 真正的存储资源,在远方。 |
PV (Pers8 istentVolume) | 一包已经放在店里的A4纸(500页) | 管理员预先准备好的一份具体存储资源。它有明确的规格(500页,A4)。 |
StorageClass | 产品手册 | 手册上写着:“我们有A4、A3纸,联系供应商XXX,他电话是YYY,下单后30分钟送到”。 |
PVC (PersistentVolumeClaim) | 用户的打印订单 | 订单上写着:“我需要100页A4纸”。它不关心纸是现成的还是现订的。 |
静态供给 | 用库存的纸 | 店员(K8s)查看订单(PVC),然后去库存里找有没有现成的符合要求的A4纸(PV),有就拿来用。 |
动态供给 | 按手册订新纸 | 订单(PVC)上注明“按手册里的A4纸标准订购”。店员(K8s)根据手册(StorageClass)打电话给供应商(Provisioner),供应商立刻送一包新的100页A4纸(PV)到店里,并交给用户。 |
Pod | 打印任务 | 打印任务开始,需要使用那100页纸。 |
Reclaim Policy: Delete | 打印完即焚 | 打印任务完成后,这批纸直接销毁。 |
Reclaim Policy: Retain | 打印完存档 | 打印任务完成后,这批用过的纸被收起来放到角落(Released ),管理员之后决定是扔掉还是重新利用。 |
希望这个详细的解释和类比能帮助你彻底理解 PV 和 PVC 的原理!