k8s进阶-持久化基础

1.持久化存储

1.1Volumes介绍

官方介绍:https://kubernetes.io/zh-cn/docs/concepts/storage/volumes/

Volumes是Kubernetes中的一个抽象概念,本质上是一个可以被Pod中容器访问的目录。它解决了容器中文件系统的临时性问题,使数据可以在容器重启后依然保持。

Volumes主要有以下几个用途:

  1. 数据持久化:保证容器重启后数据不丢失。
  2. 容器间数据共享:同一Pod中的多个容器可以访问同一个Volume。
  3. 扩展容器存储能力:可以将外部存储挂载到容器中。
  4. 配置注入:可以将配置文件以Volume的形式挂载到容器中。

1.1.1EmptyDir实现数据共享

emptyDir是一种临时存储卷,具有以下特点:

  1. 当Pod被分配到某个节点上时创建,初始内容为空。
  2. 与Pod的生命周期绑定,当Pod从节点上移除时,emptyDir中的数据会被永久删除。
  3. 可以存储在节点的任何介质上,如磁盘、SSD或网络存储,也可以设置为存储在内存中。
  4. Pod中的所有容器都可以读写emptyDir卷中的相同文件。

案例:使用emptyDir实现同一个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
57
58
59
60
61
62
63
64
65
[root@k8s-master01 pra]# cat nginx-deployment.yaml
apiVersion: apps/v1 #指定这个资源使用的 Kubernetes API 版本,固定写法
kind: Deployment #指定资源类型是 Deployment。
metadata: # deployment的元数据
name: nginx-deployment # 创建的deployment的名字
labels: #键值对标签,用于资源的分类和选择
app: nginx #给这个deployment资源打上'app: nginx'标签
spec: #描述 Deployment 的期望状态,定义 Deployment 的具体配置和行为。
replicas: 1 # 指定需要运行的 Pod 副本数量。
selector: #选择器,用于选择哪些pod属于这个deployment
matchLabels: #匹配标签,选择带有特定标签的pod
app: nginx #指定带有' app: nginx '标签的pod进行管理
template: # pod的模板,用于定义pod
metadata: #pod的元数据
labels: #标签,配置pod的标签
app: nginx #确保创建的 Pod 具有'app: nginx' 标签。
spec: #描述pod的期望状态,定义pod的具体配置和行为
volumes: #定义pod中所有可用的卷
- name: emtydir #定义了一个名为emtydir的卷
emptyDir: {} #这个 emptyDir 卷在Pod启动时被创建,并且在Pod被删除时也会被删除。它本质上是一个临时存储,数据仅在Pod的生命周期内有效。
containers: #容器列表,复数,可配置多个容器
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #定义容器使用的镜像
volumeMounts: #定义了容器中挂载卷的位置
- name: emtydir #指定挂载的卷名为 emtydir
mountPath: /opt #指定该卷挂载到容器内的 /opt 目录。
- name: nginx1
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine
command:
- sh
- -c
- sleep 3600
volumeMounts:
- name: emtydir
mountPath: /data


#创建这个deployment
[root@k8s-master01 pra]# kubectl replace -f nginx-deployment.yaml
deployment.apps/nginx-deployment replaced

#在nginx的/opt目录中创建一个名字是test.log文件,验证在nginx1这个容器的/data是否存在这个test.log文件
[root@k8s-master01 pra]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-56c677c5df-9l94l 2/2 Running 0 112s

#进入第一个容器中创建文件
[root@k8s-master01 pra]# kubectl exec -ti nginx-deployment-56c677c5df-9l94l -c nginx -- sh
/ # touch /opt/text.log
/ # ls -l /opt/
total 0
-rw-r--r-- 1 root root 0 Aug 4 07:19 text.log

#进入nginx1容器的/data目录中验证是否有text.log
[root@k8s-master01 pra]# kubectl exec -ti nginx-deployment-56c677c5df-9l94l -c nginx1 -- sh
/ # ls /data/ -l
total 0
-rw-r--r-- 1 root root 0 Aug 4 07:19 text.log
/ # echo 'hello kubernetes' > /data/text.log #向文件中追加内容,然后去nginx容器中查看是否有改内容


#进入nginx容器中
[root@k8s-master01 pra]# kubectl exec -ti nginx-deployment-56c677c5df-9l94l -c nginx -- sh
/ # cat /opt/text.log
hello kubernetes #可以看到内容存在,实现了容器间数据共享

总结:用于多个容器之间的数据共享,同一个pod中a容器创建的数据在b容器中能获取到,与Pod的生命周期绑定,当Pod从节点上移除时,emptyDir中的数据会被永久删除。主要用于数据共享,而不是存储数据

1.1.2hostPath

hostPath卷能将主机节点文件系统上的文件或目录挂载到Pod中。它允许Pod访问宿主机上的文件系统。并不推荐使用,因为创建的pod并不能保证创建在同一个节点上,当然也可以使用其他手段让pod创建在某个节点上

使用hostPath的示例:将宿主机上/data/log.txt文件挂载到容器中的/liujunwei/log.txt文件中

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
[root@k8s-master01 pra]# vim nginx-deployment.yaml
apiVersion: apps/v1 #指定这个资源使用的 Kubernetes API 版本,固定写法
kind: Deployment #指定资源类型是 Deployment。
metadata: # deployment的元数据
name: nginx-deployment # 创建的deployment的名字
labels: #键值对标签,用于资源的分类和选择
app: nginx #给这个deployment资源打上'app: nginx'标签
spec: #描述 Deployment 的期望状态,定义 Deployment 的具体配置和行为。
replicas: 1 # 指定需要运行的 Pod 副本数量。
selector: #选择器,用于选择哪些pod属于这个deployment
matchLabels: #匹配标签,选择带有特定标签的pod
app: nginx #指定带有' app: nginx '标签的pod进行管理
template: # pod的模板,用于定义pod
metadata: #pod的元数据
labels: #标签,配置pod的标签
app: nginx #确保创建的 Pod 具有'app: nginx' 标签。
spec: #描述pod的期望状态,定义pod的具体配置和行为
nodeSelector:
valume: hostpath
volumes: #定义pod中所有可用的卷
- name: my-hostpath #定义了一个名字是my-hostpath的卷,用于在volumeMounts中引用。
hostPath: #卷类型,hostPath表示允许pod访问宿主机上的文件或目录
path: /data/log.txt #定义要挂载的宿主机文件路径
type: File #定义挂载的是文件,表示该路径必须是一个文件。(也可以是目录类型Directory)
containers: #容器列表,复数,可配置多个容器
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #定义容器使用的镜像
volumeMounts: #定义如何使用卷
- name: my-hostpath #引用卷的名称是my-hostPath,该字段必须与volumes.name字段相同
mountPath: /liujunwei/log.txt #定义容器内的挂载路径

#创建这个deploy
[root@k8s-master01 pra]# kubectl replace -f nginx-deployment.yaml
deployment.apps/nginx-deployment replaced

#查看创建的pod
[root@k8s-master01 pra]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-676d4d6b7d-8zrn4 1/1 Running 0 6m

#进入该pod的nginx容器中查看是否存在/liujunwei/log.txt文件
[root@k8s-master01 pra]# kubectl exec -ti nginx-deployment-5bb8d84d8f-q2wpz -c nginx -- sh
/ # cat /liujunwei/liujunwei.log
hello


#在上述案例中,是将宿主机的/data/log.txt文件挂载到容器的/liujunwei/liujunwei.log文件,在容器内liujunwei.log文件的内容是宿主机上log.txt文件的内容

hostPath卷有两个主要参数:

  • path: 指定宿主机上的文件或目录路径(必需)
  • type: 指定挂载类型(可选)

type支持的值包括:

  • DirectoryOrCreate: 如果路径不存在,则创建空目录
  • Directory: 必须存在的目录,是指每个运行pod的节点上都必须存在
  • FileOrCreate: 如果文件不存在,则创建空文件
  • File: 必须存在的文件,是指每个运行pod的节点上都必须存在
  • Socket: 必须存在的UNIX套接字
  • CharDevice: 必须存在的字符设备
  • BlockDevice: 必须存在的块设备

1.1.3挂载NFS至容器

1.1.3.1安装nfs服务

在使用nfs前需要先准备一台nfs服务器,这里用一台新机器作为nfs服务器,ip地址为192.168.0.106,主机名为:nfs-server。不占用k8s集群的五个节点资源。

在nfs-server机器上安装nfs服务端:

1
[root@nfs-server ~]# yum -y install rpcbind nfs-utils

启动服务并开机自启

1
2
3
4
5
[root@nfs-server ~]# systemctl start nfs-server^C
[root@nfs-server ~]# systemctl enable nfs-server
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
[root@nfs-server ~]# systemctl enable rpcbind.service

创建共享目录:

1
2
mkdir -p /data/nfs/
chmod 755 -R /data/nfs/

编辑配置文件,配置谁能访问共享目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vim /etc/exports
#在文件中假如下面配置
/data/nfs/ 192.168.0.0/24(rw,no_root_squash,no_all_squash,sync)



这行代码的意思是把共享目录/data/share/共享给192.168.0.0/24网段,表示该网段的机器都能访问该目录。
后面括号里的内容是权限参数,其中:
rw 表示设置目录可读写。
sync 表示数据会同步写入到内存和硬盘中,相反 rsync 表示数据会先暂存于内存中,而非直接写入到硬盘中。
no_root_squash NFS客户端连接服务端时如果使用的是root的话,那么对服务端分享的目录来说,也拥有root权限。
no_all_squash 不论NFS客户端连接服务端时使用什么用户,对服务端分享的目录来说都不会拥有匿名用户权限。
如果有多个共享目录配置,则使用多行,一行一个配置。保存好配置文件后,需要执行以下命令使配置立即生效:
[root@nfs-server ~]# exportfs -r

重启服务:

1
2
systemctl restart rpcbind
systemctl restart nfs

重启后执行showmount 命令来查看服务端(本机)是否可连接:

1
2
3
[root@nfs-server ~]# showmount -e localhost
Export list for localhost:
/data/nfs 192.168.0.0/24

出现上面结果表明NFS服务端配置正常。

在需要挂载的机器节点上挂载测试:

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
#客服端挂载服务端的共享目录,前提客服端需要安装nfs客户端
#这里在k8s-master01机器上挂载测试,所以在k8s-master01上安装客户端
[root@k8s-master01 ~]# yum -y install nfs-utils

#查看nfs服务器可挂载的共享目录,nfs服务器ip是192.168.0.106
[root@k8s-master01 ~]# showmount -e 192.168.0.106
Export list for 192.168.0.106:
/data/nfs 192.168.0.0/24

#挂载测试
[root@k8s-master01 ~]# mount -t nfs 192.168.0.106:/data/nfs /mnt/nfs/
[root@k8s-master01 ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 2.0G 0 2.0G 0% /dev
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 2.0G 92M 1.9G 5% /run
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/centos_k8s--master01-root 17G 6.7G 11G 39% /
/dev/sda1 1014M 170M 845M 17% /boot
tmpfs 393M 0 393M 0% /run/user/0
192.168.0.106:/data/nfs 46G 2.7G 43G 6% /mnt/nfs #该目录是新挂载的


#在/mnt/nfs目录创建文件,去nfs服务器(192.168.0.106)的/data/nfs目录查看是否存在
#文件创建
[root@k8s-master01 ~]# cd /mnt/nfs/
[root@k8s-master01 nfs]# touch 123.txt

#nfs服务器上验证文件是否存在
[root@nfs-server nfs]# pwd
/data/nfs
[root@nfs-server nfs]# ll
总用量 0
-rw-r--r-- 1 root root 0 8月 7 15:53 123.txt

#测试完成卸载/mnt/nfs目录
[root@k8s-master01 nfs]# umount /mnt/nfs

#上述测试完成表示nfs共享目录挂载成功!

上述安装操作参考https://cloud.tencent.com/developer/article/1721166

1.1.3.2在pod中挂载nfs

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
[root@k8s-master01 pra]# cat nginx-deployment.yaml          
apiVersion: apps/v1 #指定这个资源使用的 Kubernetes API 版本,固定写法
kind: Deployment #指定资源类型是 Deployment。
metadata: # deployment的元数据
name: nginx-deployment # 创建的deployment的名字
labels: #键值对标签,用于资源的分类和选择
app: nginx #给这个deployment资源打上'app: nginx'标签
spec: #描述 Deployment 的期望状态,定义 Deployment 的具体配置和行为。
replicas: 1 # 指定需要运行的 Pod 副本数量。
selector: #选择器,用于选择哪些pod属于这个deployment
matchLabels: #匹配标签,选择带有特定标签的pod
app: nginx #指定带有' app: nginx '标签的pod进行管理
template: # pod的模板,用于定义pod
metadata: #pod的元数据
labels: #标签,配置pod的标签
app: nginx #确保创建的 Pod 具有'app: nginx' 标签。
spec: #描述pod的期望状态,定义pod的具体配置和行为
nodeSelector: #节点选择器,用于将pod部署到指定标签的节点上
valume: hostpath #节点上的标签
volumes: #定义pod中所有可用的卷
- name: my-hostpath #定义了一个名字是my-hostpath的卷,用于在volumeMounts中引用。
hostPath: #卷类型,hostPath表示允许pod访问宿主机上的文件或目录
path: /data/log.txt #定义要挂载的宿主机文件路径
type: File #定义挂载的是文件,表示该路径必须是一个文件。(也可以是目录类型Directory)
- name: nfs-volume #定义了一个名字是nfs-volume的卷,用于在volumeMounts中引用。
nfs:
server: 192.168.0.106 #nfs服务地址
path: /data/nfs/dp #nfs共享目录
containers: #容器列表,复数,可配置多个容器
- name: nginx #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #定义容器使用的镜像
volumeMounts: #定义容器如何使用卷
- name: my-hostpath #引用卷的名称是my-hostPath,该字段必须与volumes.name字段相同
mountPath: /liujunwei/log.txt #定义容器内的挂载路径
- name: nfs-volume #引用卷的名称是nfs-volume ,该字段必须与volumes.name字段相同
mountPath: /junwei #指定容器中的目录,将/data/nfs/dp挂载到容器/junwei,也就是/junwei目录中的内容和/data/nfs/dp目录中的内容一样


#创建资源
[root@k8s-master01 pra]# kubectl replace -f nginx-deployment.yaml
deployment.apps/nginx-deployment replaced

#进入容器中验证目录是否挂载成功
[root@k8s-master01 pra]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-6df5d4d774-vgcrd 1/1 Running 0 6m
[root@k8s-master01 pra]# kubectl exec -ti nginx-deployment-6df5d4d774-vgcrd -- sh
/ # df -h
Filesystem Size Used Available Use% Mounted on
overlay 17.0G 6.6G 10.4G 39% /
tmpfs 64.0M 0 64.0M 0% /dev
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
192.168.0.106:/data/nfs/dp
45.1G 2.6G 42.5G 6% /junwei
/dev/mapper/centos_k8s--master01-root
17.0G 6.6G 10.4G 39% /liujunwei/acc.log
/dev/mapper/centos_k8s--master01-root
17.0G 6.6G 10.4G 39% /etc/hosts
/dev/mapper/centos_k8s--master01-root
17.0G 6.6G 10.4G 39% /dev/termination-log
/dev/mapper/centos_k8s--master01-root
17.0G 6.6G 10.4G 39% /etc/hostname
/dev/mapper/centos_k8s--master01-root
17.0G 6.6G 10.4G 39% /etc/resolv.conf
shm 64.0M 0 64.0M 0% /dev/shm
tmpfs 3.7G 12.0K 3.7G 0% /run/secrets/kubernetes.io/serviceaccount
tmpfs 1.9G 0 1.9G 0% /proc/acpi
tmpfs 64.0M 0 64.0M 0% /proc/kcore
tmpfs 64.0M 0 64.0M 0% /proc/keys
tmpfs 64.0M 0 64.0M 0% /proc/timer_list
tmpfs 64.0M 0 64.0M 0% /proc/sched_debug
tmpfs 1.9G 0 1.9G 0% /proc/scsi
tmpfs 1.9G 0 1.9G 0% /sys/firmware
/ # cat /junwei/
1.txt test/
/ # cat /junwei/1.txt
test



#在nfs服务器上查看文件
[root@nfs-server dp]# pwd
/data/nfs/dp
[root@nfs-server dp]# ll
总用量 4
-rw-r--r-- 1 root root 5 8月 7 17:00 1.txt
drwxr-xr-x 2 root root 6 8月 7 17:00 test
[root@nfs-server dp]# cat 1.txt
test

1.2PV 和 PVC

1.2.1什么是pv和pvc

持久卷 PV (Persistent Volume) :是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备,PV 卷的制备有两种方式:静态制备或动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

**存储请求PVC (Persistent Volume Claim)**:表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存)。同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以挂载为 ReadWriteOnce、ReadOnlyMany、ReadWriteMany 或 ReadWriteOncePod, 请参阅访问模式)。

PV和PVC的关系可以类比为“房东”和“租客”:

  • PV是房东,它提供了具体的存储资源。
  • PVC是租客,它向Kubernetes请求存储资源。

当PVC创建后,Kubernetes会根据PVC的需求去匹配一个合适的PV,并将它们绑定在一起。一旦绑定,PV就只能被这个PVC使用,无法再被其他PVC绑定。

PV和PVC的生命周期:

  1. 准备(Provisioning)静态供应:管理员手动创建PV。动态供应:通过StorageClass动态创建PV。
  2. 绑定(Binding):用户创建PVC并指定需要的资源和访问模式。Kubernetes找到匹配的PV并将它们绑定。
  3. 使用(Using):Pod可以像使用普通Volume一样使用PVC。
  4. 释放(Releasing):当用户删除PVC时,PV会进入“已释放”状态,但仍保留数据。
  5. 回收(Reclaiming):PV的回收策略决定了如何处理已释放的PV:保留(Retain):数据保留,需手动清理。回收(Recycle):清除数据,PV可再次使用。删除(Delete):删除PV及其数据。

1.2.2PV回收策略:

在Kubernetes中,PersistentVolume(PV)的回收策略用于定义当与之绑定的PersistentVolumeClaim(PVC)被删除后,PV应该如何处理。Kubernetes支持三种主要的PV回收策略:

  1. Retain(保留):当PVC被删除时,PV不会被删除,而是被标记为“Released”已释放状态。此时,PV中的数据仍然存在,需要管理员手动清理或重新利用这些数据。这种策略适用于数据需要保留的场景.
  2. Recycle(回收):此策略会清除PV中的数据,例如删除所有文件,然后PV可以被重新绑定到新的PVC。这种策略比较简单且适用于某些特定场景,但在Kubernetes 1.10版本后已经被弃用,不再推荐使用.
  3. Delete(删除):这是动态配置PV的默认策略。当PVC被删除时,PV和其存储资源将被自动删除。这种策略适用于不需要保留数据的场景.
  4. 可以通过persistentVolumeReclaimPolicy: Recycle字段配置

1.2.3PV的访问策略:

在Kubernetes中,Persistent Volume(PV)的访问策略(Access Modes)用于定义如何访问存储卷。PV支持以下几种访问模式:

  1. ReadWriteOnce(RWO):PV可以被单个节点以读写方式挂载。这意味着只有一个节点可以同时以读写方式访问该存储卷。
  2. ReadOnlyMany(ROX):PV可以被多个节点以只读方式挂载。这种模式允许多个节点同时访问存储卷,但只能以只读方式访问。
  3. ReadWriteMany(RWX):PV可以被多个节点以读写方式挂载。这种模式允许多个节点同时以读写方式访问存储卷。

需要注意的是,虽然一些PV可能支持多种访问模式,但在实际挂载时只能选择一种模式进行使用。选择合适的访问模式取决于应用程序的需求和存储卷的特性。

1.2.4存储的分类

文件存储:一些数据可能需要被多个节点使用,比如用户的头像、用户上传的文件等,实现方式:NFS、NAS、FTP、CephFS等。

➢ 块存储:一些数据只能被一个节点使用,或者是需要将一块裸盘整个挂载使用,比如数据库、Redis、rabbitmq、zookeeper、kafka等,实现方式:Ceph、GlusterFS、公有云。

➢ 对象存储:由程序代码直接实现的一种存储方式,云原生应用无状态化常用的实现方式,实现方式:一般是符合S3协议的云存储,比如AWS的S3存储、Minio、七牛云等。

1.3创建NFS或NAS类型的PV

生产环境不要使用NFS在k8s集群中做文件存储,nfs是单点的,如果出现故障会影响整个集群。生产环境可以用云平台的NAS服务

这里是测试使用,nfs使用10.1.3中搭建的nfs服务。这里五台k8s集群的节点都需要安装nfs客户端,因为pod会随机在节点上运行,所以每个节点都需要安装nfs客户端。

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
#k8s集群中所有节点都安装
yum -y install nfs-utils

#在服务端新增一个共享目录
[root@nfs-server ~]# vim /etc/exports
/data/nfs/ 192.168.0.0/24(rw,no_root_squash,no_all_squash,sync)
#/data/k8s/目录为新增的目录
/data/k8s/ 192.168.0.0/24(rw,no_root_squash,no_all_squash,sync)

#重载
[root@nfs-server ~]# exportfs -r

#重启服务
[root@nfs-server ~]# systemctl restart nfs rpcbind

#测试挂载
#192.168.0.106:/data/k8s是nfs服务器的ip,目录是配置的nfs共享目录
#/test-nfs/ 挂载目录,就是将192.168.0.106:/data/k8s挂载到本地的/test-nfs目录
[root@k8s-master01 pra]# mount -t nfs 192.168.0.106:/data/k8s /test-nfs/

#查看挂载目录
[root@k8s-master01 pra]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 2.0G 0 2.0G 0% /dev
tmpfs 2.0G 0 2.0G 0% /dev/shm
tmpfs 2.0G 173M 1.8G 9% /run
tmpfs 2.0G 0 2.0G 0% /sys/fs/cgroup
/dev/mapper/centos_k8s--master01-root 17G 6.7G 11G 40% /
/dev/sda1 1014M 170M 845M 17% /boot
tmpfs 393M 0 393M 0% /run/user/0
192.168.0.106:/data/k8s 46G 2.7G 43G 6% /test-nfs #挂载目录已经存在,证明可用

创建一个pv类型的资源:

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
#下面的 PV 定义了一个使用 NFS 存储的 10Gi 容量的持久化卷,可以被多个节点以读写模式挂载。当 PV 从 PVC 中释放后,数据会被保留。
[root@k8s-master01 pv]# cat pv-nfs.yaml
apiVersion: v1 #指定了 Kubernetes API 的版本,这里使用的是 v1,表示最新稳定版本。
kind: PersistentVolume #定义了资源的类型,这里是一个 PersistentVolume。持久卷为集群提供持久化存储,与 PersistentVolumeClaim 配合使用。
metadata:#定义这个资源的元数据,通常包括 name、namespace、labels、annotations 等。
name: pv-nfs#指定了 PV 的名称,这里是 pv-nfs。在整个集群内必须是唯一的。
spec: #定义持久卷的详细规范和配置。
capacity: #定义持久卷的存储容量。
storage: 10Gi #定义了卷的大小,这里是 10Gi。
volumeMode: Filesystem #指定持久卷的卷模式,这里是 Filesystem,意味着它将作为文件系统被挂载。还有Block 模式
accessModes:#定义 PV 的访问模式,这里是 ReadWriteMany,表示可以被多个节点以读写模式挂载。
- ReadWriteMany #表示可以被多个节点以读写模式挂载。
persistentVolumeReclaimPolicy: Retain #定义当 PV 从 PVC 中释放后的回收策略,这里是 Retain,表示当持久卷被释放后,仍然保留数据而不自动删除。
storageClassName: nfs-slow #指定存储类名称,pvc要绑定到pv上就是根据这个名称进行绑定。
nfs: #定义 NFS(网络文件系统)卷的相关配置。
server: 192.168.0.106 #指定 NFS 服务器的 IP 地址或主机名,这里是 192.168.0.106。
path: /data/k8s #指定 NFS 服务器上的共享目录路径,这里是 /data/k8s。

#创建pv
[root@k8s-master01 pv]# kubectl replace -f pv-nfs.yaml
persistentvolume/pv-nfs replaced

#查看创建的pv
#pv创建成功不代表存储就是可用的,要在pod中挂载才知道能不能用
[root@k8s-master01 pv]# kubectl get -f pv-nfs.yaml
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 10Gi RWX Retain Available nfs-slow 57m

pv的状态解释:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[root@k8s-master01 pv]# kubectl get -f pv-nfs.yaml
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-nfs 10Gi RWX Retain Available nfs-slow 57m

---下面是对每个字段的解释---
NAME: 这是持久卷的名称。你的 PV 名为 pv-nfs,这是在 YAML 文件的 metadata.name 字段中指定的。
CAPACITY: 这个字段显示持久卷的存储容量。这里是 10Gi,代表这个 PV 提供 10 Gibibytes 的存储空间。这个值对应于 YAML 文件中的 spec.capacity.storage。
ACCESS MODES: 显示持久卷的访问模式。RWX 表示 ReadWriteMany,即允许多个节点同时挂载并读写该卷。这个值对应于 YAML 文件中的 spec.accessModes。
RECLAIM POLICY: 指定 PV 的回收策略。Retain 表示在 PV 被释放后(即关联的 PersistentVolumeClaim 被删除后),PV 保持现状而不自动删除。这与 YAML 文件中的 spec.persistentVolumeReclaimPolicy 字段一致。
STATUS: 显示持久卷的当前状态。Available 表示这个 PV 目前未绑定任何 PersistentVolumeClaim,可以被新的 PVC 绑定。
CLAIM: 如果这个持久卷已经被某个 PersistentVolumeClaim 绑定,这里会显示该 PVC 的名称。在你的例子中,这个字段是空的,表示没有 PVC 绑定这个 PV。
STORAGECLASS: 这个字段显示了持久卷所属的存储类(StorageClass)。nfs-slow 是在 YAML 文件中 spec.storageClassName 字段中定义的存储类名称。存储类定义了动态供应存储卷的配置和策略。
REASON: 如果持久卷无法正常使用或者有问题时,这个字段会显示具体原因。在你的例子中,这个字段是空的,表示 PV 没有问题。
AGE: 显示这个 PV 已经存在的时间。57m 表示这个 PV 已经创建了 57 分钟。
-------------------------

pv其他状态:(STATUS字段)
➢ Available:可用,没有被PVC绑定的空闲资源。
➢ Bound:已绑定,已经被PVC绑定。
➢ Released:已释放,PVC被删除,但是资源还未被重新使用。
➢ Failed:失败,自动回收失败。

1.4创建hostPath类型的PV

定义一个hostPath的PV

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@k8s-master01 pv]# cat hostpath-pv.yaml
apiVersion: v1 #指定了 Kubernetes API 的版本,这里使用的是 v1,表示最新稳定版本。
kind: PersistentVolume #定义了资源的类型,这里是一个 PersistentVolume。持久卷为集群提供持久化存储,与 PersistentVolumeClaim 配合使用。
metadata: #定义这个资源的元数据,通常包括 name、namespace、labels、annotations 等。
name: hostpath-pv #指定了 PV 的名称,这里是 pv-nfs。在整个集群内必须是唯一的。
spec: #定义持久卷的详细规范和配置。
capacity: #定义持久卷的存储容量。
storage: 10Gi #定义了卷的大小,这里是 10Gi。
volumeMode: Filesystem #指定持久卷的卷模式,这里是 Filesystem,意味着它将作为文件系统被挂载。还有Block 模式
accessModes: #定义 PV 的访问模式,这里是 ReadWriteMany,表示可以被多个节点以读写模式挂载。
- ReadWriteOnce #表示可以被多个节点以读写模式挂载。
persistentVolumeReclaimPolicy: Retain #定义当 PV 从 PVC 中释放后的回收策略,这里是 Retain,表示当持久卷被释放后,仍然保留数据而不自动删除。
storageClassName: hostpath #指定存储类名称,这里使用 nfs-slow。存储类用来管理存储的动态供应和配置。
hostPath:
path: /mnt/data

创建这个pv:

1
2
[root@k8s-master01 pv]# kubectl create -f hostpath-pv.yaml
persistentvolume/hostpath-pv created

查看创建的pv

1
2
3
4
[root@k8s-master01 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
hostpath-pv 10Gi RWO Retain Available hostpath 14s
pv-nfs 10Gi RWX Retain Available nfs-slow 6d22h

1.5创建CephRBD类型的VP

CephRBD类型的VP配置案例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: PersistentVolume
metadata:
name: ceph-rbd-pv
spec:
capacity:
storage: 1Gi
storageClassName: ceph-fast
accessModes:
- ReadWriteOnce
rbd:
monitors:
- 192.168.1.123:6789
- 192.168.1.124:6789
- 192.168.1.125:6789
pool: rbd
image: ceph-rbd-pv-test
user: admin
secretRef:
name: ceph-secret
fsType: ext4
readOnly: false

➢ monitors:Ceph的monitor节点的IP

➢ pool:所用Ceph Pool的名称,可以使用ceph osd pool ls查看

➢ image:Ceph块设备中的磁盘映像文件,可以使用rbd create POOL_NAME/IMAGE_NAME – size 1024 创建,使用rbd list POOL_NAME查看

➢ user:Rados的用户名,默认是admin

➢ secretRef:用于验证Ceph身份的密钥

➢ fsType:文件类型,可以是ext4、XFS等

➢ readOnly:是否是只读挂载

1.6PVC绑定pv

pAvUICq.md.png

10.6.1pvc挂载示例

注意:pv是没有命名空间隔离的,但是pvc具有命名空间隔离,pod和pvc要在同一个命名空间才能正常使用

这里的pvc跟10.3示例中的pv进行绑定

PV配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@k8s-master01 pv]# cat pv-nfs.yaml
apiVersion: v1 #指定了 Kubernetes API 的版本,这里使用的是 v1,表示最新稳定版本。
kind: PersistentVolume #定义了资源的类型,这里是一个 PersistentVolume。持久卷为集群提供持久化存储,与 PersistentVolumeClaim 配合使用。
metadata: #定义这个资源的元数据,通常包括 name、namespace、labels、annotations 等。
name: pv-nfs #指定了 PV 的名称,这里是 pv-nfs。在整个集群内必须是唯一的。
spec: #定义持久卷的详细规范和配置。
capacity: #定义持久卷的存储容量。
storage: 10Gi #定义了卷的大小,这里是 10Gi。
volumeMode: Filesystem #指定持久卷的卷模式,这里是 Filesystem,意味着它将作为文件系统被挂载。还有Block 模式
accessModes: #定义 PV 的访问模式,这里是 ReadWriteMany,表示可以被多个节点以读写模式挂载。
- ReadWriteMany #表示可以被多个节点以读写模式挂载。
persistentVolumeReclaimPolicy: Retain #定义当 PV 从 PVC 中释放后的回收策略,这里是 Retain,表示当持久卷被释放后,仍然保留数据而不自动删除。
storageClassName: nfs-slow #指定存储类名称,这里使用 nfs-slow。存储类用来管理存储的动态供应和配置。
nfs: #定义 NFS(网络文件系统)卷的相关配置。
server: 192.168.0.106 #指定 NFS 服务器的 IP 地址或主机名,这里是 192.168.0.106。
path: /data/k8s #指定 NFS 服务器上的共享目录路径,这里是 /data/k8s。


PVC配置:

1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s-master01 pv]# cat pvc-nfs.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nfs-pvc-claim
spec:
storageClassName: nfs-slow
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi #<=pv的大小

创建这个pvc,与pv进行绑定:

1
2
[root@k8s-master01 pv]# kubectl create -f pvc-nfs.yaml
persistentvolumeclaim/nfs-pvc-claim created

查看pv和pvc的状态:

1
2
3
4
5
6
7
[root@k8s-master01 pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
hostpath-pv 10Gi RWO Retain Available hostpath 4d1h
pv-nfs 10Gi RWX Retain Bound default/nfs-pvc-claim nfs-slow 162m
[root@k8s-master01 pv]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nfs-pvc-claim Bound pv-nfs 10Gi RWX nfs-slow 4m46s

pAvUfEj.md.png

1.6.2pod中使用pvc

pod配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@k8s-master01 pv]# cat pvc-nfs-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pvc-nfs-pod #pod名称
spec:
containers:
- name: pvc-nfs-container #容器名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #镜像地址
volumeMounts: #挂载卷
- name: nfs-pvc #卷的名称,这个名称要和下面volumes中的name一致
mountPath: /usr/share/nginx/html #挂载路径
volumes: #卷
- name: nfs-pvc #定义卷名称,这个名称要和上面volumeMounts中的name一致
persistentVolumeClaim: #持久卷声明
claimName: nfs-pvc-claim #声明名称,这个名称要和PersistentVolumeClaim中的metadata.name一致

创建pod:

1
2
[root@k8s-master01 pv]# kubectl create -f pvc-nfs-pod.yaml
pod/pvc-nfs-pod created

查看pod状态:

1
2
3
[root@k8s-master01 pv]# kubectl get po
NAME READY STATUS RESTARTS AGE
pvc-nfs-pod 1/1 Running 0 15s

进入pod中查看挂载目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@k8s-master01 pv]# kubectl exec -ti pvc-nfs-pod  -- sh
/ # df -h
Filesystem Size Used Available Use% Mounted on
overlay 17.0G 5.5G 11.5G 32% /
tmpfs 64.0M 0 64.0M 0% /dev
tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
192.168.0.106:/data/k8s 45.1G 2.6G 42.4G 6% /usr/share/nginx/html
tmpfs 1.9G 0 1.9G 0% /proc/acpi
tmpfs 64.0M 0 64.0M 0% /proc/kcore
tmpfs 64.0M 0 64.0M 0% /proc/keys
tmpfs 64.0M 0 64.0M 0% /proc/timer_list
tmpfs 64.0M 0 64.0M 0% /proc/sched_debug
tmpfs 1.9G 0 1.9G 0% /proc/scsi
tmpfs 1.9G 0 1.9G 0% /sys/firmware

#通过df -h 可以看出192.168.0.106:/data/k8s目录已经挂载到容器的/usr/share/nginx/html目录

在nfs服务器上的共享目录中创建一个文件,在该pod中查看是否存在这个文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#在nfs服务器上的共享目录中创建文件
[root@nfs-server ~]# cd /data/k8s
[root@nfs-server k8s]# echo "hello" >index.html
[root@nfs-server k8s]# ll
总用量 4
-rw-r--r-- 1 root root 6 8月 20 18:16 index.html

#在pod上验证是否存在这个index.html
[root@k8s-master01 pv]# kubectl exec -ti pvc-nfs-pod -- sh #进入pod
/ # ls -l /usr/share/nginx/html
total 4
-rw-r--r-- 1 root root 6 Aug 20 10:16 index.html
/ # cat /usr/share/nginx/html/index.html
hello

/ # curl localhost
hello

1.6.3deployment中使用pvc

deployment配置:

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
[root@k8s-master01 pv]# cat nfs-deploy.yaml
apiVersion: apps/v1 #指定这个资源使用的 Kubernetes API 版本,固定写法
kind: Deployment #指定资源类型是 Deployment。
metadata: # deployment的元数据
name: nginx-deployment # 创建的deployment的名字
labels: #键值对标签,用于资源的分类和选择
app: nginx #给这个deployment资源打上'app: nginx'标签
spec: #描述 Deployment 的期望状态,定义 Deployment 的具体配置和行为。
replicas: 5 # 指定需要运行的 Pod 副本数量。
selector: #选择器,用于选择哪些pod属于这个deployment
matchLabels: #匹配标签,选择带有特定标签的pod
app: nginx #指定带有' app: nginx '标签的pod进行管理
template: # pod的模板,用于定义pod
metadata: #pod的元数据
labels: #标签,配置pod的标签
app: nginx #确保创建的 Pod 具有'app: nginx' 标签。
spec: #描述pod的期望状态,定义pod的具体配置和行为
volumes:
- name: nfs-pvc #定义卷的名称,用于在容器中引用,这个名称要和下面volumeMounts中的name一致
persistentVolumeClaim: #指定要使用的PVC
claimName: nfs-pvc-claim #指定要使用的PVC的名称
containers: #容器列表,复数,可配置多个容器
- name: pvc-nfs-container #容器的名称
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/nginx:1.27-alpine #定义容器使用的镜像
volumeMounts:
- mountPath: /usr/share/nginx/html #容器内的挂载路径
name: nfs-pvc #挂载的卷名称,与volumes中的name保持一致

创建找个5副本的deployment:

1
2
[root@k8s-master01 pv]# kubectl create -f nfs-deploy.yaml
deployment.apps/nginx-deployment created

查看创建的pod:

1
2
3
4
5
6
7
[root@k8s-master01 pv]# kubectl get po
NAME READY STATUS RESTARTS AGE
nginx-deployment-9b55c9df6-4wc6v 1/1 Running 0 20h
nginx-deployment-9b55c9df6-5bd2d 1/1 Running 0 20h
nginx-deployment-9b55c9df6-c95lv 1/1 Running 0 20h
nginx-deployment-9b55c9df6-kmvv9 1/1 Running 0 20h
nginx-deployment-9b55c9df6-lc77f 1/1 Running 0 20h

验证挂载卷:在nfs服务器上的共享目录中(或者pod)创建一个文件,在该pod中(或者nfs的共享目录中)查看是否存在这个文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#进入nginx-deployment-9b55c9df6-c95lv 的pod 中(任意pod即可),容器内的挂载目录是/usr/share/nginx/html
[root@k8s-master01 pv]# kubectl exec -ti nginx-deployment-9b55c9df6-c95lv -- sh
/ # cd /usr/share/nginx/html
/usr/share/nginx/html # ls -l
total 4
-rw-r--r-- 1 root root 6 Aug 20 10:16 index.html
/usr/share/nginx/html # echo 'hello kubernetes' > index.html
/usr/share/nginx/html # cat index.html
hello kubernetes #在其他pod(和nfs共享目录中)内查看该文件内容是否一致

#进入nginx-deployment-9b55c9df6-lc77f查看
[root@k8s-master01 pv]# kubectl exec -ti nginx-deployment-9b55c9df6-lc77f -- sh
/ # cat /usr/share/nginx/html/index.html
hello kubernetes #(一致)

#查看nfs共享目录中的文件
[root@nfs-server k8s]# cat /data/k8s/index.html
hello kubernetes #(一致)

1.7PVC创建和挂载失败原因

  • PVC一直处于Pending的原因:
    pvc的空间申请大小大于pv的大小
    pvc的storageClassName和pv的storageClassName不一致

    pvc的accessModes和pv的accessModes不一致

  • 挂载PVC的pod一直处于Pending:
    pvc没有创建成功

    pvc的pod不在同一个namespace(命名空间)