目录
K8s 持久化存储
一、k8s 持久化存储:emptyDir
二、k8s 持久化存储:hostPath
三、k8s 持久化存储:nfs
3.1 搭建 nfs 服务
3.2 创建Pod,挂载 NFS 共享出来的目录
3.3 测试 pod 挂载 nfs 是否成功
K8s 持久化存储
在 k8s 中为什么要做持久化存储?k8s 中部署的应用都是以 pod 容器的形式运行的,假如我们部署 MySQL 、 Redis 等数据库需要对这些数据库产生的数据做备份 。因为 Pod 是有生命周期的,如果 pod 不挂载数据卷,那 pod 被删除或重启后这些数据会随之消失,如果想要长久的保留这些数据就要用到 pod 数据持久化存储。
查看 k8s 支持哪些存储类型:
[root@k8s-master01 ~]# kubectl explain pods.spec.volumes
常用的如下:
- emptyDir
- hostPath
- nfs
- persistentVolumeClaim
- glusterfs
- cephfs
- configMap
- secret
我们想要使用存储卷,需要经历如下步骤:
- 定义 pod 的 volume ,这个 volume 指明它要关联到哪个存储上的;
- 在容器中要使用 volumemounts 挂载对应的存储 。
一、k8s 持久化存储:emptyDir
emptyDir 类型的 Volume 是在 Pod 分配到 Node 上时被创建, Kubernetes 会在 Node 上自动分配一个目录,因此无需指定宿主机 Node 上对应的目录文件。 这个目录的初始内容为空,当 Pod 从 Node 上移除时, emptyDir 中的数据会被永久删除。 emptyDir Volume 主要用于某些应用程序无需永久保存的临时目录,多个容器的共享目录等 。
emptyDir
的一些用途:
- 缓存空间,例如基于磁盘的归并排序。
- 为耗时较长的计算任务提供检查点,以便任务能方便地从崩溃前状态恢复执行。
- 在 Web 服务器容器服务数据时,保存内容管理器容器获取的文件。
# 创建个存放此次实验 yaml 文件的目录
[root@k8s-master01 ~]# mkdir volumes
[root@k8s-master01 ~]# cd volumes/
# 查看帮助命令
[root@k8s-master01 volumes]# kubectl explain pods
[root@k8s-master01 volumes]# kubectl explain pods.metadata
[root@k8s-master01 volumes]# kubectl explain pods.spec
[root@k8s-master01 volumes]# kubectl explain pods.spec.containers
[root@k8s-master01 volumes]# kubectl explain pods.spec.volumes
[root@k8s-master01 volumes]# kubectl explain pods.spec.volumes.emptyDir
[root@k8s-master01 volumes]# kubectl explain pods.spec.containers.volumeMounts
# 创建一个 pod,挂载临时目录 emptyDir
[root@k8s-master01 volumes]# vim emptydir.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-empty
spec:
containers:
- name: container-empty
image: nginx
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /cache
name: cache-volume # 必须与 emptyDir.name 同名
volumes:
- emptyDir: {}
name: cache-volume
[root@k8s-master01 volumes]# kubectl apply -f emptydir.yaml
pod/pod-empty created
# pod 调度到 node2 节点了
[root@k8s-master01 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-empty 1/1 Running 0 17s 10.244.169.157 k8s-node2 <none> <none>
# 查看 pod 的 uid
[root@k8s-master01 volumes]# kubectl get pods pod-empty -o yaml | grep uid
uid: b8bf8521-cd8d-4085-8ae0-328fa6241879
# 在 node2 查看临时目录
[root@k8s-node2 ~]# tree /var/lib/kubelet/pods/b8bf8521-cd8d-4085-8ae0-328fa6241879
[root@k8s-node2 ~]# cd /var/lib/kubelet/pods/b8bf8521-cd8d-4085-8ae0-328fa6241879/volumes/kubernetes.io~empty-dir/cache-volume/
# 在 master 节点进入容器内部,在挂载目录创建文件
[root@k8s-master01 volumes]# kubectl exec -it pod-empty -- bash
root@pod-empty:/# cd cache/
root@pod-empty:/cache# touch 1.txt
# 在 node2 本地挂载目录可以同步看到
[root@k8s-node2 cache-volume]# ls
1.txt
# 而在 node2 本地挂载目录下创建文件,也能同步到容器中
[root@k8s-node2 cache-volume]# touch 2.txt
root@pod-empty:/cache# ls
1.txt 2.txt
# 如果删除了 pod,那么 node2 本地挂载目录及数据也会被删除
[root@k8s-master01 volumes]# kubectl delete -f emptydir.yaml
pod "pod-empty" deleted
[root@k8s-node2 cache-volume]# ls
[root@k8s-node2 cache-volume]# cd ../
cd: 获取当前目录时出错: getcwd: 无法访问父目录: 没有那个文件或目录
由上可知,临时目录在被调度到的 node2 节点本地的 /var/lib/kubelet/pods/b8bf8521-cd8d-4085-8ae0-328fa6241879/volumes/kubernetes.io~empty-dir/cache-volume/ 下。
官方参考文档:卷 | Kubernetes
二、k8s 持久化存储:hostPath
hostPath Volume 是指 Pod 挂载宿主机上的目录或文件。 hostPath Volume 使得容器可以使用宿主机的文件系统进行存储 hostpath (宿主机路径):节点级别的存储卷,在 pod 被删除,这个存储卷还是存在的,不会被删除,但要同一个 pod 被调度到同一个节点上来,在 pod 被删除重新被调度到这个节点之后,对应的数据依然是存在的。
# 查看 hostPath 存储卷的用法
[root@k8s-master01 volumes]# kubectl explain pods.spec.volumes.hostPath
# 创建一个 pod ,挂载 hostPath 存储卷
[root@k8s-master01 volumes]# vim hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: test-nginx
volumeMounts:
- mountPath: /test-nginx
name: test-volume
- image: billygoo/tomcat8-jdk8
imagePullPolicy: IfNotPresent
name: test-tomcat
volumeMounts:
- mountPath: /test-tomcat
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data1
type: DirectoryOrCreate # DirectoryOrCreate 表示本地有 data1 目录,就用本地的,本地没有就会在 pod 调度到的节点自动创建一个。
# 更新资源清单文件
[root@k8s-master01 volumes]# kubectl apply -f hostpath.yaml
pod/test-hostpath created
# 查看 pod 调度 到了哪个物理节点
[root@k8s-master01 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-hostpath 2/2 Running 0 8s 10.244.169.158 k8s-node2 <none> <none>
支持的 type
值如下:
由上面可以知道 pod 调度到了node2 上,登录到 node2 机器,查看是否在这台机器创建了存储目录:
# data1 目录权限为 755
[root@k8s-node2 ]# cd /
[root@k8s-node2 /]# ll | grep data1
drwxr-xr-x 2 root root 6 12月 15 21:16 data1
# 在本地挂载目录下创建文件
[root@k8s-node2 /]# cd data1/
[root@k8s-node2 data1]# touch 1.txt
# 测试存储卷是否可以正常使用,登录到 nginx 容器
[root@k8s-master01 volumes]# kubectl exec -it test-hostpath -c test-nginx -- bash
root@test-hostpath:/# cd test-nginx/
root@test-hostpath:/test-nginx# ls
1.txt
root@test-hostpath:/test-nginx# touch 2.txt
# 登录到 tomcat 容器
[root@k8s-master01 volumes]# kubectl exec -it test-hostpath -c test-tomcat -- bash
root@test-hostpath:/usr/local/tomcat# cd /test-tomcat/
root@test-hostpath:/test-tomcat# ls
1.txt 2.txt
通过上面测试可以看到, 同一个 pod 里的 test nginx 和 test tomcat 这两个容器是共享存储卷
的 。
# 删除 pod ,并使其调度到 node1
[root@k8s-master01 volumes]# vim hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
spec:
nodeName: k8s-node1 # 调度到 node1
containers:
[root@k8s-master01 volumes]# kubectl delete -f hostpath.yaml
pod "test-hostpath" deleted
[root@k8s-master01 volumes]# kubectl apply -f hostpath.yaml
pod/test-hostpath created
[root@k8s-master01 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-hostpath 2/2 Running 0 2m42s 10.244.36.67 k8s-node1 <none> <none>
重新进入两个容器内部,会发现原来的(数据)两个文件没有了,本地 node1 节点挂载目录下也没有数据,只有把 pod 重新调度到 node2 节点数据才能恢复!
hostpath 存储卷缺点:单节点,pod 删除之后重新创建必须调度到同一个 node 节点,数据才不会丢失。
官方参考文档:卷 | Kubernetes
三、k8s 持久化存储:nfs
NFS:网络文件系统,英文 Network File System(NFS) NFS),是由 SUN 公司研制的 UNIX 表示层 协议(presentation layer protocol),能使使用者访问网络上别处的文件就像在使用自己的计算机一样。
在 k8s 中,nfs
卷能将 NFS (网络文件系统) 挂载到你的 Pod 中。 不像 emptyDir
那样会在删除 Pod 的同时也会被删除,nfs
卷的内容在删除 Pod 时会被保存,卷只是被卸载。 这意味着 nfs
卷可以被预先填充数据,并且这些数据可以在 Pod 之间共享。
3.1 搭建 nfs 服务
#1. 搭建 nfs 服务。所有节点都安装 nfs,以 k8s 的控制节点作为 NFS 服务端,工作节点为客户端
yum install -y nfs-utils
#2. 在宿主机创建 NFS 需要的共享目录
[root@k8s-master01 ~]# mkdir /data/volumes -pv
#3. 所有节点启动 nfs 并设置开机自启
systemctl enable nfs --now
#4. 配置 nfs 共享服务器上的 /data/volumes 目录
[root@k8s-master01 ~]# vim /etc/exports
/data/volumes *(rw,no_root_squash)
# * :所有客户端都可以访问
# rw:该主机对该共享目录有读写权限
# no_root_squash:登入 NFS 主机使用分享目录的使用者,如果是 root 的话,那么对于这个分享的目录来说,他就具有 root 的权限
#5. 使 NFS 配置生效
[root@k8s-master01 ~]# exportfs -arv
exporting *:/data/volumes
#6. 在 node1 上手动挂载试试
[root@k8s-node1 ~]# mkdir /test
# 控制节点的宿主机 ip
[root@k8s-node1 ~]# mount 192.168.78.133:/data/volumes /test/
# 说明 nfs 搭建成功
[root@k8s-node1 ~]# df -Th |grep nfs
192.168.78.133:/data/volumes nfs4 27G 7.9G 20G 29% /test
# 卸载目录
[root@k8s-node1 ~]# umount /test
[root@k8s-node1 ~]# df -Th |grep nfs
3.2 创建Pod,挂载 NFS 共享出来的目录
# 查看帮助命令
[root@k8s-master01 ~]# kubectl explain deployment
[root@k8s-master01 ~]# kubectl explain deployment.spec
[root@k8s-master01 ~]# kubectl explain deployment.spec.selector
[root@k8s-master01 ~]# kubectl explain deployment.spec.template
[root@k8s-master01 ~]# kubectl explain deployment.spec.template.spec
[root@k8s-master01 ~]# kubectl explain deployment.spec.template.spec.containers
[root@k8s-master01 ~]# kubectl explain deployment.spec.template.spec.containers.ports
[root@k8s-master01 ~]# kubectl explain deployment.spec.template.spec.volumes
[root@k8s-master01 ~]# kubectl explain deployment.spec.template.spec.volumes.nfs
[root@k8s-master01 volumes]# vim nfs.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-test
spec:
replicas: 3
selector:
matchLabels:
cunchu: nfs
template:
metadata:
labels:
cunchu: nfs
spec:
containers:
- name: test-nfs
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
protocol: TCP
volumeMounts:
- name: nfs-volumes
mountPath: /usr/share/nginx/html
volumes:
- name: nfs-volumes
nfs:
path: /data/volumes
server: 192.168.78.133
# 删除前面创建的 pod
[root@k8s-master01 volumes]# kubectl delete -f hostpath.yaml
pod "test-hostpath" deleted
# 更新资源清单文件
[root@k8s-master01 volumes]# kubectl apply -f nfs.yaml
deployment.apps/nfs-test created
# 查看 pod 信息
[root@k8s-master01 volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-test-6bcdf5f5d6-4g7fk 1/1 Running 0 65s 10.244.169.161 k8s-node2 <none> <none>
nfs-test-6bcdf5f5d6-g5lsj 1/1 Running 0 65s 10.244.169.162 k8s-node2 <none> <none>
nfs-test-6bcdf5f5d6-hfwqc 1/1 Running 0 65s 10.244.36.74 k8s-node1 <none> <none>
3.3 测试 pod 挂载 nfs 是否成功
# 登录到 nfs 服务器,在共享目录创建一个 index.html
[root@k8s-master01 volumes]# cd /data/volumes/
[root@k8s-master01 volumes]# vim index.html
hello sky
# 请求任意 pod,查看结果
[root@k8s-master01 ~]# curl 10.244.169.161
hello sky
# 通过上面可以看到,在共享目录创建的 index.html 已经被 pod 挂载了
# 登录到 pod 验证下
[root@k8s-master01 volumes]# kubectl exec -it nfs-test-6bcdf5f5d6-4g7fk -- bash
root@nfs-test-6bcdf5f5d6-4g7fk:/# cat /usr/share/nginx/html/index.html
hello sky
上面说明挂载 nfs 存储卷成功了,nfs 支持多个客户端挂载,可以创建多个 pod,挂载同一个nfs 服务器共享出来的目录;但是 nfs 如果宕机了,数据也就丢失了,所以需要使用分布式存储,常见的分布式存储有 glusterfs 和 cephfs(后面会讲到)。
pod 挂载 nfs 官方参考文档:卷 | Kubernetes
上一篇文章:【云原生 | Kubernetes 实战】12、K8s 四层代理 Service 入门到企业实战应用(下)_Stars.Sky的博客-CSDN博客