前言
Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足。拿前面示例可以看出,要使用Volume,Pod 必须事先知道如下信息:
- 当前 Volume 来自来哪里及具体位置 Local、网络。
- 存储卷的类型,并知道每种类型卷的配置使用方法,通过 kubectl explain pods.spec.volumes 可以看到kubernetes支持卷的类型非常的多
Pod通常是由应用的开发人员维护,而 Volume 则通常是由存储系统的管理员维护。开发人员要获得上面的信息:要么询问管理员 要么自己就是管理员。
这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境这样的情况还可以接受。但当集群规模变大,特别是对于生成环境,考虑到效率和安全性,这就成了必须要解决的问题。
Kubernetes 给出的解决方案是 PersistentVolume 和 PersistentVolumeClaim。
PersistentVolume (PV) 是外部存储系统中的一块存储空间,由管理员创建和维护。与 Volume 一样,PV 具有持久性,生命周期独立于 Pod。
PersistentVolumeClaim (PVC) 是对 PV 的申请 (Claim)。PVC 通常由普通用户创建和维护。需要为 Pod 分配存储资源时,用户可以创建一个 PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes 会查找并提供满足条件的 PV。
有了 PersistentVolumeClaim,用户只需要告诉 Kubernetes 需要什么样的存储资源,而不必关心真正的空间从哪里分配,如何访问等底层细节信息。这些 Storage Provider 的底层信息交给管理员来处理,只有管理员才应该关心创建 PersistentVolume 的细节信息。
PVC和PV简介
- 是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV 也是集群中的资源。 PV 是Volume 之类的卷插件,但具有独立于使用 PV 的 Pod 的生命周期。此 API 对象包含存储实现的细节,即NFS、iSCSI 或特定于云供应商的存储系统
- PV、PVC:将存储消费,存储创建的职能分离开来,
- PV: Persistent Volume,持久卷,可被PVC绑定;而PV一定要与某个真正的存储空间(一般是网络存储服务上的存储空间)对应起来,才能真正存储数据。由集群管理员负责管理。集群级别资源;将真正的存储设备上的一段存储空间抽象成的k8s的对象
- PVC: Persistent Volume Claim 持久卷申请,简称PVC;k8s上标准的资源类型之一;名称空间级别;由用户定义出存储消费需求,而后根据需求条件与现有各PV进行匹配检测,找出一个最佳的使用。
Pod使用这类存储的步骤:
- Admin: 创建好PV;
- User: 按需创建PVC,而后创建Pod,在Pod调用persistentVolumeClaim 类型的存储卷插件调用同一个名称空间的PVC资源;
PV字段介绍:
除了存储卷插件之外,PersistentVolume资源规范Spec字段主要支持嵌套以下几个通用字段,它们用于定义PV的容量、访问模式和回收策略等属性
- capacity <map[string]string>: 指定PV的容量;目前 Capacity仅支持存储容量设定,将来还应该可以指定IOPS和吞吐量(throughput) 。
- accessModes <[]string>: 指定当前PV支持访问模式;存储系统支持存取能力大体可分为ReadWriteOnce(单路读写)、ReadOnlyWlany(多路只读)和ReadwriteMany(多路读写)三种类型,某个特定的存储系统可能会支持其中的部分或全部的能力。
- persistentVolumeReclaimPolicy <string> ∶PV空间被释放时的处理机制;可用类型仅为Retain(默认)、Recycle(已废弃)或Delete(k8s自动创造默认选择)。目前,仅nfs和hostPath支持Recycle策略,也仅有部分存储系统支持Delete策略。
- volumenode <string>:该PV的卷模型,用于指定此存储卷被格式化为文件系统使用还是直接使用裸格式的块设备;默认值为Filesystem,仅块设备接口的存储系统支持该功能。
- storageClassName <string>:当前PV所属的StorageClass资源的名称,指定的存储类需要事先存在;默认为空值,即不属于任何存储类。
- mountOptions <string>:挂载选项组成的列表,例如ro、soft和hard等。
- nodeAffinity <Object>:节点亲和性,用于限制能够访问该PV的节点,进而会影响到使用与该PV关联的PVC的Pod的调度结果。
PVC字段介绍:
定义PVC时,用户可通过访问模式(accessModes)、数据期(dataSource)、存储资源空间需求和限制(resources)、存储类、标签选择器、卷模型和卷名称等匹配标准来筛选集群上的PV资源,其中,resources和accessModes是最重的筛选标准。PVC的Spec字段的可嵌套字段有如下几个。
- accessModes <[]string>: PVC的访问模式;它同样支持RWO、RWX和ROX三种模式;
- dataSrouces <Object>: 用于从指定的数据源恢复该PVC卷,它目前支持的数据源包括一个现在卷快照对象(snapshot.storage.k8s.io/VolumeSnapshot)、一个既有PVC对象(PersistentVolumeClaim)或一个既有的用于数据转存的自定义资源对象(resource/object) ;
- resources <Object>: 声明使用的存储空间的最小值和最大值;目前,PVC的资源限定仅支持空间大小一个维度;
- selector <Object>: 筛选PV时额外使用的标签选择器(matchLabels)或匹配条件表达式, (matchExpressions) ;
- storageClassName <string>:该PVC资源隶属的存储类资源名称;指定了存储类资源的PVC仅能在同一个存储类下筛选PV资源,否则,就只能从所有不具有存储类的PI中进行筛选;
- volumeMode <string>∶卷模型,用于指定此卷可被用作文件系统还是裸格式的块设备;默认值为Filesystem;
- volumeName <string>: 直接指定要绑定的PV咨源的名称
资源规范:
spec:
volumes :
- name <string> #存储卷名称标识,仅可使用DNS标签格式的字符,在当前Pod中必须唯
vOL_TYPE <0bject> #存储卷插件及具体的目标存储供给方的相关配置
containers:
- name: ...
image: ...
volumeMounts:
- name <string> #要挂载的存储卷的名称,必须匹配存储卷列表中某项的定义
mountPath <string> #容器文件系统上的挂载点路径
readOnly <boolean> #是否挂载为只读模式,默认为“否”
subPath <string> #挂载存储卷上的一个子目录至指定的挂载点
subPathExpr <string> #挂载由指定的模式匹配到的存储卷的文件或目录至挂载点
示例1: NFS网络存储、PV、PVC、POD创建与引用
- 1、创建NFS服务共享目录
[root@nfs ~]# mkdir /data/redis00{1,2,3,4,5}
[root@nfs ~]# chmod -R 1010 /data/
[root@nfs ~]# cat /etc/exports
/data/redis 192.168.4.0/24(rw)
/data/redis001 192.168.4.0/24(rw)
/data/redis002 192.168.4.0/24(rw)
/data/redis003 192.168.4.0/24(rw)
/data/redis004 192.168.4.0/24(rw)
/data/redis005 192.168.4.0/24(rw)
[root@nfs ~]# systemctl restart nfs
[root@k8s-node1 ~]# showmount -e 192.168.4.100
Export list for 192.168.4.100:
/data/redis005 192.168.4.0/24
/data/redis004 192.168.4.0/24
/data/redis003 192.168.4.0/24
/data/redis002 192.168.4.0/24
/data/redis001 192.168.4.0/24
/data/redis 192.168.4.0/24
2、创建3种不同类型的PV 分别为
- 5G多路读写
- 10G多路读
- 1G单路读写
[root@k8s-master storage]# cat pv-nfs-demo001.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo001
spec:
capacity:
storage: 5Gi #容量
volumeMode: Filesystem #文件系统
accessModes:
- ReadWriteMany #多路读写
persistentVolumeReclaimPolicy: Retain #回收策略
mountOptions:
- hard
- nfsvers=4.1
nfs :
path: "/data/redis001"
server: 192.168.4.100 #nfs存储地址与路径
[root@k8s-master storage]# cat pv-nfs-demo002.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo002
spec:
capacity:
storage: 10Gi #容量
volumeMode: Filesystem
accessModes:
- ReadWriteMany #多路读
persistentVolumeReclaimPolicy: Retain
mountOptions:
- hard
- nfsvers=4.1
nfs :
path: "/data/redis002"
server: 192.168.4.100 #nfs存储地址与路径
[root@k8s-master storage]# cat pv-nfs-demo003.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-demo003
spec:
capacity:
storage: 1Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce #单路读写
persistentVolumeReclaimPolicy: Retain
mountOptions:
- hard
- nfsvers=4.1
nfs :
path: "/data/redis002"
server: 192.168.4.100
[root@k8s-master storage]# kubectl apply -f pv-nfs-demo001.yaml -f pv-nfs-demo002.yaml -f pv-nfs-demo003.yaml #创建3个不同属性的PV卷
persistentvolume/pv-nfs-demo001 created
persistentvolume/pv-nfs-demo002 created
persistentvolume/pv-nfs-demo003 created
[root@k8s-master storage]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-demo001 5Gi(容量) RWX(多路读写) Retain(回收策略) Available 33s
pv-nfs-demo002 10Gi RWX Retain Available 33s
pv-nfs-demo003 1Gi RWO(单路读写) Retain Available
3、创建2个不同属性PVC需求
- 3G-10G多路读写
- 2G-5G单路读写
[root@k8s-master storage]# cat pvc-demo-0001.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-demo-0001
namespace: default
spec:
accessModes: ["ReadWriteMany"] #多路读写
volumeMode: Filesystem
resources:
requests:
storage: 3Gi #最小容量
limits:
storage: 10Gi #最大容量
[root@k8s-master storage]# cat pvc-demo-0002.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-demo-0002
spec:
accessModes: ["ReadWriteOnce"] #单路读写
volumeMode: Filesystem
resources:
requests:
storage: 2Gi #要求最小容量 2G-5G之间
limits:
storage: 5Gi #要求最大容量
selector: #使用标签匹配
matchLabels:
usedof : "redisdata"
- PVC根据需要会自动与PV匹配并绑定
[root@k8s-master storage]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-demo-0001 Bound pv-nfs-demo001 5Gi RWX 13h
pvc-demo-0002 Pending 2m40s #没有匹配卷 挂起
[root@k8s-master storage]# kubectl describe pvc pvc-demo-0002
Name: pvc-demo-0002
Namespace: default
StorageClass:
Status: Pending
Volume:
Labels: <none>
Annotations: <none>
Finalizers: [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode: Filesystem
Mounted By: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal FailedBinding 7s (x3 over 34s) persistentvolume-controller no persistent volumes available for this claim and no storage class is set #没有匹配标签的PV挂起
[root@k8s-master storage]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-demo001 5Gi RWX Retain Bound default/pvc-demo-0001 13h
pv-nfs-demo002 10Gi RWX Retain Available 13h
pv-nfs-demo003 1Gi RWO Retain Available 13h
- 4、Pod的创建绑定PVC
[root@k8s-master storage]# cat volumes-pvc-demo.yaml
apiVersion: v1
kind: Pod
metadata:
name: volumes-pvc-demo
namespace: default
spec:
containers:
- name: redis
image: redis:alpine
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 1010
ports:
- containerPort: 6379
name: redisport
volumeMounts:
- mountPath: /data
name: redis-rbd-vol
volumes:
- name: redis-rbd-vol
persistentVolumeClaim:
claimName: pvc-demo-0001 #挂载PVC 指定名称
[root@k8s-master storage]# kubectl apply -f volumes-pvc-demo.yaml
pod/volumes-pvc-demo created
[root@k8s-master storage]# kubectl get pod
NAME READY STATUS RESTARTS AGE
centos-deployment-66d8cd5f8b-fkhft 1/1 Running 0 27h
my-grafana-7d788c5479-8bx6k 1/1 Running 0 4h24m
volumes-nfs-demo 1/1 Running 0 4h25m
volumes-pvc-demo 1/1 Running 0 4s
[root@k8s-master ~]# kubectl get pvc #可以看到PVC绑定已成功
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-demo-0001 Bound pv-nfs-demo001 5Gi RWX 52m
[root@k8s-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
centos-deployment-66d8cd5f8b-fkhft 1/1 Running 0 27h
my-grafana-7d788c5479-8bx6k 1/1 Running 0 5h19m
volumes-hostpath-demo 1/1 Running 0 48m
volumes-nfs-demo 1/1 Running 0 5h20m
volumes-pvc-demo 1/1 Running 0 4m
[root@k8s-master ~]# kubectl exec volumes-pvc-demo -it -- /bin/sh #挂载PVC写入数据
/data $ redis-cli
127.0.0.1:6379> set mykey2 "taobao"
OK
127.0.0.1:6379> get mykey2
"taobao"
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> exit
/data $ ls
dump.rdb
/data $
[root@nfs redis001]# ls /data/redis001/ #nfs服务器上查看数据
dump.rdb
示例2: 通过PVC实现共享数据
这里只是演示不同的Pod可以挂载同一个PVC共享数据,但对于一些有状态的服务,数据的实时读写和服务、存储类型都有关系
[root@k8s-master storage]# cat volumes-pvc2.demo.yaml #新建redis 2
apiVersion: v1
kind: Pod
metadata:
name: volumes-pvc2-demo
namespace: default
spec:
containers:
- name: redis
image: redis:alpine
imagePullPolicy: IfNotPresent
securityContext:
runAsUser: 1010
ports:
- containerPort: 6379
name: redisport
volumeMounts:
- mountPath: /data
name: redis-rbd-vol
volumes:
- name: redis-rbd-vol
persistentVolumeClaim:
claimName: pvc-demo-0001 #使用相同的PVC
[root@k8s-master storage]# kubectl exec volumes-pvc2-demo -it -- /bin/sh #在别一个Pod上查看数据
/data $ redis-cli
127.0.0.1:6379> get mykey
"baidu.com"
127.0.0.1:6379> exit
/data $ exit
示例3: 删除Pod、PVC、PV后恢复数据
- 所有数据的恢复都需要回收策略为Retain的情况下
- 删除Pod及PVC
[root@k8s-master storage]# kubectl delete pod volumes-pvc-demo
pod "volumes-pvc-demo" deleted
[root@k8s-master storage]# kubectl delete pod volumes-pvc2-demo #删除之前两个Pod
pod "volumes-pvc2-demo" deleted
[root@k8s-master storage]# kubectl get pvc #删除Pod不影响PVC及数据
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-demo-0001 Bound pv-nfs-demo001 5Gi RWX 14h
pvc-demo-0002 Pending 33m
[root@k8s-master storage]# kubectl delete pvc pvc-demo-0001 #删除PVC
persistentvolumeclaim "pvc-demo-0001" deleted
[root@k8s-master storage]# kubectl get pv #因为回收策略为Retain 所以PV不会自动删除 变为Released状态
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-demo001 5Gi RWX Retain Released default/pvc-demo-0001 14h
pv-nfs-demo002 10Gi RWX Retain Available 14h
pv-nfs-demo003 1Gi RWO Retain Available 14h
[root@k8s-master storage]# kubectl apply -f pvc-demo-0001.yaml #最次创建PVC看是否能绑定原来的PV
persistentvolumeclaim/pvc-demo-0001 created
[root@k8s-master storage]# kubectl get pv #绑定到的新的PV 原来的PV还是为Released状态
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-demo001 5Gi RWX Retain Released default/pvc-demo-0001 14h
pv-nfs-demo002 10Gi RWX Retain Bound default/pvc-demo-0001 14h
pv-nfs-demo003 1Gi RWO Retain Available 14h
[root@k8s-master storage]# kubectl delete -f pvc-demo-0001.yaml #删除Pod
persistentvolumeclaim "pvc-demo-0001" deleted
[root@k8s-master storage]# kubectl get pv #现在两个PV都为Released
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-demo001 5Gi RWX Retain Released default/pvc-demo-0001 14h
pv-nfs-demo002 10Gi RWX Retain Released default/pvc-demo-0001 14h
pv-nfs-demo003 1Gi RWO Retain Available 14h
- 修改PVC 让PVC恢复为Available状态 重新绑定
[root@k8s-master storage]# kubectl edit pv pv-nfs-demo001 #修改PV 让状态变为Available 可以重新绑定
...
spec:
accessModes:
- ReadWriteMany
capacity:
storage: 5Gi
claimRef: #删除claimRef:字段所有内容
apiVersion: v1
kind: PersistentVolumeClaim
name: pvc-demo-0001
namespace: default
resourceVersion: "6371169"
uid: f8a9ba0b-e15e-44ea-bccf-6b40f0d46390
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /data/redis001
server: 192.168.4.100
persistentVolumeReclaimPolicy: Retain
volumeMode: Filesystem
status:
phase: Released
...
[root@k8s-master storage]# kubectl edit pv pv-nfs-demo002 #pv-nfs-demo002也做相同操作
persistentvolume/pv-nfs-demo002 edited
[root@k8s-master storage]# kubectl get pv #恢复Available状态
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-demo001 5Gi RWX Retain Available 14h
pv-nfs-demo002 10Gi RWX Retain Available 14h
pv-nfs-demo003 1Gi RWO Retain Available
14h
[root@k8s-master storage]# kubectl apply -f pvc-demo-0001.yaml #新建PVC
persistentvolumeclaim/pvc-demo-0001 created
[root@k8s-master storage]# kubectl get pv #查看PV 绑定到原来的PV成功
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-demo001 5Gi RWX Retain Bound default/pvc-demo-0001 14h
pv-nfs-demo002 10Gi RWX Retain Available 14h
pv-nfs-demo003 1Gi RWO Retain Available 14h
[root@k8s-master storage]# kubectl apply -f volumes-pvc-demo.yaml #重新创建Pod
pod/volumes-pvc-demo created
[root@k8s-master storage]# kubectl get pod
NAME READY STATUS RESTARTS AGE
centos-deployment-66d8cd5f8b-fkhft 1/1 Running 0 41h
my-grafana-7d788c5479-8bx6k 1/1 Running 0 19h
volumes-hostpath-demo 1/1 Running 0 14h
volumes-nfs-demo 1/1 Running 0 19h
volumes-pvc-demo 1/1 Running 0 3s
[root@k8s-master storage]# kubectl exec volumes-pvc-demo -it -- /bin/sh #查看之前数据
/data $ ls
dump.rdb
/data $ redis-cli
127.0.0.1:6379> get mykey2
"taobao"
127.0.0.1:6379> exit
/data $ exit
[root@k8s-master storage]#
[root@k8s-master storage]# kubectl delete pod volumes-pvc-demo #删除Pod
pod "volumes-pvc-demo" deleted
[root@k8s-master storage]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-demo-0001 Bound pv-nfs-demo001 5Gi RWX 6m34s
pvc-demo-0002 Pending 79m
[root@k8s-master storage]# kubectl delete pvc pvc-demo-0001 #删除PVC
persistentvolumeclaim "pvc-demo-0001" deleted
[root@k8s-master storage]# kubectl delete pv pv-nfs-demo001 #删除PV
persistentvolume "pv-nfs-demo001" deleted
[root@k8s-master storage]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs-demo002 10Gi RWX Retain Available 14h
pv-nfs-demo003 1Gi RWO Retain Available 14h
[root@nfs ~]# ls /data/redis001/ #NFS服务查看数据文件 依然存在
dump.rdb
PVC、PV总结:
- 删除Pod、PVC 在回收策略为Retain情况下,数据不会丢失
- PV的删除数据是否会丢失与存储类型有关,上述测试的NFS不会丢失不代表所有的PV删除都不会丢失,PV删除需谨慎
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。