Kubernetes 中的 PV、PVC 和 StorageClass
PV、PVC 概念
持久卷(PersistentVolume,PV)是集群中的一块存储,可以由管理员事先供应,或者 使用 存储类(Storage Class) 来动态供应。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样,也是使用 卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
持久卷申请(PersistentVolumeClaim,PVC)表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 ;
用户在创建 pod 时使用存储卷只需要关心对应名称空间的 pvc 对象;而对应 pv 是需要集群管理管理员定义;后端存储是专门的存储管理员负责管理;pv 是 k8s 上的一种标准资源,全称叫做 PersistentVolume 翻译成中文就是持久存储卷;它主要作用是把后端存储中的某个逻辑单元,映射为 k8s 上的 pv 资源;pv 是集群级别的资源;任意名称空间都可以直接关联某一个 pv;关联 pv 的过程我们叫做绑定 pv;而对应名称空间关联某一 pv 需要使用 pvc 资源来定义;pvc 全称 PersistentVolumeClaim 的缩写,意思就是持久存储卷申请;
在一个名称空间下创建一个 pvc 就是把对应名称空间同集群上的某一 pv 做绑定;一旦一个名称空间绑定了一个 pv 后,对应的 pv 就会从 available 状态转变成 bond 状态,其他名称空间将不能再使用,只有对应 pv 是 available 状态才能正常的被其他名称空间关联绑定;
简单讲 pvc 和 pv 的关系是一一对应的,一个 pv 只能对应一个 pvc;至于同一名称空间下的多个 pod 是否能够同时使用一个 PVC 取决 pv 是否允许多路读写,对应 pv 是否支持多路读写取决后端存储系统;不同类型的存储系统,对应访问模式也有所不同。访问模式有三种,单路读写(ReadWriteOnce 简称 RWO),多路读写(ReadWriteMany 简称 RWX),多路只读(ReadOnlyMany 简称 ROX);
PV、PVC、和 POD 的关系如下图:
示例
创建 pv 的 yaml 文件
1 | |
创建 PV 资源以及 PV 字段详解
kind
在创建 pv 的配置文件时, kind 字段要指定为 PersistentVolume
spec.capcity
这个字段是对持久性卷的资源和容量的描述;spec.capacity.storage 字段用来描述 pv 的存储用量;
为了序列化,关于存储容量使用 storage 字段来声明,值是使用 i 来结尾,比如 1Gi、150Mi。
spec.volumeMode
spec.volumeMode 字段用来描述对应存储系统提供的存储卷类型接口;该字段有以下这些值:
- Filesystem(文件系统)
- Block(块)
默认是
Filesystem
spec.accessModes
spec.accessModes 代表着这个卷在挂载 pod 上的访问模式,该字段有以下值:
ReadWriteOnce
卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式也允许运行在同一节点上的多个 Pod 访问卷。
ReadOnlyMany
卷可以被多个节点以只读方式挂载。
ReadWriteMany
卷可以被多个节点以读写方式挂载。
ReadWriteOncePod
卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本。
在命令行接口(CLI)中,访问模式也使用以下缩写形式:
- RWO - ReadWriteOnce
- ROX - ReadOnlyMany
- RWX - ReadWriteMany
- RWOP - ReadWriteOncePod
spec.persistentVolumeReclaimPolicy
该字段代表着一个 PV 卷被释放时所出的动作和存储卷回收策略,持久卷回收策略有 3 种:Delete
表示当 pvc 删除以后,对应 pv 也随之删除;
Recycle
表示当 pvc 删除以后,对应 pv 的数据也随之被删除;
Retain
表示当 pvc 被删除以后,pv 原封动,即 pv 也在,对应数据也在
该卷如果是手动创建,那回收策略默认是 Recycle;
如果是动态创建,回收策略则是 Delete
spec.mountOptions
mountOptions 字段用来指定挂载选项,具体请看 kubernetes 官网-持久卷挂载选项
spec.nodeAffinity
每个 PV 卷可以通过设置节点亲和性来定义一些约束,进而限制从哪些节点上可以访问此卷。 使用这些卷的 Pod 只会被调度到节点亲和性规则所选择的节点上执行。 要设置节点亲和性,配置 PV 卷 .spec 中的 nodeAffinity。 持久卷 API 参考关于该字段的更多细节。
spec.storageClassName
此持久卷卷所属的 StorageClass 的名称。空值表示此卷不属于任何 StorageClass。
想要查看更详细的文件字段信息,请查看 kubernetesAPI 文档—PersistentVolumeSpec
PV 的状态
每个卷会处于以下阶段(Phase)之一:Available(可用)
卷是一个空闲资源,尚未绑定到任何申领;
Bound(已绑定)
该卷已经绑定到某申领;
Released(已释放)
所绑定的申领已被删除,但是资源尚未被集群回收;
Failed(失败)
卷的自动回收操作失败。
查看 PV 状态
使用命令 describe 查看 PV 的详细状态
1 | |
从上面信息可以看出,该 PV 的状态为 Available,回收策略是 Retain,访问模式是 RWO,ROX,RWX,卷模式是 Filesystem,容量为 1G,卷类型是 nfs,地址是 10.1.3.205,path 地址是 /nfs/data
创建 PVC 资源
1 | |
kind
在创建 pv 的配置文件时, kind 字段要指定为 PersistentVolumeClaim
spec.accessModes
spec.accessModes 字段是用来指定其 pvc 的访问模式,一般这个模式是被 pv 的 accessModes 包含,也就说 pvc 的访问模式必须是 pv 的子集,即等于小于 pv 的访问模式;
spec.volumeMode
与 PV 资源的配置保持一致
spec.resources
resources 用来描述对应 pvc 的存储空间限制,requests 用来描述对应 pvc 最小容量限制,limits 用来描述最大容量限制;
spec.selector
标签选择器,声明可以指定标签选择器以进一步筛选卷集。只有标签与选择器匹配的卷才能绑定到声明。选择器可以由两个字段组成matchLabels
卷必须具有具有此值的标签
matchExpressions
通过指定键、值列表以及与键和值相关的运算符而制定的要求列表。有效运算符包括 In、NotIn、Exists 和 DOESNOTEXTIST。
所有的需求,从匹配标签和匹配表达式,都是和在一起的——它们必须全部满足才能匹配。
应用该 pvc 配置文件,在查看 pv 和 pvc 的状态
1 | |
从以上信息可以看出,在应用 PVC 配置之后,PV 的状态就由 Available 转变为 Bound,已经被 PVC 所绑定。
创建 Pod 挂载 PVC
创建 Pod 的配置文件
1 | |
pod 在使用 PVC 的时候只需要在 spec.volumes 字段中声明该卷的类型是 PVC,然后填上 PVC 的名字即可;
应用该配置,进入容器内的/nfs/data 目录中写入数据,看 nfs 卷中是否有相对应的数据出现;
1 | |
删除 PV、PVC 和 Pod
在 pod 有挂载 PVC,PVC 又绑定 PV 的情况下,正确的删除顺序是
- 删除 pod
- 删除 PVC
- 删除 PV
如果没有按照这个顺序去删除的话,会出现一些情况:
在没有删除 pod 的情况下,删除 pvc
删除操作会被阻塞,结束操作后在查看 pvc,状态为 Terminating
在没有删除 pod 的情况下,删除 pv
删除操作会被阻塞,状态为 Terminating
正确删除顺序删除 pod、pvc、pv
删除 pod 后,对应的 pvc 状态保持不变;删除对应 pvc 以后,对应 pv 的状态就从 bound 状态转变为 Released 状态,表示等待回收;我们在资源清单中使用的是 Retain 回收策略,pv 和 pvc 都是我们人工手动回收;
StorageClass
上面介绍的 PV 和 PVC 模式都是需要先创建好 PV,然后定义好 PVC 和 pv 进行一对一的 Bond,但是如果 PVC 请求成千上万,那么就需要创建成千上万的 PV,对于运维人员来说维护成本很高,Kubernetes 提供一种自动创建 PV 的机制,叫 StorageClass,它的作用就是创建 PV 的模板。k8s 集群管理员通过创建 storageclass 可以动态生成一个存储卷 pv 供 k8s pvc 使用。
每个 StorageClass 都包含字段 provisioner,parameters 和 reclaimPolicy。
具体来说,StorageClass 会定义以下两部分:
- 1、PV 的属性 ,比如存储的大小、类型等;
- 2、创建这种 PV 需要使用到的存储插件,比如 Ceph、NFS 等
Kubernetes 就能够根据用户提交的 PVC,找到对应的 StorageClass,然后 Kubernetes 就会调用 StorageClass 声明的存储插件,创建出需要的 PV。
provisioner:供应商,storageclass 需要有一个供应者,用来确定我们使用什么样的存储来创建 pv
常见的供应商列表请到 官网查看,下面使用 Kuboard 管理界面来创建存储类
进入到 Kuboard 界面中,在左侧一级菜单选择