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 的动态创建,完美适配大规模集群的存储需求。

相关推荐
ICT董老师2 小时前
在Ubuntu 22.04上使用GitLab和Jenkins部署CI/CD的完整过程
ubuntu·ci/cd·kubernetes·gitlab·jenkins
2501_940414082 小时前
我用这套云原生工作流,把上线时间从1天压到3分钟
云原生
鲨莎分不晴2 小时前
云计算技术架构与原理深度解析:从虚拟化到云原生的演进之路
云原生·架构·云计算
ζั͡山 ั͡有扶苏 ั͡✾2 小时前
K8s 集群内存压力检测和智能 Pod 驱逐工具
云原生·容器·kubernetes
腾讯数据架构师2 小时前
k8s兼容昆仑芯p800
人工智能·云原生·容器·kubernetes·cube-studio·昆仑芯
阿杰 AJie2 小时前
Docker 常用指令和使用方法
docker·容器·eureka
风一样的男子&3 小时前
kylin桌面版v10安装docker和k8s
docker·kubernetes·kylin
阿杰 AJie3 小时前
Docker 启动参数速查表(全镜像通用)
运维·docker·容器