Persistent Volumes
- https://kuboard.cn/learning/k8s-intermediate/persistent/pv.html
- https://kubernetes.io/docs/concepts/storage/persistent-volumes/
1. 概述⚓
与管理计算资源相比,管理存储资源是一个完全不同的问题。为了更好的管理存储,Kubernetes 引入了 PersistentVolume 和 PersistentVolumeClaim 两个新的 API 资源,将存储管理抽象成两个关注点:
- 如何提供存储
- 如何使用存储
PersistentVolume(PV,持久卷)是集群中的一块存储空间,由集群管理员管理、或者由 Storage Classes(存储类)自动管理。PV 和 node 一样,是集群中的资源(kubernetes 集群由存储资源和计算资源组成)。PVs 就像 Volumes 一样是 volume 的插件,但是有自己的生命周期,并且独立于任何使用它的 Pod。这个 API 对象描述了如何提供存储的细节信息(NFS、cephfs等存储的具体参数)。
PersistentVolumeClaim(PVC,持久卷声明)代表用户使用存储的请求。它与 Pod 类似,Pods 消耗 node 计算资源,PVCs 消耗 PV 存储资源。声明可以请求特定的大小和访问模式(例如,它们可以被挂载一次读/写或多次只读)。
根据应用程序的特点不同,其所需要的存储资源也存在不同的要求,例如读写性能等。集群管理员必须能够提供关于 PersistentVolume 的更多选择,无需用户关心存储卷背后的实现细节。为了这些需求,Kubernetes 引入了 StorageClass(存储类)资源。
2. 卷和声明的生命周期⚓
2.1 提供方式⚓
2.1.1 Static⚓
集群管理员创建许多 PV 。它们提供了可供集群中应用程序使用的关于实际存储的具体信息。它们存在于 Kubernetes API 中,可供使用。
2.1.2 Dynamic⚓
当管理员创建的所有静态PV均与用户的 PersistentVolumeClaim 不匹配时,群集可能会尝试动态地为 PVC 专门配置一个卷。PVC 必须请求一个 StorageClass,并且管理员必须已经创建并配置了该类,才能进行动态预配置。
2.2 Binding⚓
假设用户创建了一个 PersistentVolumeClaim 存储卷声明,并指定了需求的存储空间大小以及访问模式。Kubernets master 将立刻为其匹配一个 PersistentVolume 存储卷,并将存储卷声明和存储卷绑定到一起。主控制器中的一个控制循环监视新的 PVCs,若找到一个匹配的 PV (如果可能的话) ,就将它们绑定在一起。如果一个 PV 被动态地提供给一个新的 PVC,那么循环将始终将 PV 绑定到 PVC。否则,用户将总是至少得到他们所要求的容量,但是容量可能超过所要求的内容。一旦绑定,PersistentVolumeClaim 将拒绝其他 PersistentVolume 的绑定关系。PVC 与 PV 之间的绑定关系是一对一的映射。
如果不存在匹配的 PV,PVC 将无限期保持未绑定。
2.3 Using⚓
Pods 使用 PVC 作为 volumes。在 Pod yaml 中的 volumes
部分导入 persistentVolumeClaim
部分即可。详见下文。
2.4 使用中的存储对象保护⚓
Storage Object in Use Protection 是为了确保正在被 Pod 使用的 PVCs 和 绑定到 PVCs 的 PVs 不会被删除,以避免可能的数据丢失。
若用户删除了正在被 Pod 使用的 PVC,PVC 不会被立即移除。只有在任何 Pod 都不再使用该 PVC 时,它才会被移除。同理,管理员删除 PV 时,PV 也会在不再绑定到 PVC 时再被移除。
2.5 回收(Reclaiming)⚓
当用户使用完 volume,他们可以从 API 删除 PVC 对象,允许资源的回收。在 PV 被声明它已经被释放时,PV 的回收策略会告知集群下一步的做法。
2.5.1 保留⚓
Retain
回收策略允许手动回收资源。PVC 被删除时,PV 仍然存在,并且 volume 被认为 "released"。但是由于原先的数据还在上面,所以对于其他 PVC 来说还是不可用的。管理员可以按照下面的步骤回收 volume:
- 删除 PV。其数据仍然存在于对应的外部存储介质中(nfs、cefpfs、glusterfs 等)
- 手工删除对应存储介质上的数据
- 手工删除对应的存储介质,您也可以创建一个新的 PersistentVolume 并再次使用该存储介质
2.5.2 删除⚓
Delete
将从 kubernete 集群移除 PersistentVolume 以及其关联的外部存储介质。
2.5.3 回收⚓
如果受底层 volume 插件支持, Recycle
回收策略将对卷执行基本清理(rm-rf/thevolume/*
),并使其再次可用于新申请。
Warning
不推荐使用 Recycle
策略,建议使用动态配置,即 storageclass。
2.6 扩展 PVCs⚓
你可以扩展以下类型的 volume:
- gcePersistentDisk
- awsElasticBlockStore
- Cinder
- glusterfs
- rbd
- Azure File
- Azure Disk
- Portworx
- FlexVolumes
- CSI
要使用此功能,需要在 storage class 中设置 allowVolumeExpansion
字段。例:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gluster-vol-default
provisioner: kubernetes.io/glusterfs
parameters:
resturl: "http://192.168.10.100:8080"
restuser: ""
secretNamespace: ""
secretName: ""
# 在这里设置支持扩展
allowVolumeExpansion: true
要为 PVC 请求更大的 volume ,请编辑 PVC 对象并指定更大的体积。永远不会创建新的 PersistentVolume 来满足声明,而是调整现有卷的大小。
2.6.1 调整包含文件系统的 volume 的大小⚓
如果文件系统是 XFS、 Ext3 或 Ext4,则只能调整包含文件系统的卷的大小。
当卷包含文件系统时,只有当新 Pod 在 ReadWrite 模式下使用 PersistentVolumeClaim 时,才会调整文件系统的大小。 文件系统扩展可以在 Pod 启动时进行,也可以在 Pod 运行且底层文件系统支持在线扩展时进行。
如果驱动程序将 RequiresFSResize 功能设置为 true,那么 FlexVolume 允许调整大小。 FlexVolume 可以在 Pod 重新启动时调整大小。
2.6.2 调整正在使用的 PVC 大小⚓
在这种情况下,您不需要删除并重新创建使用现有 PVC 的 Pod 或部署。 文件系统扩展后,所有使用中的PVC都将自动供其 Pod 使用。 此功能对 Pod 或 deployment 中未使用的 PVC 无效。 您必须创建一个使用 PVC 的 Pod,然后才能完成扩展。
类似于其他卷类型——在使用的 Pod 时 FlexVolume 卷也可以扩展。
Note
只有当底层驱动程序支持调整大小时,FlexVolume 才可能调整大小。
3. PV 类型⚓
Persistentvolume 类型以插件的形式实现。k8s 当前支持以下插件:
- GCEPersistentDisk
- AWSElasticBlockStore
- AzureFile
- AzureDisk
- CSI
- FC (Fibre Channel)
- FlexVolume
- Flocker
- NFS
- iSCSI
- RBD (Ceph Block Device)
- CephFS
- Cinder (OpenStack block storage)
- Glusterfs
- VsphereVolume
- Quobyte Volumes
- HostPath (Single node testing only -- local storage is not supported in any way and WILL NOT WORK in a multi-node cluster)
- Portworx Volumes
- ScaleIO Volumes
- StorageOS
4. PVs⚓
PV 的名字符合 DNS 子域名
命令规则。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv0003
spec:
capacity:
storage: 5Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
storageClassName: slow
mountOptions:
- hard
- nfsvers=4.1
nfs:
path: /tmp
server: 172.17.0.2
Note
在群集中使用 PersistentVolume 可能需要与卷类型有关的帮助程序。在本例中就需要 /sbin/mount.nfs
。
字段名称 | 可选项/备注 |
---|---|
容量 Capacity | 通常,一个 PersistentVolume 具有一个固定的存储容量(capacity) |
Volume Mode | Kubernetes 1.9 之前的版本,所有的存储卷都被初始化一个文件系统。当前可选项有: Block:使用一个 块设备(raw block device); Filesystem(默认值):使用一个文件系统 |
Access Modes | 可被单节点读写(ReadWriteOnce ); 可被多节点只读(ReadOnlyMany); 可被多节点读写(ReadWriteMany) |
存储类 StorageClassName | 带有存储类 StorageClassName 属性的 PersistentVolume 只能绑定到请求该 StorageClass 存储类的 PersistentVolumeClaim。 没有 StorageClassName 属性的 PersistentVolume 只能绑定到无特定 StorageClass 存储类要求的 PVC。 |
回收策略 Reclaim Policy | 保留(Retain) – 手工回收; 再利用(Recycle)– 清除后重新可用 (rm -rf /thevolume/*) ; 删除(Delete) – 删除 PV 及存储介质 |
Mount Options | 挂载选项用来在挂载时作为 mount 命令的参数,不会对选项进行验证 |
状态 Phase | Available – 可用的 PV,尚未绑定到 PVC; Bound – 已经绑定到 PVC; Released – PVC 已经被删除,但是资源还未被集群回收; Failed – 自动回收失败 |
Important
一个卷一次只能使用一种访问模式挂载,即使它支持多种访问模式。
并非所有的卷插件都支持所有的访问模式,详情请参考:https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes。
5. PVCs⚓
PVC 的名字符合 DNS 子域名
命令规则。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 8Gi
storageClassName: slow
selector:
matchLabels:
release: "stable"
matchExpressions:
- {key: environment, operator: In, values: [dev]}
字段名称 | 可选项/备注 |
---|---|
存储类 | 只有该 StorageClass 存储类的 PV 才可以绑定到此 PVC |
读写模式 Access Modes | 可被单节点读写(ReadWriteOnce ); 可被多节点只读(ReadOnlyMany); 可被多节点读写(ReadWriteMany) |
Volume Modes | blockfilesystem - default |
总量 | 请求存储空间的大小 |
5.1 Selector⚓
matchLabel 和 matchExpressions 的所有要求都进行与
运算——即必须完全满足才能匹配。
5.2 Class⚓
集群对没有 storageClassName 的 PVC 的处理具体取决于是否打开了 DefaultStorageClass
admission plugin 插件。
- 如果许可插件已打开,管理员可以指定默认的 StorageClass。 所有没有 storageClassName 的 PVC 只能绑定到该默认的PV。指定默认 StorageClass 的方法是将 StorageClass 对象中的注释
storageclass.kubernetes.io/is-default-class
设置为true
。 如果管理员未指定默认值,群集将响应PVC 创建,就像准入插件已关闭一样。 如果指定了多个默认值,准入插件将禁止创建所有PVC。 - 如果准入插件已关闭,则没有默认 StorageClass 的概念。 所有没有 storageClassName 的 PVC 只能绑定到没有 class 的 PV。 在这种情况下,不具有 storageClassName 的 PVC 与将其 storageClassName 设置为
""
的PVC的处理方式相同(即没有 StorageClassName 属性的 PersistentVolume 只能绑定到无特定 StorageClass 存储类要求的 PVC。)。
6. Claims As Volumes⚓
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
Note
因为 PVC 是 namespace 对象,所以只能在一个名称空间中使用“多”模式(ROX,RWX)挂载声明。
7. 编写合适的配置⚓
如果您正在编写在大范围集群上运行的配置模板或示例,并且需要持久存储,建议您使用以下模式:
- 将 PersistentVolumeClaim 对象包含在您的配置包中(与Deployment,ConfigMap等一起)。
- 不要在配置中包含 PersistentVolume 对象,因为实例化配置的用户可能没有创建 PersistentVolume 的权限。
- 在实例化模板时,为用户提供 storage class 名称的选项。
- 如果用户提供了 storage class 名称,则将该值放入
persistentVolumeClaim.storageClassName
- 否则置空
- 如果用户提供了 storage class 名称,则将该值放入
- 在您的工具中,请注意在一段时间之后没有绑定的 PVC,并提示给用户。因为这可能表明集群没有动态存储支持(在这种情况下,用户应该创建一个匹配的 PV)或者集群没有存储系统(在这种情况下,用户不能部署需要求的 PVC 配置)。