说起存储卷和docker的存储卷有几分相似的地方,数据不会跟随Pod的停止或删除而消失,从而实现数据的持久性,但是由于K8s的独特,K8s面对的是集群,如果要实现数据的持久性,Pod会分布到各个节点之上,所以引入了外部存储卷。
① · 常见的存储卷类型有:
- emptyDir :当Pod生命周期结束后,存储卷会被一并删除,这种通常会存放一些临时数据。
- hostPath:宿主机目录映射
- 本地的SAN(iSCSI,FC)、NAS(nfs,cifs,http)存储
- 分布式存储(glusterfs,rbd,cephfs)
- 云存储(EBS,Azure Disk)
种类繁多的存储无疑会提高K8s的使用门槛,这意味着你不仅要懂K8s还要懂存储的结构、用法、参数、使用场景等等等...
所以K8s又引入了一个概念叫做PVC 全称 persistentVolumeClaim -->PVC(存储卷创建申请)
当你需要一个存储空间的时候,只要进行对应的申请即可,灵魂图: ↓
在Pod 上定义一个PVC,但该PVC只是一个申请,他需要和PV进行关联,PV是属于存储设备上的一部分空间,so申请之前我们应该创建好对应大小的pv等待使用,那么就造成了每次用户需要存储卷的时候都要想K8s的管理员申请,等管理员建立好他才能进行PVC的申请,这听起来比较麻烦,于是又有了另一个方案。
不要pv层,把所有存储资源抽象成一个存储类,当用户申请PVC到达存储类的时候,会根据申请大小,自动创建出相应的存储空间,实现动态供给。
emptydir类型示例:
emptydir具体操作步骤: ↓
① · 在Pod层定义volume,并指明关联到哪个存储设备
② · 在容器中层使用 volume mount 进行挂载
emptydir:
是一个临时的空目录,在pod之上的每个容器都可以挂载到相同或不同的目录上,并且共享里面的内容,当Pod因为任何原因被删除时,存储卷会被一并删除,无法保留数据。但是容器崩溃的时候,不会影响数据,因为一个容器崩溃不会导致Pod被删除。
默认情况下emptydir是一个普通磁盘提供的存储空间,但是也可以定义为memory,意为使用node的内存来提供存储功能,因为内存性能强大,但是要注意当node重启的时候,内存内的数据会丢失,emptydir的数据也会随之消失。
清单示例:
apiVersion: v1
kind: Pod
metadata:
name: Pod-demo
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts:
- name: html
mountPath: /data/
command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
volumes:
- name: html
emptydir: {}
上述清单定义了一个类型为emptydir的存储卷,并且创建了两个容器共同挂载,由后端的busybox不停的向目录中注入内容,通过从前端访问显示内容,实现两个容器之间的存储共享。
[root@k8s-master volumes]# kubectl apply -f pod-vol-demo.yaml
pod/pod-vol-demo created
[root@k8s-master volumes]# kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-vol-demo 2/2 Running 0 27s
[root@k8s-master volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
......
pod-vol-demo 2/2 Running 0 16s 10.244.2.34 k8s-node02
......
[root@k8s-master volumes]# curl 10.244.2.34 #访问验证
Tue Oct 9 03:56:53 UTC 2018
Tue Oct 9 03:56:55 UTC 2018
Tue Oct 9 03:56:57 UTC 2018
Tue Oct 9 03:56:59 UTC 2018
Tue Oct 9 03:57:01 UTC 2018
Tue Oct 9 03:57:03 UTC 2018
Tue Oct 9 03:57:05 UTC 2018
Tue Oct 9 03:57:07 UTC 2018
Tue Oct 9 03:57:09 UTC 2018
Tue Oct 9 03:57:11 UTC 2018
Tue Oct 9 03:57:13 UTC 2018
Tue Oct 9 03:57:15 UTC 2018
另外一种比较特殊类型的存储类型叫做gitrepo,就是利用github仓库作为外部持久存储,但是他的基础仍然是emptydir来实现的,并且要确保node之上有Git工具,因为这是通过node 来驱动的git,具体实现方式就是通过sidecar容器将gitrepo clone到容器上,然后不停的往GitHub之上push数据来实现。
hostPath类型示例:
hostPath是将宿主机上的某个目录与Pod中的容器建立关联关系,数据不属于container,所以当Pod生命周期结束的时候,数据不会丢失。但是当node节点发生故障的时候,数据也会丢失。
apiVersion: v1
kind: Pod
metadata:
name: pod-hostPath
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
volumeMonts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
hostPath:
path: /data/pod/volume1
type: DirectoryOrCreate
# type:
#DirectoryOrCreate 宿主机上不存在创建此目录
#Directory 必须存在挂载目录
#FileOrCreate 宿主机上不存在挂载文件就创建
#File 必须存在文件
在node节点上创建挂载目录
[root@k8s-node01 ~]# mkdir -p /data/pod/volume1
[root@k8s-node01 ~]# vim /data/pod/volume1/index.html
node01.magedu.com
[root@k8s-node02 ~]# mkdir -p /data/pod/volume1
[root@k8s-node02 ~]# vim /data/pod/volume1/index.html
node02.magedu.com
[root@k8s-master volumes]# kubectl apply -f pod-hostpath-vol.yaml
pod/pod-vol-hostpath created
(4)访问测试
[root@k8s-master volumes]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
......
pod-vol-hostpath 1/1 Running 0 37s 10.244.2.35 k8s-node02
......
[root@k8s-master volumes]# curl 10.244.2.35
node02.magedu.com
[root@k8s-master volumes]# kubectl delete -f pod-hostpath-vol.yaml #删除pod,再重建,验证是否依旧可以访问原来的内容
[root@k8s-master volumes]# kubectl apply -f pod-hostpath-vol.yaml
pod/pod-vol-hostpath created
[root@k8s-master volumes]# curl 10.244.2.37
node02.magedu.com
NFS类型示例:
NFS挂载是在其中一个node之上将共享的目录发布出来,并且在各个node之上都安装好nfs-utils工具,只要在创建Pod的时候指定要挂载的文件系统为nfs,和挂载点、权限即可自动完成挂载操作,并且能实现数据同步。
在创建Pod之前要做好nfs的配置
在stor01节点上安装nfs,并配置nfs服务
[root@stor01 ~]# yum install -y nfs-utils ## 192.168.56.14
[root@stor01 ~]# mkdir /data/volumes -pv
[root@stor01 ~]# vim /etc/exports
/data/volumes 192.168.56.0/24(rw,no_root_squash)
[root@stor01 ~]# systemctl start nfs
[root@stor01 ~]# showmount -e
Export list for stor01:
/data/volumes 192.168.56.0/24
在node2上测试连接,成功后即可创建Pod
[root@k8s-node02 ~]# yum install -y nfs-utils
[root@k8s-node02 ~]# mount -t nfs stor01:/data/volumes /mnt
[root@k8s-node02 ~]# mount
......
stor01:/data/volumes on /mnt type nfs4 (rw,relatime,vers=4.1,rsize=131072,wsize=131072,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=192.168.56.13,local_lock=none,addr=192.168.56.14)
[root@k8s-node02 ~]# umount /mnt/
清单示例:
apiVersion: v1
kind: Pod
metadata:
name: Pod-nfs
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
nfs:
path: /data/volumes # 共享出来的目录
server: stor01 #要提前做好解析