Kubernetes PV 与 PVC 深度解析:从基础存储到动态部署实战

目录

前言

[一、先搞懂:K8s 基础存储卷(Volume)](#一、先搞懂:K8s 基础存储卷(Volume))

[1. emptyDir:Pod 级临时存储](#1. emptyDir:Pod 级临时存储)

[二、PV 与 PVC:存储资源的 "供需分离"](#二、PV 与 PVC:存储资源的 “供需分离”)

[1. 核心概念与角色分工](#1. 核心概念与角色分工)

[2. 关键配置详解](#2. 关键配置详解)

(1)访问模式(accessModes)

(2)回收策略(persistentVolumeReclaimPolicy)

[3. PV 与 PVC 的生命周期](#3. PV 与 PVC 的生命周期)

[三、实战:NFS + PV + PVC 静态存储部署](#三、实战:NFS + PV + PVC 静态存储部署)

[1. 前置准备:部署 NFS 服务端](#1. 前置准备:部署 NFS 服务端)

创建共享目录

配置NFS共享

生效配置

[2. 运维视角:创建 PV](#2. 运维视角:创建 PV)

[3. 开发者视角:创建 PVC 与 Pod](#3. 开发者视角:创建 PVC 与 Pod)

实现PVC和Pod的创建与测试

操作步骤

[四、进阶:StorageClass 动态存储方案](#四、进阶:StorageClass 动态存储方案)

[1. 核心原理](#1. 核心原理)

[2. 动态存储部署步骤](#2. 动态存储部署步骤)

[(1)配置 RBAC 权限](#(1)配置 RBAC 权限)

[(2)部署 NFS Provisioner](#(2)部署 NFS Provisioner)

[(3)创建 StorageClass](#(3)创建 StorageClass)

(4)测试动态存储

操作流程

五、不同存储方案对比与选型建议

选型核心建议:

六、总结


前言

在 Kubernetes(K8s)集群中,容器的文件系统默认是临时性的 ------ 容器崩溃重启后数据会丢失,同一 Pod 内的多个容器也无法直接共享文件。为了解决这两个核心问题,K8s 引入了Volume抽象,而PV(Persistent Volume,持久化存储卷)PVC(Persistent Volume Claim,持久化存储请求)则是在Volume基础上进一步优化的持久化存储方案,让存储管理更灵活、更符合生产环境需求。本文将从基础存储卷入手,逐步深入 PV/PVC 的核心机制、实战配置与动态存储方案。

一、先搞懂:K8s 基础存储卷(Volume)

在学习 PV/PVC 之前,先了解 K8s 原生的三种基础存储卷,它们是 PV/PVC 的技术基础,各自适用于不同场景:

1. emptyDir:Pod 级临时存储

  • 核心特点:Pod 调度到节点时自动创建,Pod 删除后数据随之销毁,仅支持同一 Pod 内的容器共享。

  • 适用场景:临时缓存、容器间临时数据交换(如日志转发、临时计算结果存储)。

  • 简单示例 :两个容器共享emptyDir卷,一个写入日期,一个通过 Nginx 提供访问:

    yaml 复制代码
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-emptydir
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        volumeMounts:
        - name: html
          mountPath: /usr/share/nginx/html/
      - name: busybox
        image: busybox:latest
        volumeMounts:
        - name: html
          mountPath: /data/
        command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
      volumes:
      - name: html
        emptyDir: {}
     

    二、PV 与 PVC:存储资源的 "供需分离"

    基础存储卷虽然解决了临时共享和单节点持久化问题,但在生产环境中存在明显短板:

  • 开发者需要关心底层存储细节(如 NFS 服务器地址、挂载路径),耦合度高;

  • 存储资源无法统一管理,权限控制复杂;

  • 无法动态分配存储,扩展性差。

PV 与 PVC 的核心设计理念是 **"供需分离"**:运维人员统一管理底层存储资源(定义 PV),开发者只需声明存储需求(创建 PVC),K8s 自动完成 PVC 与 PV 的绑定,开发者无需关注底层存储实现。

1. 核心概念与角色分工

组件 作用 维护者 核心配置
PV 定义底层存储资源(如 NFS 路径、容量、访问模式) 运维工程师 存储类型(nfs/hostPath)、容量(capacity)、访问模式(accessModes)、回收策略(persistentVolumeReclaimPolicy)
PVC 声明存储需求(如容量、访问模式) 应用开发者 申请容量(storage)、访问模式、存储类(storageClassName)
StorageClass 提供动态创建 PV 的模板(可选) 运维工程师 关联存储分配器(Provisioner)、默认回收策略

2. 关键配置详解

(1)访问模式(accessModes)

定义存储卷的访问权限,PV 与 PVC 的访问模式必须匹配(PVC 的访问模式需是 PV 的子集):

  • ReadWriteOnce(RWO):可读可写,仅支持单个 Pod 挂载(所有存储类型均支持);
  • ReadOnlyMany(ROX):只读,支持多个 Pod 挂载(NFS、GlusterFS 等支持);
  • ReadWriteMany(RWX):可读可写,支持多个 Pod 共享(仅 NFS、Ceph 等分布式存储支持)。

(2)回收策略(persistentVolumeReclaimPolicy)

PV 被 PVC 释放后的处理方式:

  • Retain(保留):保留数据,需手动清理(适合重要数据,避免误删);
  • Delete(删除):自动删除底层存储资源(仅云存储如 AWS EBS、Azure Disk 支持);
  • Recycle(回收):清空数据后重新变为可用(仅 NFS/HostPath 支持,已逐步废弃)。

3. PV 与 PVC 的生命周期

  1. Provisioning(配置):运维手动创建 PV(静态),或通过 StorageClass 动态创建;
  2. Binding(绑定) :K8s 根据 PVC 的需求(容量、访问模式)匹配可用 PV,绑定后 PV 状态变为Bound
  3. Using(使用):Pod 通过 PVC 挂载存储卷,持续使用直至 Pod 销毁;
  4. Releasing(释放) :删除 PVC 后,PV 状态变为Released,数据保留;
  5. Recycling(回收) :根据回收策略处理 PV(保留 / 删除 / 清空),处理后状态变为Available可重新绑定。

三、实战:NFS + PV + PVC 静态存储部署

下面通过 "NFS 作为底层存储,手动创建 PV,开发者通过 PVC 申请" 的流程,实现集群级持久化存储。

1. 前置准备:部署 NFS 服务端

假设 NFS 服务端地址为stor01(192.168.10.13),创建 5 个共享目录供 PV 使用:

使用以下命令安装NFS服务和依赖组件:

bash 复制代码
yum install -y nfs-utils rpcbind

启动并设置开机自启NFS和RPC服务:

bash 复制代码
systemctl start rpcbind nfs
systemctl enable rpcbind nfs

创建共享目录

创建多个共享目录并设置权限:

bash 复制代码
mkdir -p /data/volumes/v{1..5}
chmod 777 /data/volumes/*

配置NFS共享

编辑/etc/exports文件,配置集群网段访问权限:

bash 复制代码
vim /etc/exports

文件内容示例:

复制代码
/data/volumes/v1 192.168.10.0/24(rw,no_root_squash)
/data/volumes/v2 192.168.10.0/24(rw,no_root_squash)
/data/volumes/v3 192.168.10.0/24(rw,no_root_squash)
/data/volumes/v4 192.168.10.0/24(rw,no_root_squash)
/data/volumes/v5 192.168.10.0/24(rw,no_root_squash)

生效配置

重新加载NFS配置使更改生效:

bash 复制代码
exportfs -arv

2. 运维视角:创建 PV

定义 5 个 PV,分别对应 NFS 的 5 个共享目录,配置不同容量和访问模式:

yaml 复制代码
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
spec:
  nfs:
    path: /data/volumes/v3
    server: stor01
  accessModes: ["ReadWriteOnce"]
  capacity:
    storage: 2Gi
  persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
spec:
  nfs:
    path: /data/volumes/v4
    server: stor01
  accessModes: ["ReadWriteMany"]
  capacity:
    storage: 4Gi
  persistentVolumeReclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
spec:
  nfs:
    path: /data/volumes/v5
    server: stor01
  accessModes: ["ReadWriteOnce"]
  capacity:
    storage: 5Gi
  persistentVolumeReclaimPolicy: Retain
 

执行创建命令并查看 PV 状态:

bash 复制代码
kubectl apply -f pv-demo.yaml
kubectl get pv
 

3. 开发者视角:创建 PVC 与 Pod

开发者无需关心 NFS 地址和路径,只需声明 "2Gi 容量、支持 RWX 访问" 的需求:

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  accessModes: ["ReadWriteMany"]
  storageClassName: "standard"  # 指定存储类,动态分配存储
  resources:
    requests:
      storage: 2Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-vol-pvc
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html
    command: ["/bin/sh", "-c"]  # 添加启动命令
    args:
    - while true; do
        echo "$(date) - Hello from PVC" > /usr/share/nginx/html/index.html;
        sleep 10;
      done
  volumes:
  - name: html
    persistentVolumeClaim:
      claimName: mypvc
 

执行部署并验证:

实现PVC和Pod的创建与测试

以下是使用Kubernetes YAML文件创建PVC和Pod,并测试数据持久化的完整代码示例:

操作步骤

执行以下命令部署PVC和Pod:

bash 复制代码
kubectl apply -f pod-vol-pvc.yaml

验证PVC状态(应显示Bound状态):

bash 复制代码
kubectl get pvc

在NFS服务端创建测试文件(假设PV对应的路径是/data/volumes/v3):

bash 复制代码
echo "welcome to use pv3" > /data/volumes/v3/index.html

验证数据持久化效果:

bash 复制代码
kubectl get pods -o wide
curl <Pod_IP>

四、进阶:StorageClass 动态存储方案

静态 PV 方案需要运维手动创建大量 PV,不适用于大规模集群。StorageClass通过 "存储分配器(Provisioner)" 实现 PV 的动态创建 ------ 开发者创建 PVC 后,K8s 自动生成对应的 PV 和 NFS 共享目录,大幅降低运维成本。

1. 核心原理

  • StorageClass:定义动态 PV 的模板(关联 Provisioner、回收策略等);
  • Provisioner:存储分配器(如nfs-client-provisioner),负责与 NFS 服务端交互,自动创建共享目录和 PV;
  • RBAC权限:授权 Provisioner 操作 PV、PVC、StorageClass 等资源的权限。

2. 动态存储部署步骤

(1)配置 RBAC 权限

创建 ServiceAccount 和集群角色,授权 Provisioner 管理存储资源:

yaml 复制代码
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nfs-client-provisioner-clusterrole
rules:
- apiGroups: [""]
  resources: ["persistentvolumes"]
  verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
  resources: ["persistentvolumeclaims"]
  verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
  resources: ["storageclasses"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["events"]
  verbs: ["create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: nfs-client-provisioner-clusterrolebinding
subjects:
- kind: ServiceAccount
  name: nfs-client-provisioner
  namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-clusterrole
  apiGroup: rbac.authorization.k8s.io
 

(2)部署 NFS Provisioner

Provisioner 是动态创建 PV 的核心组件,需关联 NFS 服务端:

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
      - name: nfs-client-provisioner
        image: quay.io/external_storage/nfs-client-provisioner:latest
        env:
        - name: PROVISIONER_NAME
          value: nfs-storage
        - name: NFS_SERVER
          value: stor01
        - name: NFS_PATH
          value: /opt/k8s
        volumeMounts:
        - name: nfs-client-root
          mountPath: /persistentvolumes
      volumes:
      - name: nfs-client-root
        nfs:
          server: stor01
          path: /opt/k8s
 

(3)创建 StorageClass

yaml 复制代码
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"  # 设为false避免冲突

provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "false"  # true保留PVC数据,false自动删除
  pathPattern: "${.PVC.namespace}/${.PVC.name}"  # 存储路径命名规则
  onDelete: "delete"  # 保留策略:delete/retain/archive
  mountOptions: 
    - nfsvers=4.1  # 指定NFS协议版本
    - noatime  # 禁用访问时间更新

allowVolumeExpansion: true  # 允许动态扩容
reclaimPolicy: Delete  # 回收策略:Delete/Retain
volumeBindingMode: Immediate  # 绑定模式:Immediate/WaitForFirstConsumer
 

(4)测试动态存储

创建 PVC 时指定storageClassName,K8s 自动生成 PV:

yaml 复制代码
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-nfs-pvc
spec:
  accessModes: ["ReadWriteMany"]
  storageClassName: nfs-client-storageclass
  resources:
    requests:
      storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: test-storageclass-pod
spec:
  containers:
  - name: busybox
    image: busybox:latest
    command: ["/bin/sh", "-c", "sleep 3600"]
    volumeMounts:
    - name: nfs-pvc
      mountPath: /mnt
  volumes:
  - name: nfs-pvc
    persistentVolumeClaim:
      claimName: test-nfs-pvc
 

验证动态创建结果:

操作流程

部署存储类和PVC

bash 复制代码
kubectl apply -f storageclass-nfs.yaml

验证PVC绑定状态

bash 复制代码
kubectl get pvc test-nfs-pvc
# 预期输出显示STATUS为Bound,VOLUME为自动生成的PV名称

检查NFS服务端共享目录

bash 复制代码
ls /opt/k8s/
# 应出现格式为{namespace}-{pvcName}-{pvName}的目录

测试数据共享功能

bash 复制代码
kubectl exec -it test-storageclass-pod -- sh -c 'echo "dynamic storage test" > /mnt/test.txt'

验证NFS端数据同步

bash 复制代码
cat /opt/k8s/default-test-nfs-pvc-*/test.txt
# 应显示"dynamic storage test"内容

五、不同存储方案对比与选型建议

存储类型 生命周期 共享性 持久性 适用场景
emptyDir Pod 级 同 Pod 内容器 临时缓存、容器间临时数据交换
hostPath 节点级 单节点 本地测试、节点日志存储
NFS 独立服务 多节点 集群共享存储(无动态需求)
PV + PVC 集群级 按需分配 生产环境(静态存储管理)
StorageClass 动态创建 多节点动态分配 大规模集群、云原生生产环境

选型核心建议:

  1. 开发 / 测试环境:用emptyDir(临时)或hostPath(简单持久化);
  2. 小规模生产环境:NFS + PV + PVC(静态管理,运维成本低);
  3. 大规模生产环境:StorageClass + NFS/Ceph(动态分配,适配弹性扩缩容)。

六、总结

PV 与 PVC 通过 "供需分离" 的设计,让运维专注于底层存储管理,开发者专注于业务存储需求,大幅提升了 K8s 存储的灵活性和可维护性。而 StorageClass 则进一步实现了 PV 的动态创建,完美适配大规模集群的存储需求。

相关推荐
阿里云云原生2 天前
阿里云获评 Agentic AI 开发平台领导者,函数计算 AgentRun 赢下关键分!
云原生
蝎子莱莱爱打怪2 天前
Centos7中一键安装K8s集群以及Rancher安装记录
运维·后端·kubernetes
崔小汤呀2 天前
Docker部署Nacos
docker·容器
缓解AI焦虑2 天前
Docker + K8s 部署大模型推理服务:资源划分与多实例调度
docker·容器
阿里云云原生2 天前
MSE Nacos Prompt 管理:让 AI Agent 的核心配置真正可治理
微服务·云原生
阿里云云原生2 天前
当 AI Agent 接管手机:移动端如何进行观测
云原生·agent
阿里云云原生2 天前
AI 原生应用开源开发者沙龙·深圳站精彩回顾 & PPT下载
云原生
阿里云云原生2 天前
灵感启发:日产文章 100 篇,打造“实时热点洞察”引擎
云原生
1candobetter3 天前
Docker Compose Build 与 Up 的区别:什么时候必须重建镜像
docker·容器·eureka
~莫子3 天前
Haproxy七层负载详解+实验详细代码
云原生