一、核心概念:PV 与 PVC 定义及特点

1.1 PV(Persistent Volume,持久卷)

PV 是 Kubernetes 集群中由管理员预先准备或通过 StorageClass 动态生成的持久化存储资源,其核心特点如下:

  • 创建方式灵活:支持管理员手动预先创建,也可通过 StorageClass 根据 PVC 需求动态生成;
  • 存储类型丰富:兼容 NFS 网络文件系统、本地磁盘、云盘等多种存储介质;
  • 生命周期独立:与 Pod 生命周期解耦,即使 Pod 被删除,PV 中的数据仍会保留,不会丢失;
  • 关键配置项:包含访问模式(Access Modes)、存储容量(Capacity)、回收策略(Reclaim Policy)等核心属性,用于定义存储资源的使用规则。

1.2 PVC(Persistent Volume Claim,持久卷声明)

PVC 是用户对存储资源的 “申请单”,用户通过 PVC 声明所需的存储需求,由 Kubernetes 集群自动匹配合适的 PV,其核心特点如下:

  • 需求明确化:在 PVC 中清晰声明所需的存储容量、访问权限(读写模式)等需求;
  • 自动匹配绑定:Kubernetes 集群会根据 PVC 的需求(如容量、访问模式、标签选择器等),自动筛选并绑定符合条件的 PV;
  • Pod 挂载桥梁:PVC 与 PV 绑定成功后,Pod 可通过引用 PVC 名称,实现对 PV 存储资源的挂载和使用,无需关注 PV 的具体存储细节。

二、PV 与 PVC 工作原理流程

Kubernetes 中 PV 与 PVC 的协作遵循 “准备 - 申请 - 绑定 - 使用 - 回收” 的完整流程,具体步骤如下:

  • PV 准备阶段:管理员可提前手动创建一批 PV,也可配置 StorageClass,实现根据 PVC 需求动态生成 PV;
  • PVC 申请阶段:用户创建 PVC 资源,在配置中描述所需的存储容量(如 1Gi)、访问模式(如 ReadWriteOnce)、标签选择器(如匹配特定标签的 PV)等需求;
  • 自动绑定阶段:Kubernetes 集群的存储调度组件会根据 PVC 的需求,从集群中筛选出满足条件的 PV(需同时满足容量、访问模式、标签匹配等条件),完成 PVC 与 PV 的一对一绑定;
  • Pod 使用阶段:在 Pod 的配置中,通过volumes.persistentVolumeClaim.claimName引用已绑定的 PVC,再通过volumeMounts将 PV 挂载到 Pod 的指定目录,实现数据持久化存储;
  • 资源回收阶段:当 PVC 被删除后,Kubernetes 会根据 PV 预设的 “回收策略”,对 PV 及其中的数据进行处理(如保留数据、删除资源、清空复用等)。

三、PV 关键配置:访问模式

PV 的访问模式定义了存储资源可被挂载的节点范围和读写权限,Kubernetes 支持三种核心访问模式,适用于不同的业务场景:

访问模式 简称 权限说明 适用场景
ReadWriteOnce RWO 仅允许集群中的一个节点以 “读写” 方式挂载;若多个 Pod 需使用该 PV,需调度到同一节点 单节点独占读写场景,如数据库数据存储
ReadOnlyMany ROX 允许集群中多个节点以 “只读” 方式挂载;多节点的多个 Pod 可同时读取,但无法写入 多节点共享静态数据场景,如配置文件、静态资源
ReadWriteMany RWX 允许集群中多个节点以 “读写” 方式挂载;多节点的多个 Pod 可同时读写 多节点共享可写数据场景,如分布式存储

四、实操指南:PV、PVC 与 Pod 的创建及使用

4.1 第一步:创建 PV(手动创建示例)

通过 YAML 文件定义 3 个不同配置的 PV(分别对应 RWO、ROX、RWX 访问模式),存储类型均为 NFS,具体配置如下:

# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v1  # PV名称
  labels:
    app: v1  # 标签,用于PVC通过标签选择器匹配
spec:
  nfs:  # 存储类型为NFS
    server: 192.168.197.181  # NFS服务器地址
    path: /data/volume_test/v1  # NFS后端存储目录
  accessModes: ["ReadWriteOnce"]  # 访问模式:RWO
  capacity:
    storage: 1Gi  # 存储容量:1Gi
  persistentVolumeReclaimPolicy: Retain  # 回收策略:Retain(默认,可省略)
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v2
  labels:
    app: v2
spec:
  nfs:
    server: 192.168.197.181
    path: /data/volume_test/v2
  accessModes: ["ReadOnlyMany"]  # 访问模式:ROX
  capacity:
    storage: 2Gi
  persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: v3
  labels:
    app: v3
spec:
  nfs:
    server: 192.168.197.181
    path: /data/volume_test/v3
  accessModes: ["ReadWriteMany"]  # 访问模式:RWX
  capacity:
    storage: 3Gi
  persistentVolumeReclaimPolicy: Retain

执行创建命令及验证:
# 创建PV

[root@master1 yaml]# kubectl apply -f pv.yaml

persistentvolume/v1 created

persistentvolume/v2 created

persistentvolume/v3 created

# 查看PV状态(此时状态为Available,等待PVC绑定)

[root@master1 yaml]# kubectl get pv

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE

pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            Delete           Bound       default/test-claim1   nfs            <unset>                          30d

v1                                         1Gi        RWO            Retain           Available                                        <unset>                          8s

v2                                         2Gi        ROX            Retain           Available                                        <unset>                          8s

v3                                         3Gi        RWX            Retain           Available                                        <unset>                          8s

4.2 第二步:创建 PVC(匹配对应 PV)

通过 YAML 文件创建 3 个 PVC,分别通过标签选择器(matchLabels)匹配上述 3 个 PV,明确声明所需的存储容量和访问模式:

# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v1  # PVC名称
spec:
  accessModes: ["ReadWriteOnce"]  # 声明访问模式,需与目标PV一致
  selector:
    matchLabels:
      app: v1  # 匹配标签为app:v1的PV(即v1)
  resources:
    requests:
      storage: 1Gi  # 声明存储容量,需≤目标PV容量
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v2
spec:
  accessModes: ["ReadOnlyMany"]  # 与v2的访问模式一致
  selector:
    matchLabels:
      app: v2  # 匹配v2
  resources:
    requests:
      storage: 2Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-v3
spec:
  accessModes: ["ReadWriteMany"]  # 与v3的访问模式一致
  selector:
    matchLabels:
      app: v3  # 匹配v3
  resources:
    requests:
      storage: 3Gi
执行创建命令及验证:
# 创建PVC

[root@master1 yaml]# kubectl apply -f pvc.yaml

persistentvolumeclaim/pvc-v1 created

persistentvolumeclaim/pvc-v2 created

persistentvolumeclaim/pvc-v3 created

# 查看PVC状态(此时已与对应PV绑定,状态为Bound)

[root@master1 yaml]# kubectl get pvc

NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

pvc-v1        Bound    v1                                         1Gi        RWO                           <unset>                 5s

pvc-v2        Bound    v2                                         2Gi        ROX                           <unset>                 5s

pvc-v3        Bound    v3                                         3Gi        RWX                           <unset>                 5s

test-claim1   Bound    pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            nfs            <unset>                 30d

4.3 第三步:创建 Pod 并挂载 PVC

通过 Deployment 创建 3 个 Pod 副本,将 PVC(pvc-v1)挂载到 Pod 的指定目录(/usr/share/nginx/html),实现数据持久化:

# pod_pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pvc-test  # Deployment名称
spec:
  replicas: 3  # 创建3个Pod副本
  selector:
    matchLabels:
      cunchu: pvc  # 标签选择器,匹配Pod模板
  template:
    metadata:
      labels:
        cunchu: pvc  # Pod标签,与selector对应
    spec:
      containers:
      - name: test-pvc  # 容器名称
        image: nginx:1.25  # 基础镜像
        imagePullPolicy: IfNotPresent  # 镜像拉取策略:本地有则不拉取
        ports:
        - containerPort: 80  # 容器暴露端口
          protocol: TCP
        volumeMounts:
        - name: nginx-html  # 挂载卷名称,需与下方volumes.name一致
          mountPath: /usr/share/nginx/html  # 容器内挂载路径
      volumes:
      - name: nginx-html  # 卷名称,与volumeMounts.name对应
        persistentVolumeClaim:
          claimName: pvc-v1  # 引用已绑定的PVC名称
执行创建命令及验证:
# 创建Deployment(Pod由Deployment自动管理)

[root@master1 yaml]# kubectl apply -f pod_pvc.yaml

deployment.apps/pvc-test unchanged

# 查看Pod状态(3个副本均为Running状态)

[root@master1 yaml]# kubectl get pods -l cunchu=pvc

NAME                        READY   STATUS    RESTARTS   AGE

pvc-test-79765f768b-c4z8z   1/1     Running   0          4m40s

pvc-test-79765f768b-pb578   1/1     Running   0          4m40s

pvc-test-79765f768b-tjnqv   1/1     Running   0          4m40s

4.4 第四步:验证 PV 挂载有效性

通过在 PV 对应的 NFS 目录下创建文件,验证 Pod 是否能正常读取挂载的存储资源:

# 进入PV(v1)对应的NFS后端目录

[root@master1 yaml]# cd /data/volume_test/v1

# 在NFS目录下创建测试文件夹lucky

[root@master1 v1]# mkdir lucky

# 进入任意一个Pod内部,查看挂载目录下的文件

[root@master1 yaml]# kubectl exec -it pvc-test-79765f768b-c4z8z -- /bin/bash

# 进入Pod内的挂载路径

root@pvc-test-79765f768b-c4z8z:/# cd /usr/share/nginx/html/

# 查看文件(可看到NFS目录下创建的lucky文件夹,说明挂载成功)

root@pvc-test-79765f768b-c4z8z:/usr/share/nginx/html# ls

lucky

五、PV 核心配置:回收策略

PV(Persistent Volume,持久化卷)的回收策略,核心定义为当关联的 PVC(Persistent Volume Claim,持久化卷声明)被删除时,PV 的处理规则。在 Kubernetes(简称 K8s)体系中,支持三种标准回收策略,用户可在创建 PV 时,通过persistentVolumeReclaimPolicy字段显式指定。

PV 回收策略的核心作用是平衡数据安全性、资源复用效率与运维成本,不同策略适用于不同的业务场景(如核心数据存储、临时测试资源等),需根据实际需求选择。

5.1三种核心 PV 回收策略详解

5.1.1Retain(保留策略):手动控制资源与数据

1、策略核心逻辑

Retain是最保守的回收策略,核心特点为保留 PV 资源与存储数据

  • 当 PVC 被删除后,PV 不会被自动删除,也不会被 K8s 调度系统重新分配给新 PVC;
  • PV 状态会从Bound(已绑定)变为Released(已释放),此时 PV 仍保留原 PVC 的关联记录,且存储后端的数据完全不变;
  • 后续需通过手动操作处理 PV(如删除 PV、清理数据或重新关联 PVC),否则 PV 将一直处于Released状态无法复用。

2 实操案例验证

步骤 1:初始状态(PV 与 PVC 绑定)

通过kubectl get pv查看 PV 状态,可见v1、v2、v3三个 PV 的回收策略为Retain,且已与对应的 PVC 绑定:

[root@master1 v1]# kubectl get pv

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            Delete           Bound    default/test-claim1   nfs            <unset>                  30d

v1                                         1Gi        RWO            Retain           Bound    default/pvc-v1                       <unset>                  15m

v2                                         2Gi        ROX            Retain           Bound    default/pvc-v2                       <unset>                  15m

v3                                         3Gi        RWX            Retain           Bound    default/pvc-v3                       <unset>                  15m

步骤 2:删除 PVC 后,PV 状态变为 Released

删除关联的 PVC 后,再次查看 PV 状态,v1、v2、v3的状态从Bound变为Released,但 PV 资源未被删除:

[root@master1 yaml]# kubectl delete -f pvc.yaml

persistentvolumeclaim "pvc-v1" deleted

persistentvolumeclaim "pvc-v2" deleted

persistentvolumeclaim "pvc-v3" deleted

[root@master1 yaml]# kubectl get pv

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            Delete           Bound      default/test-claim1   nfs            <unset>                  30d

v1                                         1Gi        RWO            Retain           Released   default/pvc-v1                       <unset>                  19m

v2                                         2Gi        ROX            Retain           Released   default/pvc-v2                       <unset>                  19m

v3                                         3Gi        RWX            Retain           Released   default/pvc-v3                       <unset>                  19m

步骤 3:重新创建 PVC,无法绑定 Released 状态的 PV

由于Retain策略下 PV 不会被重新调度,重新创建 PVC 后,PVC 会处于Pending状态,无法与v1、v2、v3绑定:

[root@master1 yaml]# kubectl apply -f pvc.yaml

persistentvolumeclaim/pvc-v1 created

persistentvolumeclaim/pvc-v2 created

persistentvolumeclaim/pvc-v3 created

[root@master1 yaml]# kubectl get pv

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            Delete           Bound      default/test-claim1   nfs            <unset>                  30d

v1                                         1Gi        RWO            Retain           Released   default/pvc-v1                       <unset>                  19m

v2                                         2Gi        ROX            Retain           Released   default/pvc-v2                       <unset>                  19m

v3                                         3Gi        RWX            Retain           Released   default/pvc-v3                       <unset>                  19m

[root@master1 yaml]# kubectl get pvc

NAME          STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

pvc-v1        Pending                                                                                       <unset>                  22s

pvc-v2        Pending                                                                                       <unset>                  22s

pvc-v3        Pending                                                                                       <unset>                  22s

test-claim1   Bound     pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            nfs            <unset>                  30d
5.1.2 Delete(删除策略):自动销毁 PV 资源

1 策略核心逻辑

Delete是最自动化的回收策略,核心特点为PVC 删除后,自动销毁关联的 PV 资源,但需注意:

  • PV 对象会被 K8s 自动删除,但存储后端的实际资源(如 NFS 目录、块设备)是否删除,取决于 PV 的类型和存储插件支持情况
  • 适用于 “无需保留数据” 的场景(如测试环境、临时业务),但需警惕存储后端资源未清理导致的 “残留问题”。

2 不同 PV 类型下的 Delete 策略表现

为明确Delete策略的实际效果,下表对比了三种常见 PV 类型的行为差异:

PV 类型 Delete 策略是否生效(PV 对象是否删除) 后端存储资源(目录 / 块设备)是否自动删除
手动创建的 NFS PV 是(PV 对象被删除) 否(需手动清理 NFS 后端目录)
基于 StorageClass 的动态 PV 是(PV 对象被删除) 是(若 CSI 插件支持,存储资源会完全释放)
hostPath(本地路径)PV 是(PV 对象被删除) 否(本地文件 / 目录仍保留在节点上)

3 实操案例:NFS 类型 PV 的 Delete 策略验证

步骤 1:创建 NFS 类型 PV(指定 Delete 策略)

编写 PV 配置文件pv_test.yaml,指定存储类型为 NFS,回收策略为Delete:

[root@master1 yaml]# cat pv_test.yaml

apiVersion: v1

kind: PersistentVolume

metadata:

  name: v4

  labels:

    app: v4

spec:

  nfs:

    server: 192.168.197.181  # NFS服务器地址

    path: /data/volume_test/v4  # NFS后端目录

  accessModes:

  - ReadWriteOnce  # 读写权限(仅单节点挂载)

  capacity:

    storage: 1Gi  # 存储容量

  persistentVolumeReclaimPolicy: Delete  # 回收策略为Delete

执行创建命令,查看 PV 状态为Available(待绑定):

[root@master1 yaml]# kubectl apply -f pv_test.yaml

persistentvolume/v4 created

[root@master1 yaml]# kubectl get pv | grep v4

v4                                         1Gi        RWO            Delete           Available                                        <unset>                  12s

步骤 2:创建 PVC 并绑定 PV

编写 PVC 配置文件pvc_test.yaml,通过标签选择器匹配 PVv4:

[root@master1 yaml]# cat pvc_test.yaml

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: pvc-v4

spec:

  accessModes: ["ReadWriteOnce"]

  selector:

    matchLabels:

      app: v4  # 匹配PV v4的标签

  resources:

    requests:

      storage: 1Gi

执行创建命令,查看 PVC 状态为Bound(已绑定 PVv4):

[root@master1 yaml]# kubectl apply -f pvc_test.yaml

persistentvolumeclaim/pvc-v4 created

[root@master1 yaml]# kubectl get pvc

NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

pvc-v4        Bound    v4                                         1Gi        RWO                           <unset>                  5s

test-claim1   Bound    pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            nfs            <unset>                  31d

步骤 3:删除 PVC 后,PV 状态变为 Failed 且后端目录残留

删除 PVC 后,PVv4的状态变为Failed(因 NFS 后端目录未清理,K8s 无法完全销毁资源),且重新创建 PVC 会失败:

# 删除PVC

[root@master1 yaml]# kubectl delete -f pvc_test.yaml

persistentvolumeclaim "pvc-v4" deleted

# 查看PV状态:v4变为Failed

[root@master1 yaml]# kubectl get pv

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                 STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            Delete           Bound      default/test-claim1   nfs            <unset>                  31d

v1                                         1Gi        RWO            Retain           Available                                        <unset>                  22h

v2                                         2Gi        ROX            Retain           Available                                        <unset>                  22h

v3                                         3Gi        RWX            Retain           Available                                        <unset>                  22h

v4                                         1Gi        RWO            Delete           Failed      default/pvc-v4                       <unset>                  2m3s

# 重新创建PVC,状态为Pending(无法绑定Failed的PV)

[root@master1 yaml]# kubectl apply -f pvc_test.yaml

persistentvolumeclaim/pvc-v4 created

[root@master1 yaml]# kubectl get pvc

NAME          STATUS    VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE

pvc-v4        Pending                                                                                       <unset>                  6s

test-claim1   Bound     pvc-4d24c635-2e08-46e9-8f70-8cbac620d2ee   1Gi        RWX            nfs            <unset>                  31d

# 验证NFS后端目录:仍存在(未被自动删除)

[root@master1 yaml]# ls -al /data/volume_test/v4/

total 0

drwxr-xr-x  2 root root   6 Aug 27 22:27 .

drwxr-xr-x 12 root root 107 Aug 27 22:27 ..

注意事项

对于 NFS 类型 PV,不建议使用 Delete 策略:由于后端目录不会被自动清理,易导致 “PV 已删除但数据残留” 的误解,且残留目录需手动清理,增加运维成本。

5.1.3 Recycle(回收策略):自动清空数据并复用(不推荐)

1 策略核心逻辑

Recycle是早期的 “折中策略”,核心特点为:

  • 当 PVC 被删除后,K8s 会自动执行内部命令(如rm -rf /path/*)清空 PV 的存储数据;
  • 数据清空后,PV 状态从Bound变为Available,可重新被新 PVC 绑定复用。

2 不推荐使用的原因

  • 清理不彻底:内部命令仅能清空表层文件,无法处理特殊场景(如隐藏文件、分区残留数据),存在数据泄露风险;
  • 兼容性差:现代存储插件(如 CSI)大多不支持Recycle策略,仅兼容部分传统存储类型;
  • 安全性低:无数据擦除确认机制,误操作后无法恢复数据,不适用于生产环境。

目前 K8s 官方已逐步淡化Recycle策略,推荐用Retain(手动控制)或Delete(自动销毁)替代。

5.2 PV 回收策略选择建议

业务场景 推荐策略 核心原因
核心业务数据存储(如数据库) Retain 数据安全性优先,需手动控制数据清理,避免误删
测试环境 / 临时业务 Delete 资源自动回收,减少运维成本(需确保存储插件支持后端资源清理)
需复用 PV 但无需保留数据 Retain + 手动清理 替代 Recycle,手动清空数据后重新关联 PVC,兼顾安全性与复用性

同时需注意:

  • 无论选择哪种策略,都需定期检查存储后端资源(如 NFS 目录、hostPath 路径),避免残留资源占用磁盘;
  • 动态 PV(基于 StorageClass)优先使用Delete策略,因 CSI 插件可实现存储资源的 “全生命周期自动化”;
  • 生产环境中禁止使用Recycle策略,防止数据泄露或清理不彻底导致的业务风险。
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐