PV
概述
PV 的全称是:PersistentVolume(持久化卷),是对底层的共享存储的一种抽象,PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。
Kubernetes支持的PV类型如下。
◎ AWSElasticBlockStore:AWS公有云提供的ElasticBlockStore。
◎ AzureFile:Azure公有云提供的File。
◎ AzureDisk:Azure公有云提供的Disk。
◎ CephFS:一种开源共享存储系统。
◎ FC(Fibre Channel):光纤存储设备。
◎ FlexVolume:一种插件式的存储机制。
◎ Flocker:一种开源共享存储系统。
◎ GCEPersistentDisk:GCE公有云提供的PersistentDisk。
◎ Glusterfs:一种开源共享存储系统。
◎ HostPath:宿主机目录,仅用于单机测试。
◎ iSCSI:iSCSI存储设备。
◎ Local:本地存储设备,从Kubernetes 1.7
版本引入,到1.14
版本时更新为稳定版,目前可以通过指定块(Block)设备提供LocalPV,或通过社区开发的sig-storage-local-static-provisioner插件(https://github.com/kubernetes-sigs/sigstorage-local-static-provisioner)来管理LocalPV的生命周期。
◎ NFS:网络文件系统。
◎ Portworx Volumes:Portworx提供的存储服务。
◎ Quobyte Volumes:Quobyte提供的存储服务。
◎ RBD(Ceph Block Device):Ceph块存储。
◎ ScaleIO Volumes:DellEMC的存储设备。
◎ StorageOS:StorageOS提供的存储服务。
◎ VsphereVolume:VMWare提供的存储系统。
配置参数
存储能力(Capacity)
描述存储设备具备的能力,目前仅支持对存储空间的设置(storage=xx)
存储卷模式(Volume Mode)
Kubernetes从1.13
版本开始引入存储卷类型的设置(volumeMode=xxx),存储卷的模式有两种:Filesystem(文件系统) 和 Block(块设备),默认为 Filesystem。
支持块类型的存储卷有:
AWSElasticBlockStore、AzureDisk、FC、GCEPersistentDisk、iSCSI、Local volume、RBD(Ceph Block Device)、VsphereVolume
访问模式(Access Modes)
设置 PV 的访问模式,描述应用对存储资源的访问权限,现在的访问模式有如下 3 类:
访问模式 | 说明 |
---|---|
- ReadWriteOnce(RWO) :读写权限 |
只能被单个 Node 挂载 |
- ReadWriteOnce(RWO) :读写权限 |
可以被多个 Node 挂载 |
- ReadWriteOnce(RWO) :读写权限 |
可以被多个 Node 挂载 |
某些 PV 可以支持多种访问模式(比如:NFS 可以支持多个应用的读写操作),但是在挂载的时候只能支持一种访问模式,多种访问模式并不能同时生效。
下面的表格展示了不同卷类型所支持的访问模式:
Volume Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
---|---|---|---|
AWSElasticBlockStore | ✔️ | - | - |
AzureFile | ✔️ | ✔️ | ✔️ |
AzureDisk | ✔️ | - | - |
CephFS | ✔️ | ✔️ | ✔️ |
Cinder | ✔️ | - | - |
CSI | 视驱动而定 | 视驱动而定 | 视驱动而定 |
FC | ✔️ | ✔️ | - |
FlexVolume | ✔️ | ✔️ | 视驱动而定 |
Flocker | ✔️ | - | - |
GCEPersistentDisk | ✔️ | ✔️ | - |
Glusterfs | ✔️ | ✔️ | ✔️ |
HostPath | ✔️ | - | - |
iSCSI | ✔️ | ✔️ | - |
Quobyte | ✔️ | ✔️ | ✔️ |
NFS | ✔️ | ✔️ | ✔️ |
RBD | ✔️ | ✔️ | - |
VsphereVolume | ✔️ | - | - |
PortworxVolume | ✔️ | - | ✔️ |
ScaleIO | ✔️ | ✔️ | - |
StorageOS | ✔️ | - | - |
PV 回收策略(persistentVolumeReclaimPolicy)
当前的回收策略有 3 种:
回收策略 | 说明 |
---|---|
Retain(保留) | 保留数据,需要手工处理。回收策略 Retain 使得用户可以手动回收资源。当 PersistentVolumeClaim 对象 被删除时,PersistentVolume 卷仍然存在,对应的数据卷被视为”已释放(released)”。 由于卷上仍然存在这前一申领人的数据,该卷还不能用于其他申领。 管理员可以通过下面的步骤来手动回收该卷:删除 PersistentVolume 对象。与之相关的、位于外部基础设施中的存储资产 (例如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)在 PV 删除之后仍然存在。根据情况,手动清除所关联的存储资产上的数据。手动删除所关联的存储资产;如果你希望重用该存储资产,可以基于存储资产的 定义创建新的 PersistentVolume 卷对象。 |
Recycle(回收空间) | 简单清除文件的操作(执行 rm -rf /thevolume/* 命令)。 |
Delete(删除) | 与 PV 相连的后端存储完成 Volume 的删除操作(比如:AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder 等设备内部的 Volume 清理)。 |
支持对应策略的卷分别有:
- Recycle 策略:NFS、HostPath
- Delete 策略:AWS EBS、GCE PD、Azure Disk 和 OpenStack Cinder
存储类别(storageClassName)
如果需要支持动态存储的话,需要配置这个字段选项,通过storageClassName参数指定一个StorageClass资源对象的名称。具有特定类别的PV只能与请求了该类别的PVC进行绑定。未设定类别的PV则只能与不请求任何类别的PVC进行绑定。挂载参数(mountOptions)
当 PV 挂载到 Node 上时,根据不同卷的特点可以设置额外的挂载参数。
现在支持挂载参数的卷有:AWSElasticBlockStore、AzureDisk、AzureFile、CephFS、Cinder、GCEPersistentDisk、Glusterfs、NFS、Quobyte Volumes、RBD(Ceph Block Device)、StorageOS、VsphereVolume、iSCSI。
由于挂载参数没有验证,所以如果其中的一个参数是无效的,那么挂载就会失败。节点亲和性(nodeAffinity)
使用这个字段可以限制只有符合条件的 Node 才能访问存储卷,而使用这些存储卷的 Pod 也只会被调度到满足条件的 Node 上。
这个参数只能用于 Local 存储卷。对于公有云提供的存储卷(比如:AWS EBS、GCE PD、Azure Disk 等)是公有云自动完成节点亲和性设置,不需要手工设置。
PV生命周期
- Available: 可用状态,表示还没有与 PVC 绑定
- Bound: 已经 PVC 绑定
- Released: 绑定的 PVC 已经删除,资源已经释放,但没有被集群回收
- Failed: 自动资源回收失败
PVC(持久化卷声明)
PVC 是对 PV 的声明使用。PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式
生命周期
Pending
: 等待状态,还没有与 PV 绑定Bound
: 绑定状态,已经与 PV 绑定Lost
: 丢失状态,与 PV 失去了绑定关系
参数设置
accessModes(访问模式)
这个字段,PVC 与 PV 相同,也可以设置访问模式,作用也是描述应用对存储资源的访问权限。
volumeMode(存储卷模式)
这个字段,PVC 与 PV 也是相同的,描述的是希望使用的 PV 存储卷模式,可以配置的模式为文件系统和块设备。
resources(资源请求)
这个字段用于描述对存储资源的请求,目前仅支持设置 requests.storage
,也就是对存储空间的设置。
storageClassName(绑定的 StorageClass 的名称,即:存储类别)
这个字段用于设置后端存储类别(即:绑定 StorageClass),可以减少对后端存储特性详细信息的依赖。分为两种情况:
- 如果设置这个字段为某个 StorageClass,那么只有设置了相同 Class 的 PV 才会被选中,然后与 PVC 绑定。
如果设置这个字段为空
storageClassName=""
,即不设置 Class。这时取决于系统是否启用名为 DefaultStorageClass 的 admission controller:- 没有启动 DefaultStorageClass:将选择没有设定 Class 的 PV 进行匹配和绑定。
- 启用 DefaultStorageClass:管理员定义默认的 StorageClass,系统将使用默认 StorageClass 的后端存储创建一个 PV 并自动与 PVC 绑定。设置的具体方法为:在 StorageClass 的定义中添加一个 annotation “storageclass.kubernetes.io/is-default-class=true”。需要注意的是:只能定义一个默认的 StorageClass。
selector(选择条件)
这个字段可以对系统中已经存在的各种 PV 进行筛选,根据筛选条件选出最符合条件的 PV 进行绑定。这下面包含两个字段:
matchLabels:PV 必须有这个标签值
- matchExpressions:通过键值对和操作符指定标签选择器列表,操作符包括:In、Notln、Exists 和 DoesNotExist
如果两个字段都设置了,就必须满足所有的条件才能完成匹配。
最后需要注意的是:Pod、PV 和 PVC 都必须在同一命名空间下才起作用。
另外,如果使用动态存储管理,即不预先定义 PV,只通过 StorageClass 交给系统自动完成 PV 的动态创建,那么 PVC 设置的 selector 就是无效的。如果用户删除了 PVC,与它绑定的 PV(默认回收策略为 Delete
)也会被删除,可以在绑定成功后手动将 Delete
策略修改为 Retain
。
HelloWorld
pv-hostpath.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-hostpath
labels:
type: local
spec:
capacity:
storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: local-sc
hostPath:
path: /data/k8s/local/hostpath
执行
$ kubectl apply -f pv-hostpath.yaml
persistentvolume/pv-hostpath created
$ kubectl get pv pv-hostpath
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-hostpath 2Gi RWO Recycle Available local-sc 28s
创建 pvc-hostpath.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-hostpath
spec:
storageClassName: local-sc
resources:
requests:
storage: 2Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
执行
$ kubectl apply -f pvc-hostpath.yaml
persistentvolumeclaim/pvc-hostpath created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-hostpath Bound pv-hostpath 2Gi RWO local-sc 93s
创建pv-hostpath-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pv-hostpath-pod
labels:
name: myapp
spec:
nodeSelector:
kubernetes.io/hostname: k8s-node1
volumes:
- name: pvc-hostpath
persistentVolumeClaim:
claimName: pvc-hostpath
containers:
- name: nginx
image: nginx:1.14
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
volumeMounts:
- mountPath: /usr/share/nginx/html
name: pvc-hostpath
在k8s-node1 执行
echo "hello k8s" >> /data/k8s/local/hostpath/index.html
执行
kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pv-hostpath-pod 1/1 Running 0 28s 100.111.156.110 k8s-node1 <none> <none>
在集群内部执行
curl 100.111.156.110
hello k8s