kubernetes volume
介绍
在学习docker时,学习了如何将宿主机上的文件系统挂载到容器当中,实现持久化存储,以及多个容器共享同一个文件目录.
在k8s中,我们也希望pod容器中的数据能够持久化存储.当一个容器因为故障或者其他原因需要删除时,我们希望新的容器能够在上一个容器结束的位置继续运行.
但是和docker一样,容器默认情况下删除后,所有该容器产生的数据都会消失.并且,虽然容器和宿主机共享CPU,网络,内存等资源,但是并不会共享文件存储.甚至同一个Pod中每个容器都有自己独立的文件系统,彼此互相隔离.
和docker容器一样,这就需要有一种存储卷能够挂载到Pod容器中,并脱离Pod的生命周期之外,将容器运行产生的数据保存在宿主机或者独立的外部存储卷中
存储卷类型
- emptyDir——-用于存储容器临时数据的空目录
emptyDir类型的存储卷和pod容器的生命周期相关联当pod容器删除时,emtpyDir卷的数据就会丢失
- hostPath——–和docker类似,将宿主机的某个目录挂载到pod容器.
但是本地节点运行的Pod容器和其他节点服务器上的同一组pod容器之间无法共享数据.只能本地持久化,无法实现集群存储
- nfs,iscsi,FC SAN——-网络存储
网络存储设备,挂载一个独立的第三方存储设备
AWS EBK,Azure Disk等—— 云厂商虚拟存储
cephfs,glusterfs等—– 分布式集群存储
使用
kubectl explain pods.spec.volumes
命令可以查看k8s支持的许多存储卷类型
一. emptyDir卷
为了演示emtpyDir卷,现在创建2个简单的pod容器:
nginx-alpine容器.
fortune容器定期输出字符串到/var/hotdocs/index.html文件下.然后Nginx容器展示.
这2个容器需要共享同一个目录.
1 | #furtune容器镜像主要是运行一个while循环脚本,该脚本每隔10秒随机想/var/htdocs/index.html文件写入一段名人名言 |
使用kubectl explain pod.volumes
命令可以查看k8s支持哪些存储卷类型
在pod定义的sepc.containers.volumeMounts字段中详细介绍了挂载磁盘卷的配置参数.
使用命令 kubectl explian pod.spec.containers.volumeMounts
可以看到支持以下主要挂载参数
1 | [root@k8s-master ~]# kubectl explain pod.spec.containers.volumeMounts |
为了演示实验是否正常,同时复习之前学到的replicaSet和Service对象,我们来创建一个rs,和svc对象
1. 创建replicaSet对象.包含一个副本,以及上面配置的2个pod容器
1 | apiVersion: apps/v1 |
pod包含2个容器,他们挂载同一个公用的存储卷,当html-generator容器启动时,每10秒启动一次fortune命令输出到/var/htdocs/index.html文件中,因为卷同时也被web-server容器挂载,所以后者能访问到html-generator容器生成的数据
如果要将emptyDir卷存储在内存上而非磁盘,可以声明medium配置如下配置:
1 | volumes: |
2.为此ReplicaSet创建一个Service对象.内容如下
1 |
|
3.分别创建svc和rs对象
1 | kubectl create -f fortune-rs.yaml |
4.查看资源
1 | [root@k8s-master ~]# kubectl get rs |
5.访问Service
1 | [work@k8s-node1 ~]$ curl http://10.96.123.110 |
可以看到,每10秒钟访问的内容不一样
二 .hostPath卷
hostPath卷可以实现持久性存储,如果删除了一个Pod,并且新的pod使用了相同的主机路径的hostPath卷,则新pod会发现上一个pod留下来的数据,但是前提是必须和前一个pod是同一个节点
这也解释了为什么使用hostPath卷不是一个好主意,因为当Pod被调度到另外一个节点上时,会找不到数据.
三.NFS卷
NFS卷可以实现多个节点之间共享存储.但是生产中不建议这样做,因为NFS共享存储传输效率低,稳定性和安全性不高.
仍然使用上面的例子
1 | [root@k8s-master ~]# cp fortune-svc.yaml fortune-nfs-svc.yaml |
修改各资源的标签,和rs配置文件中的卷信息:
1 | apiVersion: apps/v1 |
启动rs后,在nfs服务器上已经看到pod写入的数据:
1 | [work@idc-beta-cron ~]$ cat /data/apps/k8s/index.html |
PV和PVC
PV和PVC用于kubenetes将存储和pod解耦,存储管理人员配置好PV,然后开发人员只需要声明需要多大的存储卷(pvc)即可,无需关系底层的存储实现方式.
实现逻辑大致如下:
1.存储管理员配置底层存储方案(NFS,SAN,FC SAN,ceph等)
2.k8s集群管理员创建一个PV(Psersistent volume,持久卷)
3.开发人员(或者用户)创建一个PVC(Persistent volume claim,持久卷声明),将PVC和PV绑定
4.开发人员(或者用户)在pod中引用PVC
下面用NFS底层存储来演示PV和PVC的工作过程
1.创建PV
1 | apiVersion: v1 |
- accessModes支持ReadWriteOnce ,ReadOnlyMany ,ReadWriteMany
可以直接使用RWO,ROM,RWM缩写.
PersistentVolumeReclaimPolicy回收策略支持:
- Retain: PV一直保留,直到管理员手动回收
- Recycle: 清除PV中的数据
- Delete: 清除存储上的资源
storageClassName: PV的类型
1 | [root@k8s-master ~]# kubectl create -f nfs-pv.yaml |
2.持久卷声明(PVC)
1 | apiVersion: v1 |
创建PVC
1 | [root@k8s-master ~]# kubectl create -f nfs-pvc.yaml |
default/mypvc1 表示default命名空间的PVC
Status的Bound表示PV和PVC已经成功绑定
持久卷PV不属于任何名称空间,但是PVC和pod有名称空间概念.PV可以被所有名称空间下的PVC绑定.
3.创建pod.在pod中调用刚才创建的PVC
1 | apiVersion: apps/v1 |
和empty dir以及Hostpath类似,在引用pvc的时候只是修改一下卷类型.引用mypvc1这个刚才创建的pvc
创建pod
1 | [root@k8s-master ~]# kubectl create -f fortune-nfs-pvc.yaml |
4.验证
在nfs服务器上的共享目录/data/k8s上确实看到了Pod容器写入的数据
1 | [work@idc-beta-docker ~]$ ll /data/k8s/ |
pv的手动回收
手动删除Pod,pvc
1 | [root@k8s-master ~]# kubectl delete pvc mypvc1 |
删除pvc后,pv是Released状态,不可绑定PVC.删除PV,然后重新创建.
1 | [root@k8s-master ~]# kubectl delete pv mypv1 |
删除PV卷,并不会删除存储卷中的数据
重新创建PV.存储卷中的数据仍然存在,并且PV的状态为Available
1 |
|
PV自动回收
在pv的配置中修改如下字段
1 | persistentVolumeReclaimPolicy: Recycle |
创建PV.Reclaim policy是Recycle
1 |
|
创建PVC,绑定到PV,并且创建pod
1 | [root@k8s-master ~]# kubectl create -f nfs-pvc.yaml |
nfs底层存储卷上数据已经更新
1 | [work@idc-beta-docker ~]$ cat /data/k8s/index.html |
删除Pod,pvc
1 | [root@k8s-master ~]# kubectl delete pvc mypvc1 |
再次查看PV发现状态又变成了Available
1 | [root@k8s-master ~]# kubectl get pv |
NFS不支持delete回收策略,所以就不演示