
Recycle回收策略依靠专用回收Pod清理存储文件,该Pod运行依赖debian-base:bookworm-v1.0.4镜像。集群若无外网访问权限,会出现镜像拉取失败问题,可通过云链接离线下载镜像包,手动导入集群节点使用。
链接: https://pan.baidu.com/s/17IhaH9O5cF3GzlcjZZDDRg?pwd=dtbn
提取码: dtbn
一、PV与PVC
1. PV定义
PV,全称PersistentVolume(持久化存储卷)。属于集群级存储资源对象,一般由管理员提前创建,对接底层各类真实的存储介质,包含本地磁盘、云硬盘、NAS、NFS、iSCSI等。PV生命周期独立于Pod,不会随着Pod删除而销毁。PV如同集群内的节点,是集群基础资源,属于存储卷插件。逻辑与Pod内普通volume类似,但是拥有独立的生命周期。管理员负责配置、供给后端存储空间,而无需干预业务Pod如何使用这块存储。
可以简单将PV类比为:仓库里现成的硬盘/存储空间。
1.1 PV核心特点
资源供给方:管理员提前划分存储空间、定义访问模式、存储大小、回收策略
独立生命周期:Pod删除、重建,PV数据不会消失
无需绑定容器/Pod,只和PVC绑定
完整存储属性:容量、访问模式、存储类、回收策略
Kubernetes提供两种卷模式(volumeMode):Filesystem文件系统模式、Block块设备模式。当volumeMode配置为Filesystem时,存储卷会以挂载形式接入容器指定目录。若后端存储为空白裸块设备,Kubernetes会在首次挂载前自动为设备格式化并创建文件系统。
1.2 访问模式
1.3 PV回收策略
目前仅NFS和HostPath支持Recycle策略。AES EBS、GCE PD、Azure Disk和Cinder卷都支持Delete策略。
1.4 PV卷阶段(Phase)
2. PVC定义
PVC,全称PersistentVolumeClaim(持久化存储申请)。PVC由开发人员或运维人员创建,相当于存储资源申请凭证,用于声明业务所需要的存储容量、读写访问权限等需求。使用者仅需要将PVC挂载到容器,无需关心底层PV是依托NFS、云盘还是何种存储技术实现。
PVC是面向用户的存储资源申请载体,类似于Pod这种资源消耗逻辑。Pod占用节点内存、CPU这类计算资源;PVC则占用PV存储资源。Pod可以请求指定CPU、内存资源;PVC可以指定存储容量大小、访问模式等存储需求。
可以简单将PVC类比为:向仓库申请领用硬盘的申请表。
2.1 核心特点
资源需求方:只提需求(大小、访问模式、StorageClass),无需关心底层存储硬件
调度匹配机制:k8s自动筛选符合条件的空闲PV,完成一对一绑定
PVC挂载到Pod,Pod读写实际走绑定后的PV
命名空间隔离:PVC属于namespace,PV是集群全局资源
2.2 PVC状态
3. PV与PVC完整工作流程
管理员创建PV,提前准备好存储资源
业务人员重建PVC,写清楚需要的存储空间与条件,如10Gi、可单节点读写
集群控制器自动匹配满足条件的空闲PV,二者绑定
Pod中通过“volumeClaimTemplates”或直接引用PVC名称挂载
Pod删除 → PVC仍存在、PV和数据完整保留
删除PVC,根据PV的回收策略(Retain/Delete/Recycle)决定PV数据是否清理
4. 移除volumeName后PVC仍可匹配PV
当PVC配置中删除“volumeName”参数后依旧能够成功申请PV,依靠的是Kubernetes内置的PV-PVC自动绑定匹配机制。控制器会依次执行多轮筛选来锁定适配PV,完整匹配筛选流程如下:
依据PVC声明的存储容量要求、访问模式(如ReadWriteOnce、ReadOnlyMany等),剔除参数不满足的PV
如果PVC填写了“volumeName”会按照该字段精准筛选指定PV,未填写则跳过这一步
核对存储类(StorageClass)配置,过滤掉存储类不匹配的PV
最后检查标签、节点亲和性等其他约束条件,从剩余符合全部要求的空闲PV(Available 状态)中完成配对绑定
二、StorageClass
1. StorageClass定义
传统静态PV模式需要管理员提前手动创建大量PV,当集群Pod数量多、存储需求经常变化时,手动维护PV工作量极大,不符合自动化运维思想。StorageClass是Kubernetes提供的存储抽象资源,核心作用是实现PV动态供给,统一定义存储的创建规则、后端驱动、回收策略等,消除手动创建PV的繁琐操作,实现存储自动化。
StorageClass是Kubernetes中用于动态供应持久化存储卷(PV)的核心资源对象,核心作用如下:
自动创建PV:接收PV存储申请后,调度对应存储供给器Provisioner自动生成匹配的PV,省去管理员手动批量预创建PV的操作;
统一抽象存储规格:集中定义存储介质类型、性能指标、数据回收策略等通用配置,为业务提供标准化、差异化存储能力;
分层分级管理存储:可以创建多套不同规格的StorageClass(如高性能黄金级、低成本白银级),业务可以根据自身需求灵活选用对应存储方案。
5.1 核心组件
Provisioner是对接底层存储的驱动程序,是动态创建PV的执行者。官方内置AWS EBS、GCE PD、Cinder等云厂商存储驱动。第三方扩展NFS、本地存储、Ceph、MinIO等部署对应Provisioner组件,如nfs-provisioner。PVC发起存储申请后,storageClass会调用绑定的Provisioner,自动在底层存储创建目录/磁盘,并生成对应PV。
2. StorageClass特性
3. NFS外部存储供给器
NFS外部供给器是nfs-subdir-external-provisioner是兼容Kubernetes存储规范的动态卷供给器,属于第三方运维组件,以Pod形式部署在集群内部。该组件对接外部独立NFS服务端,配合StorageClass实现PV自动化动态创建。
当接收到PVC存储申请后,它会自动在NFS共享根目录创建专属子目录并生成匹配PV,供PVC直接绑定。删除PVC时,还可以根据预设策略自动清理对应的NFS子目录。
k8s官方内置供给器仅适配AWS EBS等云厂商块存储,原生不支持NFS共享存储的动态PV供给,因此需要基于NFS实现StorageClass动态卷能力,必须额外部署该第三方组件作为中间驱动。
NFS外部供给器官方GitHub仓库地址
https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner三、Recycle PV案例配置
1. NFS模拟存储设备
[Step1] 本次环境中缺少独立存储设备,利用RedHat服务器部署NFS共享来模拟仿真持久化存储,依托一个200G的虚拟磁盘承载NFS共享数据。

[Step2] 将新添加的进行分区,输入“n”新建分区,其余保持默认,最后输入“w”保存分区表。
[root@redhat ~]# fdisk /dev/nvme0n2
Welcome to fdisk (util-linux 2.37.4).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x2dbaa303.
Command (m for help): n
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p):
Using default response p.
Partition number (1-4, default 1):
First sector (2048-419430399, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-419430399, default 419430399):
Created a new partition 1 of type 'Linux' and of size 200 GiB.
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.[Step3] 格式化文件系统,格式为xfs。
[root@redhat ~]# mkfs.xfs /dev/nvme0n2p1
[Step4] 创建本地挂载目录并写入fstab文件实现开机自动挂载。
[root@redhat ~]# mkdir -p /data/nfs-share
[root@redhat ~]# echo '/dev/nvme0n2p1 /data/nfs-share xfs defaults 0 0' >> /etc/fstab
[root@redhat ~]# mount -a[Step5] 验证:查看挂载情况。
[root@redhat ~]# df -h
[Step6] 安装NFS服务及相关组件。
[root@redhat ~]# dnf install -y nfs-utils rpcbind[Step7] 编辑NFS配置文件,仅允许k8s-master读写。
[root@redhat ~]# vim /etc/exports
# 写入下列内容
/data/nfs-share 192.168.8.0/24(rw,no_root_squash)[Step8] 启动NFS服务并开机自启。
[root@redhat ~]# systemctl enable --now nfs-server.service[Step9] 在所有工作节点上安装NFS组件,分别验证共享。
root@k8s-worker1:~# apt-get install -y nfs-common
root@k8s-worker2:~# apt-get install -y nfs-common
root@k8s-worker1:~# showmount -e 192.168.8.10

2. 创建PV持久化存储卷
[Step1] 因为PV和PVC要编写的YAML文件比较多,这里创建一个目录用于存储文件。
root@k8s-master:~# mkdir pv-pvc
root@k8s-master:~# cd pv-pvc/[Step2] 本地新建YAML清单,定义回收策略为Recycle的PV持久卷。
root@k8s-master:~/pv-pvc# vim pv.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: PersistentVolume # 资源类型
metadata:
name: mypv
spec:
capacity: # 定义PV的容量
storage: 10Gi # 分配存储空间大小
accessModes: # 访问模式
# 仅支持单个节点挂载读写,同一节点可允许多个Pod共用,跨节点无法挂载
- ReadWriteOnce
# 指定PV的回收策略,集群自动创建回收Pod,清空PV内所有文件
persistentVolumeReclaimPolicy: Recycle
nfs: # 配置NFS服务器信息
path: /data/nfs-share # NFS共享目录
server: 192.168.8.10 # NFS服务器地址[Step3] 根据YAML清单向Kubernetes集群声明式地创建PV持久化存储卷。输出的告警信息提示Recycle回收策略已被官方弃用,不在推荐静态PV手动清空数据的回收方式。
root@k8s-master:~/pv-pvc# kubectl create -f pv.yml
[Step4] 验证:查看当前集群中的所有PV卷资源。
root@k8s-master:~/pv-pvc# kubectl get persistentvolume
root@k8s-master:~/pv-pvc# kubectl get pv
3. 创建PVC持久化存储申请
[Step1] 本地新建YAML清单,定义PVC持久化存储申请。
root@k8s-master:~/pv-pvc# vim pvc.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: PersistentVolumeClaim # 资源类型
metadata:
name: mypvc
spec:
accessModes: # 匹配的卷访问模式,需要与PV匹配
- ReadWriteOnce # 匹配访问模式为ReadWriteOnce的PV
volumeName: mypv # 绑定指定名称的PV,匹配mypv
resources: # 存储资源申请配额
requests: # 指定PV容量,如果不存在满足该容量需求的PV,则PVC无法绑定任何PV
storage: 5Gi # 申请的存储空间[Step2] 根据YAML清单向Kubernetes集群声明式地创建PVC持久化存储申请。
root@k8s-master:~/pv-pvc# kubectl create -f pvc.yml[Step3] 验证:查看当前集群中的所有PVC资源,可以看到分配存储容量显示为10G,而非PVC申请的5G。根源在于k8s静态NFS PV内配置的容量数值仅作为调度匹配标识,而非存储空间隔离配额。绑定规则仅要求PV标注容量≥PVC申请容量,集群中仅有一块标注10G的PV,满足5G的容量匹配条件。因此,该PV直接于PVC完成绑定,容器可使用整个10G的存储空间。
root@k8s-master:~/pv-pvc# kubectl get pvc
[Step4] 验证:查看当前集群中的所有PV卷资源,可以看到STATUS从“Available”变更为“Bound”。
root@k8s-master:~/pv-pvc# kubectl get pv
4. 创建Pod关联PVC
[Step1] 本地新建YAML清单,定义Pod资源描述模板,并关联mypvc。
root@k8s-master:~/pv-pvc# vim mypvc-pod.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: Pod # 资源类型
metadata:
name: mypvc-pod
spec:
containers:
- name: mypvc-kylin-pod
image: kylin-server-10-sp3b23-x86_64-20230324:b23
imagePullPolicy: IfNotPresent
args: # 更改容器默认启动命令,自定义运行指令
- /bin/sh
- -c
- sleep 10000
volumeMounts: # 存储卷挂载配置
- mountPath: "/tmp" # 容器内挂载目录
name: kylin-pvc # Volume卷名称
volumes: # 定义存储卷
# 自定义存储卷名称,与[containers.volumeMounts.name]对应
- name: kylin-pvc
persistentVolumeClaim: # 绑定持久化存储申请PVC
claimName: mypvc # 绑定名为mypvc的PVC存储申请[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。
root@k8s-master:~/pv-pvc# kubectl create -f mypvc-pod.yml[Step3] 验证:查看当前集群中的所有的Pod资源。
root@k8s-master:~/pv-pvc# kubectl get pods
[Step4] 验证:登录到mypvc-pod,查看/tmp目录的挂载来源。可以看到NFS服务器IP地址与共享目录,代表PVC已成功挂载到Pod。这里看到可用空间是200G,而非PV标注的10G、PVC申请的5G。原因是NFS无软配额隔离,PV的10G、PVC的5G仅用于k8s调度,不会限制实际读写空间。
root@k8s-master:~/pv-pvc# kubectl exec -it mypvc-pod -- /bin/bash
[root@mypvc-pod /]# df -h /tmp
[Step5] 验证:生成11G大容量文件,写入过程无报错且文件正常创建。说明PV和PVC配置的容量限制仅作为调度匹配标识,不会对实际读写空间施加限制。只有当后端NFS共享空间写满才会报错。
[root@mypvc-pod /]# dd if=/dev/zero of=/tmp/big bs=1G count=11
[root@mypvc-pod /]# ls -lh /tmp/big
[root@mypvc-pod /]# exit
5. 数据持久化测试
[Step1] 删除mypvc-pod后重新创建Pod。
root@k8s-master:~/pv-pvc# kubectl delete pod mypvc-pod
root@k8s-master:~/pv-pvc# kubectl create -f mypvc-pod.yml[Step2] 验证:查看mypvc-pod的/tmp目录,可以看到数据仍然存在。
root@k8s-master:~/pv-pvc# kubectl exec mypvc-pod -- ls -lh /tmp
[Step3] 登录到NFS服务器,同样可以在共享目录下看到该文件。
[root@redhat ~]# ll -h /data/nfs-share/
6. PV回收
在上述创建PV时选择的回收策略是“Recycle”,删除PVC时Kubernetes会启动清理PV内的数据,数据清理流程通过一个单独创建专门用于回收的Pod执行。
需要注意的是:回收Pod依赖镜像bookworm-v1.0.4,如果无法正常拉取可以访问我的百度云链接下载。
[Step1] 这里需要先将占用PVC的Pod删除,防止因为Pod僵死阻塞流程。然后删除PVC,删除完毕后可以看到存在一个回收Pod。
root@k8s-master:~# kubectl delete pod mypvc-pod
root@k8s-master:~# kubectl delete pvc mypvc
root@k8s-master:~# kubectl get pod
[Step2] 验证:此时查看集群中的PV,可以看到“mypv”的状态为“Available”。需要等待控制器自动创建的回收 Pod,挂载存储并清空全部文件。
root@k8s-master:~# kubectl get pv
[Step3] 验证:登录到NFS服务,可以看到共享目录的文件已清空。
[root@redhat ~]# ll /data/nfs-share/
四、Retain PV案例配置
1. NFS模拟存储设备
[Step1] 这里继续使用上述配置好NFS服务器,分别在工作节点验证共享。
root@k8s-worker1:~# showmount -e 192.168.8.10
root@k8s-worker2:~# showmount -e 192.168.8.10

2. 创建PV持久化存储卷
[Step1] 因为PV和PVC要编写的YAML文件比较多,这里创建一个目录用于存储文件。
root@k8s-master:~# mkdir retain-pv-pvc
root@k8s-master:~# cd retain-pv-pvc/[Step2] 本地新建YAML清单,定义回收策略为Retain的PV持久卷。
root@k8s-master:~/retain-pv-pvc# vim retain-pv.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: PersistentVolume # 资源类型
metadata:
name: retain-pv
spec:
capacity: # 定义PV的容量
storage: 10Gi # 分配存储空间大小
accessModes: # 访问模式
# 仅支持单个节点挂载读写,同一节点可允许多个Pod共用,跨节点无法挂载
- ReadWriteOnce
# 指定PV的回收策略,不删除,需要管理员手动回收
persistentVolumeReclaimPolicy: Retain
nfs: # 配置NFS服务器信息
path: /data/nfs-share # NFS共享目录
server: 192.168.8.10 # NFS服务器地址[Step3] 根据YAML清单向Kubernetes集群声明式地创建PV持久化存储卷。
root@k8s-master:~/retain-pv-pvc# kubectl create -f retain-pv.yml[Step4] 验证:查看当前集群中的所有PV卷资源。
root@k8s-master:~/retain-pv-pvc# kubectl get pv
3. 创建PVC持久化存储申请
[Step1] 本地新建YAML清单,定义PVC持久化存储申请。
root@k8s-master:~/retain-pv-pvc# vim retain-pvc.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: PersistentVolumeClaim # 资源类型
metadata:
name: retain-pvc
spec:
accessModes: # 匹配的卷访问模式,需要与PV匹配
- ReadWriteOnce # 匹配访问模式为ReadWriteOnce的PV
volumeName: retain-pv # 绑定指定名称的PV,匹配retain-pvc
resources: # 存储资源申请配额
requests: # 指定PV容量,如果不存在满足该容量需求的PV,则PVC无法绑定任何PV
storage: 5Gi # 申请的存储空间[Step2] 根据YAML清单向Kubernetes集群声明式地创建PVC持久化存储申请。
root@k8s-master:~/retain-pv-pvc# kubectl create -f retain-pvc.yml[Step3] 验证:查看当前集群中的所有PVC资源。
root@k8s-master:~/retain-pv-pvc# kubectl get pvc
[Step4] 验证:查看当前集群中的所有PV卷资源,可以看到retain-pv的状态变更为“Bound”。
root@k8s-master:~/retain-pv-pvc# kubectl get pv
4. 创建Pod关联PVC
[Step1] 本地新建YAML清单,定义Pod资源描述模板,并关联mypvc。
root@k8s-master:~/retain-pv-pvc# vim retain-pod.yml
retain-pvc
# 写入下列内容
apiVersion: v1 # 固定配置
kind: Pod # 资源类型
metadata:
name: retain-pod
spec:
containers:
- name: retain-pod
image: kylin-server-10-sp3b23-x86_64-20230324:b23
imagePullPolicy: IfNotPresent
args: # 更改容器默认启动命令,自定义运行指令
- /bin/sh
- -c
- sleep 10000
volumeMounts: # 存储卷挂载配置
- mountPath: "/tmp" # 容器内挂载目录
name: retain-pvc # Volume卷名称
volumes: # 定义存储卷
# 自定义存储卷名称,与[containers.volumeMounts.name]对应
- name: retain-pvc
persistentVolumeClaim: # 绑定持久化存储申请PVC
claimName: retain-pvc # 绑定名为retain-pvc的PVC存储申请[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。
root@k8s-master:~/retain-pv-pvc# kubectl create -f retain-pod.yml[Step3] 验证:查看当前集群中的所有的Pod资源。
root@k8s-master:~/retain-pv-pvc# kubectl get pods
[Step4] 验证:登录到mypvc-pod,查看/tmp目录的挂载来源。可以看到NFS服务器IP地址与共享目录,代表PVC已成功挂载到Pod。
root@k8s-master:~/retain-pv-pvc# kubectl exec -it retain-pod -- /bin/bash
[root@retain-pod /]# df -h /tmp
[Step5] 验证:生成11G大容量文件,写入过程无报错且文件正常创建。
[root@retain-pod /]# dd if=/dev/zero of=/tmp/big bs=1G count=11
[root@retain-pod /]# ls -lh /tmp/big
[root@retain-pod /]# exit
5. 数据持久化测试
[Step1] 删除retain-pod后重新创建Pod。
root@k8s-master:~/retain-pv-pvc# kubectl delete pod retain-pod
root@k8s-master:~/retain-pv-pvc# kubectl create -f retain-pod.yml[Step2] 验证:查看retain-pod的/tmp目录,可以看到数据仍然存在。
root@k8s-master:~/retain-pv-pvc# kubectl exec retain-pod -- ls -lh /tmp
[Step3] 登录到NFS服务器,同样可以在共享目录下看到该文件。
[root@redhat ~]# ll -h /data/nfs-share/
6. PV回收
[Step1] 这里需要先将占用PVC的Pod删除,防止因为Pod僵死阻塞流程,随后删除PVC。
root@k8s-master:~/retain-pv-pvc# kubectl delete pod retain-pod
root@k8s-master:~/retain-pv-pvc# kubectl delete pvc retain-pvc[Step2] 删除PVC后,PV的数据仍然存在,此时PV的状态为“Released”。
root@k8s-master:~/retain-pv-pvc# kubectl get pv
[Step3] 登录到NFS服务器,可以看到文件仍然存在。
[root@redhat ~]# ll -h /data/nfs-share/
[Step4] 采用Retain回收策略的PV,删除关联PVC后,后端存储数据不会被清理。同时PV会保留指向原PVC的claimRef绑定引用,状态变更为Released。受到该残留引用限制,PV无法对接新PVC,需要手动删除claimRef参数以解决绑定限制。
# 方式1:一键删除
root@k8s-master:~/retain-pv-pvc# kubectl patch pv retain-pv -p '{"spec":{"claimRef":null}}'
# 方式2:手动删除,删除下列整块内容
root@k8s-master:~/retain-pv-pvc# kubectl edit pv retain-pv
claimRef:
name: retain-pvc
namespace: default
uid: xxxxxx[Step5] 查看当前集群中的PV状态,可以看到retain-pv状态变更为“Available”。
root@k8s-master:~/retain-pv-pvc# kubectl get pv
五、StorageClass案例配置
1. 安装与配置外部存储供给器
如果无法正常下载nfs-subdir-external-provisioner.git和nfs-subdir-external-provisioner:v4.0.2,可以访问我的百度云链接获取。
链接: https://pan.baidu.com/s/1SV3Q_dYH_xfnE58Coq7oNA?pwd=9qgu
提取码: 9qgu
[Step1] 克隆仓库,内置全套RBAC、Deployment、StorageClass部署YAML。
root@k8s-master:~# git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner.git
[Step2] 批量替换rbac.yaml和deployment.yaml文件中“namespace”字段值为default。缺省情况下,文件内“namespace”字段值为default,无需任何操作。
root@k8s-master:~# cd nfs-subdir-external-provisioner/
root@k8s-master:~/nfs-subdir-external-provisioner# vim deploy/rbac.yaml
root@k8s-master:~/nfs-subdir-external-provisioner# vim deploy/deployment.yaml
# 将文件内所有 [namespace: default] 修改为default,默认情况下文件的namespace全为default,不需任何修改
:%s/namespace:.*/namespace: default/g // 批量替换
:x // 保存并退出[Step3] NFS动态存储供给器需要调用Kubernetes接口实现PV自动创建,必须配置RBAC权限赋予其操作集群存储资源的资格。加载rbac.yaml文件即可加载并部署rbac.yaml内的权限配置,完成供给器运行所需要的权限初始化。
root@k8s-master:~/nfs-subdir-external-provisioner# kubectl create -f deploy/rbac.yaml
[Step4] 验证:查看RBAC文件所创建的相关资源。
root@k8s-master:~/nfs-subdir-external-provisioner# kubectl get sa
root@k8s-master:~/nfs-subdir-external-provisioner# kubectl get role
root@k8s-master:~/nfs-subdir-external-provisioner# kubectl get rolebindings.rbac.authorization.k8s.io
[Step5] 修改供给器Deployment配置,对接外部NFS服务。“env”字段负责provisioner程序运行逻辑,用于创建子PV目录。“volumes”字段负责宿主机kubelet挂载NFS到Pod,底层挂载,不会读取env。
root@k8s-master:~/nfs-subdir-external-provisioner# vim deploy/deployment.yaml
# 修改下列内容
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 192.168.8.10 # 替换为NFS服务器IP地址
- name: NFS_PATH
value: /data/nfs-share # 替换为NFS共享目录
volumes:
- name: nfs-client-root
nfs:
server: 192.168.8.10 # 替换为NFS服务器IP地址
path: /data/nfs-share # 替换为NFS共享目录[Step6] 根据YAML清单向Kubernetes集群声明式地创建NFS供给器Pod。需要注意的是,这个Pod依赖nfs-subdir-external-provisioner:v4.0.2镜像,如果无法正常拉取,可以访问我提供的百度云链接下载并导入。
root@k8s-master:~/nfs-subdir-external-provisioner# kubectl apply -f deploy/deployment.yaml[Step7] 验证:查看当前集群中的所有Deployment资源。
root@k8s-master:~/nfs-subdir-external-provisioner# kubectl get deployments.apps
[Step8] 验证:查看当前集群中的所有Pod资源。
root@k8s-master:~# kubectl get pods
2. 创建StorageClass资源
[Step1] 如果需要支持NFS,需要在所有工作节点都按照NFS组件,这里我们在上述的操作已安装。本地新建YAML清单,创建StorageClass动态供应卷。
root@k8s-master:~# vim storageclass.yml
# 写入下列内容
apiVersion: storage.k8s.io/v1 # 固定配置
kind: StorageClass # 资源类型
metadata:
name: nfs-client # 存储类名称,创建PVC时通过storageClassName:nfs-storage引用
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 指定存储供给器
allowVolumeExpansion: true # 开启存储卷在线扩容功能
# 延迟绑定机制:不会在PVC创建时立即生成并绑定PV,等到Pod调度就绪、真正使用该存储时,才触发provisioner创建NFS目录与PV
volumeBindingMode: WaitForFirstConsumer
parameters: # 自定义供给器参数
# 自定义NFS共享下目录命名规则,例如:default命名空间下名为retain-pvc的PVC,自动创建目录default-retain-pvc
pathPattern: "${.PVC.namespace}-${.PVC.name}"
onDelete: delete # PVC删除策略[Step2] 根据YAML清单向Kubernetes集群声明式地创建StorageClass动态供应卷。
root@k8s-master:~# kubectl create -f storageclass.yml[Step3] 验证:查看当前集群中的所有StorageClass动态供应卷资源。
root@k8s-master:~# kubectl get storageclasses.storage.k8s.io
3. 创建PVC自动生成PV
[Step1] 本地新建YAML清单,定义PVC持久化存储申请。
root@k8s-master:~# vim nfs-pvc.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: PersistentVolumeClaim # 资源类型
metadata:
name: nfs-pvc
spec:
# 和StorageClass中的name对应
storageClassName: nfs-client
accessModes: # 匹配的卷访问模式,需要与PV匹配
- ReadWriteMany # 匹配访问模式为ReadWriteMany的PV
resources: # 存储资源申请配额
requests: # 指定PV容量,如果不存在满足该容量需求的PV,则PVC无法绑定任何PV
storage: 5G # 申请的存储空间[Step2] 根据YAML清单向Kubernetes集群声明式地创建PVC持久化存储申请。
root@k8s-master:~# kubectl create -f nfs-pvc.yml[Step3] 验证:查看PVC状态,可以看到状态变更为“Pending”。这是因为我们在StorageClass中使用的是“WaitForFirstConsumer”,需要创建一个Pod关联PVC后,才会触发provisioner去NFS创建目录、生成PV、绑定PV,状态才会变更为“Bound”。
root@k8s-master:~# kubectl get pvc
4. 创建Pod关联PVC
[Step1] 本地新建YAML清单,定义PVC持久化存储申请。
root@k8s-master:~# vim nfs-pod.yml
# 写入下列内容
apiVersion: v1 # 固定配置
kind: Pod # 资源类型
metadata:
name: mypvc-pod
spec:
containers:
- name: mypvc-kylin-pod
image: kylin-server-10-sp3b23-x86_64-20230324:b23
imagePullPolicy: IfNotPresent
args: # 更改容器默认启动命令,自定义运行指令
- /bin/sh
- -c
- sleep 10000
volumeMounts: # 存储卷挂载配置
- name: kylin-pvc # Volume卷名称
mountPath: "/data" # 容器内挂载目录
volumes: # 定义存储卷
# 自定义存储卷名称,与[containers.volumeMounts.name]对应
- name: kylin-pvc
persistentVolumeClaim: # 绑定持久化存储申请PVC
claimName: nfs-pvc # 绑定名为nfs-pvc的PVC存储申请[Step2] 根据YAML清单向Kubernetes集群声明式地创建Pod资源。
root@k8s-master:~# kubectl create -f nfs-pod.yml[Step3] 验证:查看当前集群中的所有的Pod资源。
root@k8s-master:~# kubectl get pods
[Step4] 验证:查看当前集群中的PV,可以看到PVC自动生成一条PV,状态为“Bound”。
root@k8s-master:~# kubectl get pv
[Step5] 验证:查看PVC状态,可以看到成功绑定了一个PV,与「Step4」中查询到的PV名称一致。
root@k8s-master:~# kubectl get pvc
[Step6] 验证:登录到NFS服务器,同样可以在共享目录下看到自动生成的目录。目录的命名参照定义StorageClass资源时我们定义的“pathPattern”字段,格式为「命名空间+PVC」名称。
[root@rocky9 ~]# ll /data/nfs-share/
5. 数据读写测试
[Step1] 登录到mypvc-pod,查看/data目录的挂载来源。可以看到NFS服务器IP地址与共享目录,代表PVC已成功挂载到Pod。
root@k8s-master:~# kubectl exec -it mypvc-pod -- /bin/bash
[root@mypvc-pod /]# df -h /data
[Step2] 生成11G大容量文件,写入过程无报错且文件正常创建。
[root@mypvc-pod /]# dd if=/dev/zero of=/tmp/big bs=1G count=11
[root@mypvc-pod /]# ls -lh /tmp/big
[root@mypvc-pod /]# exit
