目录
[k8s持久化存储: PVC](#k8s持久化存储: PVC)
[1 k8s PV是什么?](#1 k8s PV是什么?)
[2 k8s PVC是什么?](#2 k8s PVC是什么?)
[3 k8s PVC和PV工作原理](#3 k8s PVC和PV工作原理)
[4 创建pod,使用pvc作为持久化存储卷](#4 创建pod,使用pvc作为持久化存储卷)
查看pv和pvc,STATUS是Bound,表示这个pv已经被pvc绑定了
[删除pod-pvc 的这个pod,发现pvc还是存在的](#删除pod-pvc 的这个pod,发现pvc还是存在的)
k8s持久化存储: PVC
1 k8s PV是什么?
PersistentVolume(PV)是群集中的一块存储,由管理员配置或使用存储类动态配置。 它是集群中的资源,就像pod是k8s集群资源一样。 PV是容量插件,如Volumes,其生命周期独立于使用PV的任何单个pod。
2 k8s PVC是什么?
PersistentVolumeClaim(PVC)是用户使用存储的请求。 它类似于pod。Pod消耗节点资源,PVC消耗存储资源。 pod可以请求特定级别的资源(CPU和内存)。 pvc在申请pv的时候也可以请求特定的大小和访问模式(例如,可以一次读写或多次只读)。
3 k8s PVC和PV工作原理
PV是群集中的资源。 PVC是对这些资源的请求。
PV和PVC之间的相互作用遵循以下生命周期:
(1)pv的供应方式
可以通过两种方式配置PV:静态或动态。
静态的:
集群管理员创建了许多PV。它们包含可供群集用户使用的实际存储的详细信息。它们存在于Kubernetes API中,可供使用。
动态的:
当管理员创建的静态PV都不匹配用户的PersistentVolumeClaim时,群集可能会尝试为PVC专门动态配置卷。此配置基于StorageClasses,PVC必须请求存储类,管理员必须创建并配置该类,以便进行动态配置。
(2)绑定
用户创建pvc并指定需要的资源和访问模式。在找到可用pv之前,pvc会保持未绑定状态
(3)使用
-
需要找一个存储服务器,把它划分成多个存储空间;
-
k8s管理员可以把这些存储空间定义成多个pv;
-
在pod中使用pvc类型的存储卷之前需要先创建pvc,通过定义需要使用的pv的大小和对应的访问模式,找到合适的pv;
-
pvc被创建之后,就可以当成存储卷来使用了,我们在定义pod时就可以使用这个pvc的存储卷;
-
pvc和pv它们是一一对应的关系,pv如果被pvc绑定了,就不能被其他pvc使用了;
-
我们在创建pvc的时候,应该确保和底下的pv能绑定,如果没有合适的pv,那么pvc就会处于pending状态。
(4)回收策略
当我们创建pod时如果使用pvc做为存储卷,那么它会和pv绑定,当删除pod,pvc和pv绑定就会解除,解除之后和pvc绑定的pv卷里的数据需要怎么处理,目前,卷可以保留、回收或删除:
1、Retain #保留
当删除pvc的时候,pv仍然存在,处于released状态,但是它不能被其他pvc绑定使用,里面的数据还是存在的,当我们下次再使用的时候,数据还是存在的,这个是默认的回收策略。
2、Delete #删除
删除pvc时即会从Kubernetes中移除PV,也会从相关的外部设施中删除存储资产。
4 创建pod,使用pvc作为持久化存储卷

三种回收策略详解
策略 | 行为 | 适用场景 | 数据安全性 |
---|---|---|---|
Retain | PVC删除后,PV进入Released 状态,保留数据需手动清理 |
生产环境(数据库/关键数据) | ⭐⭐⭐⭐⭐ |
Delete | PVC删除后,自动删除PV及后端存储(如云磁盘/EBS) | 临时测试环境 | ⭐⭐ |
Recycle | 数据擦除后PV恢复为Available (K8s 1.15+已废弃) |
旧版本兼容 | ⭐ |
1、创建nfs共享目录
cpp
[root@k8s-master pvc]#
[root@k8s-master pvc]# cd /data
[root@k8s-master data]# ls
index.html
#在宿主机创建NFS需要的共享目录
[root@k8s-master data]# mkdir /data/v{1..10} -p
[root@k8s-master data]# ls
index.html v1 v10 v2 v3 v4 v5 v6 v7 v8 v9
#配置nfs共享宿主机上的/data/v1..v10目录
[root@k8s-master data]# vim /etc/exports
/data 192.168.158.0/24(rw,no_root_squash)
/data/v1 192.168.158.0/24(rw,no_root_squash)
/data/v2 192.168.158.0/24(rw,no_root_squash)
/data/v3 192.168.158.0/24(rw,no_root_squash)
/data/v4 192.168.158.0/24(rw,no_root_squash)
/data/v5 192.168.158.0/24(rw,no_root_squash)
/data/v6 192.168.158.0/24(rw,no_root_squash)
/data/v7 192.168.158.0/24(rw,no_root_squash)
/data/v8 192.168.158.0/24(rw,no_root_squash)
/data/v9 192.168.158.0/24(rw,no_root_squash)
/data/v10 192.168.158.0/24(rw,no_root_squash)
#重新加载配置,使配置成效
[root@k8s-master data]# exportfs -arv
exporting 192.168.158.0/24:/data/v10
exporting 192.168.158.0/24:/data/v9
exporting 192.168.158.0/24:/data/v8
exporting 192.168.158.0/24:/data/v7
exporting 192.168.158.0/24:/data/v6
exporting 192.168.158.0/24:/data/v5
exporting 192.168.158.0/24:/data/v4
exporting 192.168.158.0/24:/data/v3
exporting 192.168.158.0/24:/data/v2
exporting 192.168.158.0/24:/data/v1
exporting 192.168.158.0/24:/data

2、如何编写pv的资源清单文件
cpp
#查看定义pv需要的字段
[root@k8s-master ~]# kubectl explain pv
KIND: PersistentVolume
VERSION: v1
DESCRIPTION:
PersistentVolume (PV) is a storage resource provisioned by an
administrator. It is analogous to a node. More info:
[https://kubernetes.io/docs/concepts/storage/persistent-volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes)
FIELDS:
apiVersion <string>s
kind<string>
metadata<Object>
spec<Object>
#查看定义nfs类型的pv需要的字段
[root@k8s-master] ~]# kubectl explain pv.spec.nfs
KIND: PersistentVolume
VERSION: v1
RESOURCE: nfs <Object>
FIELDS:
path<string> -required-
readOnly<boolean>
server <string> -required-
3、创建pv
cpp
[root@k8s-master pvc]# vim pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: v1
spec:
capacity:
storage: 1Gi #pv的存储空间容量 #这两个必要条件
accessModes: ["ReadWriteOnce"] #访问模式:多节点读写
nfs:
path: /data/v1 #把nfs的存储空间创建成pv
server: 192.168.158.33 #nfs服务器的地址
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v2
spec:
capacity:
storage: 2Gi
accessModes: ["ReadWriteMany"]
nfs:
path: /data/v2
server: 192.168.158.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v3
spec:
capacity:
storage: 3Gi
accessModes: ["ReadOnlyMany"]
nfs:
path: /data/v3
server: 192.168.158.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v4
spec:
capacity:
storage: 4Gi
accessModes: ["ReadWriteOnce","ReadWriteMany"]
nfs:
path: /data/v4
server: 192.168.158.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v5
spec:
capacity:
storage: 5Gi
accessModes: ["ReadWriteOnce","ReadWriteMany"]
nfs:
path: /data/v5
server: 192.168.158.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v6
spec:
capacity:
storage: 6Gi
accessModes: ["ReadWriteOnce","ReadWriteMany"]
nfs:
path: /data/v6
server: 192.168.158.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v7
spec:
capacity:
storage: 7Gi
accessModes: ["ReadWriteOnce","ReadWriteMany"]
nfs:
path: /data/v7
server: 192.168.158.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v8
spec:
capacity:
storage: 8Gi
accessModes: ["ReadWriteOnce","ReadWriteMany"]
nfs:
path: /data/v8
server: 192.168.158.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v9
spec:
capacity:
storage: 9Gi
accessModes: ["ReadWriteOnce","ReadWriteMany"]
nfs:
path: /data/v9
server: 192.168.158.33
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: v10
spec:
capacity:
storage: 10Gi
accessModes: ["ReadWriteOnce","ReadWriteMany"]
nfs:
path: /data/v10
server: 192.168.158.33
更新资源清单文件
cpp
[root@k8s-master pvc]# kubectl apply -f pv.yaml
persistentvolume/v1 created
persistentvolume/v2 created
persistentvolume/v3 created
persistentvolume/v4 created
persistentvolume/v5 created
persistentvolume/v6 created
persistentvolume/v7 created
persistentvolume/v8 created
persistentvolume/v9 created
persistentvolume/v10 created
查看pv资源
cpp
[root@k8s-master pvc]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
v1 1Gi RWO Retain Available 32s
v10 10Gi RWO,RWX Retain Available 32s
v2 2Gi RWX Retain Available 32s
v3 3Gi ROX Retain Available 32s
v4 4Gi RWO,RWX Retain Available 32s
v5 5Gi RWO,RWX Retain Available 32s
v6 6Gi RWO,RWX Retain Available 32s
v7 7Gi RWO,RWX Retain Available 32s
v8 8Gi RWO,RWX Retain Available 32s
v9 9Gi RWO,RWX Retain Available 32s
#这时还没有创建pvc
[root@k8s-master pvc]# kubectl get pvc
No resources found in default namespace.
#ROW是一次性读写,RWX是多次读写,ROX是多次只读,RWO是未知读写
#STATUS是Available,表示pv是可用的
NAME(名称)
通常用于标识某个特定的对象,在这里可能是指存储相关的实体(比如存储卷等)的具体名字,方便对其进行区分和引用。
CAPACITY(容量)
代表该对象所具备的存储容量大小,一般会以特定的存储单位(如字节、KB、MB、GB、TB 等)来衡量,表示其能够容纳的数据量多少。
ACCESS MODES(访问模式)
指的是允许对相应存储资源进行访问的方式,例如可以是只读、读写、可追加等不同模式,决定了用户或系统对其存储内容操作的权限范围。
RECLAIM POLICY(回收策略)#Retain保留
关乎当存储资源不再被使用或者释放时,对其所占用空间等资源的处理方式,常见的策略比如立即回收、延迟回收、按特定条件回收等,确保资源能合理地被再次利用。
STATUS(状态)
描述该存储相关对象当前所处的情况,例如可能是可用、不可用、正在初始化、已损坏等不同状态,便于了解其是否能正常工作。
CLAIM(声明)#pvc
在存储语境中,往往涉及对存储资源的一种请求或者占用声明,表明某个主体对相应存储资源有着相关权益或者正在使用它等情况。
STORAGECLASS(存储类别)
用于区分不同特性的存储分类,比如可以根据存储的性能(高速、低速)、存储介质(磁盘、磁带等)、存储成本(昂贵、廉价)等因素划分出不同的存储类,以满足不同场景的需求。
VOLUMEATTRIBUTESCLASS(卷属性类别)
主要是针对存储卷这一特定存储对象而言,涵盖了该卷在诸如容量属性、性能属性、安全属性等多方面的类别划分,体现其具备的各类特性。
REASON(原因)
如果存储对象处于某种特定状态(比如异常状态等),此处用于说明造成该状态的具体缘由,方便排查问题、分析情况。
AGE(时长)
一般是指从该存储对象创建开始到当前所经历的时间长度,可用于衡量其存在的时间阶段,辅助判断其使用情况等。
4、创建pvc,和符合条件的pv绑定
cpp
[root@k8s-master pvc]# vim pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc1
spec:
accessModes: ["ReadWriteMany"]
resources:
requests:
storage: 1Gi
#你也可以创建多个pvc
翻译:
cpp
apiVersion: v1 # Kubernetes API 版本(核心API组)
kind: PersistentVolumeClaim # 资源类型:持久化存储声明
metadata:
name: my-pvc # PVC名称(自定义标识)
spec:
accessModes: ["ReadWriteMany"] # 访问模式:多节点读写
resources:
requests:
storage: 2Gi # 申请存储空间大小:2GB
更新资源清单文件
cpp
[root@k8s-master pvc]# kubectl apply -f pvc.yaml
persistentvolumeclaim/my-pvc created
persistentvolumeclaim/my-pvc1 created
查看pv和pvc,STATUS是Bound,表示这个pv已经被pvc绑定了
cpp
#下面显示为什么绑定的是v2和v4呢,那是因为v1和v3不符合条件,所以按照顺序v2被my-pvc占用,v4被my-pvc占用
[root@k8s-master pvc]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
my-pvc Bound v2 2Gi RWX 34s
my-pvc1 Bound v4 4Gi RWO,RWX 34s
[root@k8s-master pvc]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
v1 1Gi RWO Retain Available 4m4s
v10 10Gi RWO,RWX Retain Available 4m4s
v2 2Gi RWX Retain Bound default/my-pvc 4m4s
v3 3Gi ROX Retain Available 4m4s
v4 4Gi RWO,RWX Retain Bound default/my-pvc1 4m4s
v5 5Gi RWO,RWX Retain Available 4m4s
v6 6Gi RWO,RWX Retain Available 4m4s
v7 7Gi RWO,RWX Retain Available 4m4s
v8 8Gi RWO,RWX Retain Available 4m4s
v9 9Gi RWO,RWX Retain Available 4m4s
[root@k8s-master pvc]#
5、创建pod,挂载pvc
注意:pvc和pv是一对一的关系,pvc和pod可以是一对一,也可以是一对多的关系
这里我们演示pvc和pod一对一的关系
cpp
[root@k8s-master pvc]# kubectl apply -f pod-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-pvc
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nginx-html #这个要
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-html #和这个要一样
persistentVolumeClaim:
claimName: my-pvc #pvc名
更新资源清单文件
cpp
[root@k8s-master pvc]# kubectl apply -f pod-pvc.yaml
pod/pod-pvc created
查看pod状态
cpp
[root@k8s-master pvc]# kubectl get pod pod-pvc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-pvc 1/1 Running 0 17s 10.244.169.181 k8s-node2 <none> <none>
#通过上面可以看到pod处于Running状态,正常运行
测试
cpp
[root@k8s-master pvc]# curl 10.244.169.181
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.29.1</center>
</body>
</html>
####在nfs服务器端写入index.html
#因为创建的pod是绑定在my-pvc上的,而my-pvc对应的是v2存储卷
#所以这里我们就往共享目录/data/v2目录中写入
[root@k8s-master pvc]# echo pvc > /data/v2/index.html
[root@k8s-master pvc]# curl 10.244.169.181
pvc
创建另一个pod测试
cpp
[root@k8s-master pvc]# vim pod-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-pvc1
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nginx-html #这个要
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-html #和这个要一样
persistentVolumeClaim:
claimName: my-pvc #pvc名
[root@k8s-master pvc]# kubectl apply -f pod-pvc.yaml
pod/pod-pvc1 created
[root@k8s-master pvc]# kubectl get pod -o wide | grep pod
pod-pvc 1/1 Running 0 7m48s 10.244.169.181 k8s-node2 <none> <none>
pod-pvc1 1/1 Running 0 29s 10.244.36.95 k8s-node1 <none> <none>
#访问pod-pvc1的虚拟ip,返回pvc,证明多个pod可共享同一个pvc,实现目录共享
[root@k8s-master pvc]# curl 10.244.36.95
pvc
删除pod-pvc 的这个pod,发现pvc还是存在的
cpp
[root@k8s-master pvc]# vim pod-pvc.yaml
[root@k8s-master pvc]# kubectl delete pod pod-pvc
pod "pod-pvc" deleted
[root@k8s-master pvc]# kubectl delete pod pod-pvc1
pod "pod-pvc1" deleted
[root@k8s-master pvc]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
my-pvc Bound v2 2Gi RWX 24m
my-pvc1 Bound v4 4Gi RWO,RWX 24m
[root@k8s-master pvc]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
v1 1Gi RWO Retain Available 25m
v10 10Gi RWO,RWX Retain Available 25m
v2 2Gi RWX Retain Bound default/my-pvc 25m
v3 3Gi ROX Retain Available 25m
v4 4Gi RWO,RWX Retain Bound default/my-pvc1 25m
v5 5Gi RWO,RWX Retain Available 25m
v6 6Gi RWO,RWX Retain Available 25m
v7 7Gi RWO,RWX Retain Available 25m
v8 8Gi RWO,RWX Retain Available 25m
v9 9Gi RWO,RWX Retain Available 25m
删除pvc
pv仍然存在,处于released状态,但是它不能被其他pvc绑定使用,里面的数据还是存在的,当我们下次再使用的时候,数据还是存在的,这个是默认的回收策略。
cpp
[root@k8s-master pvc]# kubectl delete pvc my-pvc
persistentvolumeclaim "my-pvc" deleted
[root@k8s-master pvc]# kubectl delete pvc my-pvc1
persistentvolumeclaim "my-pvc1" deleted
[root@k8s-master pvc]# kubectl get pvc
No resources found in default namespace.
#发现pv的状态发生了变化
[root@k8s-master pvc]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
v1 1Gi RWO Retain Available 27m
v10 10Gi RWO,RWX Retain Available 27m
v2 2Gi RWX Retain Released default/my-pvc 27m
v3 3Gi ROX Retain Available 27m
v4 4Gi RWO,RWX Retain Released default/my-pvc1 27m
v5 5Gi RWO,RWX Retain Available 27m
v6 6Gi RWO,RWX Retain Available 27m
v7 7Gi RWO,RWX Retain Available 27m
v8 8Gi RWO,RWX Retain Available 27m
v9 9Gi RWO,RWX Retain Available 27m
此时我们进入到nfs的共享目录,发现我们建立的index.html还是存在的
cpp
[root@k8s-master ~]# cd /data/v2
[root@k8s-master v2]# ls
index.html
如果想要彻底删除数据
cpp
[root@k8s-master pvc]# kubectl delete -f pv.yaml
persistentvolume "v1" deleted
persistentvolume "v2" deleted
persistentvolume "v3" deleted
persistentvolume "v4" deleted
persistentvolume "v5" deleted
persistentvolume "v6" deleted
persistentvolume "v7" deleted
persistentvolume "v8" deleted
persistentvolume "v9" deleted
persistentvolume "v10" deleted
[root@k8s-master pvc]# kubectl get pv
No resources found
[root@k8s-master pvc]# kubectl apply -f pv.yaml
persistentvolume/v1 created
persistentvolume/v2 created
persistentvolume/v3 created
persistentvolume/v4 created
persistentvolume/v5 created
persistentvolume/v6 created
persistentvolume/v7 created
persistentvolume/v8 created
persistentvolume/v9 created
persistentvolume/v10 created
[root@k8s-master pvc]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
v1 1Gi RWO Retain Available 3s
v10 10Gi RWO,RWX Retain Available 3s
v2 2Gi RWX Retain Available 3s
v3 3Gi ROX Retain Available 3s
v4 4Gi RWO,RWX Retain Available 3s
v5 5Gi RWO,RWX Retain Available 3s
v6 6Gi RWO,RWX Retain Available 3s
v7 7Gi RWO,RWX Retain Available 3s
v8 8Gi RWO,RWX Retain Available 3s
v9 9Gi RWO,RWX Retain Available 3s
[root@k8s-master pvc]# kubectl get pvc
No resources found in default namespace.
删除pv
kubectl delete pv pv_name,删除pv,不会删除pv里的数据
注:使用pvc和pv的注意事项
1、我们每次创建pvc的时候,需要事先有划分好的pv,这样可能不方便,那么可以在创建pvc的时候直接动态创建一个pv这个存储类,pv事先是不存在的
2、pvc和pv绑定,如果使用默认的回收策略retain,那么删除pvc之后,pv会处于released状态,我们想要继续使用这个pv,需要手动删除pv,kubectl delete pv pv_name,删除pv,不会删除pv里的数据,当我们重新创建pvc时还会和这个最匹配的pv绑定,数据还是原来数据,不会丢失。