Kubernetes Volume之Persistent Volume持久卷

这里介绍Kubernetes卷中的持久卷(PersistentVolume,PV)

abstract.png

基本概念

1. PV 持久卷:PersistentVolume,其是K8s中对实际物理存储系统的抽象。作为K8s中集群层面的资源,与节点资源类似。PV不属于任何命名空间
2. PVC 持久卷申领:PersistentVolumeClaim,其是K8s中用户对存储请求的抽象。类似地,Pod会消耗节点资源,而PVC则会消耗PV资源

具体地,通过PV实现了对底层真实存储系统的抽象,使得开发者只需通过创建PVC资源即可。而开发者可以直接将PVC的名称作为卷在工作负载资源中进行引用。当集群中存在满足PVC要求的PV时,则会将该PV与PVC进行双向绑定

静态制备

此场景下K8s集群的管理员需要先创建相应的PV资源,然后才能供开发者使用该资源。下面即是通过hostPath卷创建PV资源的示例。此时不难理解,PV实际上是对物理存储资源的抽象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 1. 创建持久卷PV

apiVersion: v1
kind: PersistentVolume
metadata:
# PV卷名称
name: mongodb-pv
spec:
# 容量
capacity:
# 存储大小: 100MB
storage: 100Mi
# 该卷支持的访问模式
accessModes:
- ReadWriteOnce # RWO, 该卷可以被一个节点以读写方式挂载
- ReadOnlyMany # ROX, 该卷可以被多个节点以只读方式挂载
# 回收策略: 保留
persistentVolumeReclaimPolicy: Retain
# 该持久卷的实际存储类型: 此处使用HostPath类型卷
hostPath:
path: /tmp/MongodbData

这里对卷的访问模式进行说明,其支持下述选项。值得一提的是,卷虽然可以能够支持多种访问模式,但其在同一时刻只能以一种访问模式进行挂载。例如,某卷可以被节点A以RWO模式挂载,也可以被B节点以ROX模式挂载。但不能同时使用两种模式挂载

1. ReadWriteOnce (RWO):卷可以被一个节点以读写方式挂载。ReadWriteOnce访问模式允许运行在同一节点上的多个Pod访问卷
2. ReadOnlyMany (ROX):卷可以被多个节点以只读方式挂载
3. ReadWriteMany (RWX):卷可以被多个节点以读写方式挂载
4. ReadWriteOncePod (RWOP):在Kubernetes 1.22以上版本时,卷可以被单个Pod以读写方式挂载

这里对卷的回收策略进行补充说明

1. Retain 保留

当PVC资源被删除时,其所绑定的PV不会被删除,但该PV的状态会变为Released已释放。由于此时PV所关联的物理存储系统上仍然存在历史数据,故该PV此时不能直接被申领。 需要集群管理员手动进行处置。一方面对于PV资源而言,其需要删除并重新创建;另一方面,对于PV所关联的物理存储系统上的数据,需要根据实际情况判断是直接删除还是保留以便能够复用数据

2. Delete 删除

其不需要管理员人工进行介入操作,系统不仅会将PV资源删除,同时还会将该PV资源所关联的物理存储系统上的数据一并删除掉

K8s集群的管理员创建PV资源,效果如下所示

figure 1.jpeg

当K8s集群中的PV资源准备好后,开发者就可以通过创建PVC资源来获取PV了。这里我们将storageClassName字段设置为空字符串,意为不使用存储类进行动态制备,而是使用集群管理员提前创建好的PV。即所谓的静态制备;然后在部署应用的配置文件中,直接引用PVC的名称进行卷的定义即可。需要注意 PVC所属的命名空间 与 使用该PVC的Pod 需在同一个命名空间下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 1. 创建持久卷申领PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-pvc
spec:
resources:
# 申请30MB的存储空间
requests:
storage: 30Mi
# 访问模式
accessModes:
- ReadWriteOnce
# 禁止使用动态制备的卷, 即使用静态制备
storageClassName: ""

---

# 2. 创建数据库应用

apiVersion: apps/v1
# 资源类型
kind: ReplicaSet
metadata:
# RS名称
name: my-mongodb-app
spec:
# 副本数量
replicas: 1
# 标签选择器
selector:
matchLabels:
app: db
# Pod 模板
template:
metadata:
# 标签信息
labels:
app: db
spec:
# 容器信息
containers:
- name: my-mongodb-app
image: mongo
volumeMounts:
# 将名为mongodb-data的卷挂载到容器内的指定路径
- name: mongodb-data
# MongoDB默认的数据存储路径
mountPath: /data/db
# 卷信息
volumes:
- name: mongodb-data
# 引用PVC的名称即可
persistentVolumeClaim:
claimName: mongodb-pvc

当PVC创建完成后,一旦集群中存在满足PVC指定的容量要求、访问模式的PV资源后。该PVC即会与相应的PV进行双向绑定。如下所示,同时会发现应用所在Pod也部署成功

figure 2.jpeg

动态制备

对于静态制备而言,无论采用何种回收策略。事实上都需要系统管理员再次创建PV资源。为此动态制备应运而生,K8s集群在收到用户创建的PVC后,会通过PVC中所指定的StorageClass存储类自动地制备出相应的PV资源以供使用。在动态制备场景下,系统管理员只需提前创建相应的若干个StorageClass存储类资源即可。具体地,在StorageClass存储类中会关联真实的物理存储系统和相应的provisioner制备器。其中动态制备的PV会继承相应的StorageClass中定义的回收策略。由于这里我们是通过Kind搭建K8s集群环境的,其已经内置了一个StorageClass存储类。如下所示

figure 3.jpeg

此时,开发者只需在创建PVC的过程通过storageClassName字段指定相应的存储类名称即可。类似地在部署应用时直接引用PVC名称定义卷

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 1. 创建持久卷申领PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mongodb-pvc-2
spec:
resources:
# 申请20MB的存储空间
requests:
storage: 30Mi
# 访问模式
accessModes:
- ReadWriteOnce
# 使用名为standard的存储类进行动态制备
storageClassName: "standard"

---

# 2. 创建数据库应用

apiVersion: apps/v1
# 资源类型
kind: ReplicaSet
metadata:
# RS名称
name: my-mongodb-app-2
spec:
# 副本数量
replicas: 1
# 标签选择器
selector:
matchLabels:
app: db2
# Pod 模板
template:
metadata:
# 标签信息
labels:
app: db2
spec:
# 容器信息
containers:
- name: my-mongodb-app-2
image: mongo
volumeMounts:
# 将名为mongodb-data-2的卷挂载到容器内的指定路径
- name: mongodb-data-2
# MongoDB默认的数据存储路径
mountPath: /data/db
# 卷信息
volumes:
- name: mongodb-data-2
# 引用PVC的名称即可
persistentVolumeClaim:
claimName: mongodb-pvc-2

效果如下所示,动态制备的PV成功与PVC进行了绑定,应用也处于运行状态

figure 4.jpeg

参考文献

  1. Kubernetes in Action中文版 Marko Luksa著
  2. 深入剖析Kubernetes 张磊著
0%