PV (PersistentVolume) 和 PVC (PersistentVolumeClaim) 的生命周期与绑定机制是怎样的?
在 Kubernetes 中,PV (PersistentVolume) 和 PVC (PersistentVolumeClaim) 是存储管理的核心概念。理解它们的生命周期和绑定机制,对于管理有状态应用(Stateful Applications)至关重要。
可以将它们的关系比喻为:
- PV 是房产(实际的存储资源,如 NFS、AWS EBS、Ceph)。
- PVC 是租房申请(用户对存储的需求描述,如“我要 10GB,要能读写”)。
- StorageClass 是房产中介(根据申请自动建造或分配房产)。
以下是详细的生命周期与绑定机制解析:
一、 PV 和 PVC 的生命周期 (Lifecycle)
PV 和 PVC 的生命周期通常遵循四个阶段:供应 (Provisioning) -> 绑定 (Binding) -> 使用 (Using) -> 回收 (Reclaiming)。
1. 供应 (Provisioning)
这是创建 PV 的阶段,有两种方式:
- 静态供应 (Static):
- 集群管理员预先创建好一堆 PV。
- 这些 PV 对应真实的后端存储(如创建好几个 NFS 目录或云硬盘)。
- 适用场景: 存储资源固定,或不支持动态创建的传统存储。
- 动态供应 (Dynamic):
- 管理员不需要预先创建 PV,而是创建一个 StorageClass(存储类)。
- 当用户创建一个 PVC 时,如果找不到匹配的静态 PV,Kubernetes 会根据 PVC 指定的 StorageClass 自动创建一个 PV。
- 适用场景: 云环境(AWS, GCP, Azure)或支持 CSI 的现代存储系统。
2. 绑定 (Binding)
- 用户创建 PVC(由于 PVC 是命名空间级别的,PV 是集群级别的,PVC 就像一张票据)。
- Kubernetes 的控制平面(PV Controller)会持续观察新的 PVC。
- 匹配过程: 控制器会寻找一个“合适”的 PV(状态为 Available)与该 PVC 进行绑定。
- 一旦找到,PV 和 PVC 就会进入 Bound 状态。
- 注意: 绑定是一对一的排他关系。
3. 使用 (Using)
- Pod 在定义中引用 PVC(作为 Volume 挂载)。
- Kubernetes 节点(Kubelet)根据 PVC 找到绑定的 PV,将真实的存储挂载到 Pod 的容器内。
- 保护机制: 当 Pod 正在使用 PVC 时,Kubernetes 会启动“存储对象在用保护”(Storage Object in Use Protection),防止用户误删除正在使用的 PVC。
4. 回收 (Reclaiming)
当用户不再需要存储时,会删除 PVC。此时 PV 的命运取决于其 回收策略 (Reclaim Policy):
- Retain (保留):
- PVC 删除后,PV 变为 Released 状态。
- 数据依然保留,但 PV 不可被新的 PVC 直接绑定(因为它还包含前一个用户的数据)。
- 管理员需要手动清理数据并删除 PV 对象,或者手动移除 PV 的
ClaimRef字段才能复用。
- Delete (删除):
- PVC 删除后,PV 也会被自动删除。
- 同时,后端的物理存储(如 AWS EBS 卷)也会被删除。
- 这是大多数云服务商动态供应的默认策略。
- Recycle (回收 - 已弃用):
- 执行基本的
rm -rf /thevolume/*,然后让 PV 变回 Available 状态供他人使用。现在基本不再使用,建议用动态供应替代。
- 执行基本的
二、 绑定机制详解 (Binding Mechanism)
Kubernetes 如何决定哪个 PV 绑定给哪个 PVC?这是一个基于条件的匹配过程。
1. 匹配条件
PV Controller 在绑定时会检查以下参数,必须全部满足:
- 存储容量 (Capacity): PV 的容量必须 PVC 请求的容量。
- 访问模式 (Access Modes): PV 支持的模式必须包含 PVC 请求的模式。
ReadWriteOnce (RWO): 单节点读写。ReadOnlyMany (ROX): 多节点只读。ReadWriteMany (RWX): 多节点读写(需要底层存储支持,如 NFS)。
- StorageClass (存储类):
- 如果 PVC 指定了
storageClassName,则必须绑定到具有相同类名的 PV。 - 如果 PVC 将
storageClassName设为""(空字符串),则只能绑定到无类名(Classless)的 PV。 - 如果 PVC 未指定
storageClassName,则根据集群是否开启DefaultStorageClass准入插件来决定行为(通常绑定到默认存储类)。
- 如果 PVC 指定了
- 卷模式 (Volume Mode): 必须匹配(
Filesystem或Block)。
2. 预绑定 (Pre-binding)
用户可以在创建 PVC 时,直接在 spec.volumeName 字段中写死某个 PV 的名字。这会跳过匹配过程,强制将两者绑定(前提是该 PV 存在且未被绑定)。
3. 延迟绑定 (WaitForFirstConsumer)
这是 StorageClass 的一种高级绑定模式 (volumeBindingMode: WaitForFirstConsumer)。
- 问题: 默认情况下,PVC 一创建,系统就立马创建/绑定 PV。但在多可用区(Multi-Zone)环境中,如果 PV 被创建在 Zone-A,而随后 Pod 被调度到了 Zone-B,Pod 将无法启动。
- 解决: 设置延迟绑定后,PVC 创建后会处于 Pending 状态,直到使用该 PVC 的 Pod 被调度器选中节点后,才会触发 PV 的创建和绑定。这确保了存储和计算资源在同一个拓扑区域(Zone/Region)。
三、 状态流转图解
理解 PV 的状态流转有助于排查问题:
- Available (可用): PV 已创建,未被任何 PVC 绑定。
- Bound (已绑定): PV 已被某个 PVC 独占。
- Released (已释放): 绑定的 PVC 已被删除,但集群尚未回收 PV(通常发生在 Retain 策略下)。此时 PV 不能接受新绑定。
- Failed (失败): 自动回收失败。
典型流程:
plaintext
[创建 PV] --> Available
|
[创建 PVC] --> (匹配成功) --> Bound
|
[Pod 使用]
|
[删除 PVC]
|
+-------------------+-------------------+
| | |
(Policy: Retain) (Policy: Delete) (Policy: Recycle)
| | |
Released PV 被删除 Available (数据被清空)
|
(管理员手动处理)
四、 常见问题与总结
PVC 一直 Pending 怎么办?
- 检查是否有满足容量、访问模式、StorageClass 的 PV (Available 状态)。
- 如果是动态供应,检查 StorageClass 配置或云厂商配额。
- 检查是否开启了
WaitForFirstConsumer,如果是,需要先创建 Pod。
PVC 删除卡在 Terminating 怎么办?
- 通常是因为有 Pod 正在使用该 PVC。Kubernetes 保护机制会阻止删除。删除对应的 Pod 后,PVC 就会消失。
Released 状态的 PV 怎么复用?
- 如果是 Retain 策略,你需要手动编辑 PV,删除
spec.claimRef字段(即删除对旧 PVC 的引用 UID)。保存后,PV 会变回 Available。
- 如果是 Retain 策略,你需要手动编辑 PV,删除
总结: PV 是资源,PVC 是请求。绑定是将资源分配给请求的过程。理解回收策略(Retain vs Delete)和延迟绑定机制对于生产环境的数据安全和调度成功率至关重要。
右滑查看面试常问