- Volume
- 容器销毁时,保存在容器内部文件系统中的数据都会被清除,为了持久化保存容器的数据,可以使用kubernetes Volume
- volume的生命周期独立于容器,Pod中的容器可能被销毁和重建,但Volume会被保留
- 本质上,Kubernetes Volume是一个目录,当Volume被mount到Pod,Pod中的所有容器都可以访问这个Volume,Volume提供了对各种backend的抽象,容器在使用Volume读写数据时不需要关心数据到底是存在本地节点的文件系统还是云硬盘上,对他来说,所有类型的Volume都只是一个目录
- Kubernetes Volume支持多种backend类型,包括emptyDir, hostPath, GCE Persistent Disk, AWS Elastic Block Store, NFS, Ceph等
- emptyDir
-
emptyDir是最基础的Volume类型,一个emptyDir Volume是Host上的一个空目录
-
emptyDir Volume对于容器来说是持久的,对于Pod则不是,当Pod从节点删除时,Volume的内容也会被删除,但如果只是容器被销毁而Pod还在,则Volume不受影响,也就是说emptyDir Volume的生命周期与Pod一致
-
Pod中的所有容器都可以共享Volume,他们可以指定各自的mount路径,
-
配置解析:
- 模拟了一个producer-consumer场景,Pod有两个容器producer和consumer,他们共享一个Volume,producer负责往Volume中写数据,consumer则是从Volume读取数据
- 文件底部Volume定义了一个emptyDir类型的Volume shared-volume
- producer容器将shared-volume mount到/producer_dir目录
- producer通过echo将数据写到文件hello中
- consumer容器将shared-volume mount到/consumer_dir目录
- consumer通过cat从文件hello读取数据
-
执行命令创建Pod
- kubectl logs显示容器consumer成功读到了producer写入的数据,验证了两个容器共享emptyDSir Volume
-
因为emptyDir是Docker Host文件系统里的目录,其效果相当于执行了docker run -v/producer_dir 和 docker run -v /consumer_dir 。通过docker inspect 查看容器的详细配置信息,可以看到两个容器都mount了同一个目录
- 这里的var/lib/kubelet/pods/3e6100eb-a97a-11e7-8f72-0800274451ad/volumes/kubernetes.io~empty-dir/shared-volume就是emptyDir在Host上的真正路径
-
emptyDir是Host上创建的临时目录,其优点是能够方便地为Pod中的容器提供共享存储,不需要额外的配置,他不具备持久性,如果pod不存在了,emptyDir也就没有了,根据这个特性,emptyDir特别适合Pod中的容器需要临时共享存储空间的场景,比如之前的生产者消费者
-
- hostPath
-
hostPath Volume的作用是将Docker Host文件系统中已经存在的目录mount给Pod的容器,
-
大部分应用都不会使用hostPath Volume,因为这实际上增加了Pod与节点的耦合,限制了Pod的使用
-
不过那些需要访问kubernetes或DSocker内部数据(配置文件和二进制库)的应用则需要使用hostPath。比如kube-apiserver和kube-controller-manager就是这样的应用,通过kubectl edit–namespace=kube-system pod kube-apiserver-k8s-master查看kube-apiserver Pod的配置
- 这里定义了三个hostPath:volume k8s,certs 和pki,分别对应的Host目录/etc/kubernetes, /etc/ssl/certs和/etc/pki
- 如果Pod被销毁了,hostPath对应的目录还是会被保留,从这一点看,hostPath的持久性比emptyDir强,不过一旦Host崩溃。hostPath也就无法访问了
-
外部Storage Provider
-
如果Kubernetes部署在诸如AWS,GCE,Azure等公有云上,可以直接使用云硬盘作为Volume,以AWS Elastic Block Store为例子:
- 要在Pod中使用ESB volume,必须先在AWS中创建,然后通过volume-id引用,
-
Kubernetes Volume也可以使用主流的分布式存储,比如Ceph,GlusterFS等,以Ceph为例:
-
Ceph文件系统的/some/path/in/side/cephfs目录被mount到容器路径/test-ceph,相对于emptyDir和hostPath,这些Volume类型的最大特点是不依赖Kubernetes,Volume的底层基础设施由独立的存储系统管理,与Kubernetes集群是分离的,数据被持久化后,即使整个Kubernetes崩溃也不会受损
-
-
PersistentVolume & PersistentVolumeClaim
-
PersistentVolume(PV)是外部存储系统中的一块存储空间,由管理员创建和维护,与Volume一样,PV具有持久性,生命周期独立于Pod
-
PersistentVolumeClaim(PVC)是对PV的申请(Claim),PVC通常由普通用户创建和维护,需要为Pod分配资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问模式(比如只读)等信息,Kubernetes会查找并提供满足条件的PV
-
有了PersistenVolumeClaim,用户只需要告诉Kubernetes需要什么样的存储资源,而不必关心真正的空间从哪里分配,如何访问等底层细节信息,这些Storage Provider的底层信息交给管理员来处理,只有管理员才应该关心创建PersistentVolume的细节信息
-
Kubernetes支持多种类型的PersistenVolume,比如AWS EBS, Ceph,NFS等,
-
NFS PersistentVolume
-
先做准备工作,在k8s-master节点上搭建一个NFS服务器,目录为/nfsdata
-
创建一个PV mypv1,配置文件为nfs-pv1.yml
- capacity指定PV的容量为1GB
- accessModes指定访问模式为ReadWriteOnce,支持的访问模式有三种,ReadWriteOnce表示PV能以read-write模式mount到单个节点,ReadOnlyMany表示PV能以read-only模式mount到多个节点
- persistentVolumeReclaimPolicy指定当PV的回收策略为Recycle,支持的策略有三种,Retain表示需要管理员手工回收,Recycle表示清除PV中的数据,效果相当于执行rm -rf/thevolume/*,Delete表示删除Storage Provider上的对应存储资源,例如AWS EBS, GCE PD, Azure Disk, OpenStack Cinder Volume等
- storageClassName指定PV的class为nfs,相当于为PV设置了一个分类,PVC可以指定class申请相应class的PV
- 指定PV在NFS服务器上对应的目录
-
创建mypv1
- status为available,表示mypv1就绪,可以被PVC申请
-
创建PVC mypvc1,配置文件为nfs-pvc1.yml,只需要指定PV的容量,访问模式和class即可
-
创建mypvc1,从kubectl get pvc 和kubectl get pv的输出,可以看到mypvc1已经bound到mypv1,申请成功
-
在pod中使用存储,Pod配置文件pod1.yml
-
与普通Volume的格式相似,在volumes中通过persistentVolumeClaim指定使用mypvc1申请的volume
-
验证PV是否可用,可见,在pod中创建的文件/mydata/hello已经保存到了NFS服务器目录/nfsdata/pv1中
-
-
回收PV
-
当不需要使用PV时,可删除PVC回收PV
-
当PVC mypvc1被删除后,发现kubernetes启动了一个新Pod recycler-for-mypv1,这个Pod的作用就是清除PV mypv1的数据,此时mypv1的状态Released,表示已经被解除了与mypvc1的bound,正在清除数据,不过此时还不可用,
-
当数据清除完毕,mypv1的状态重新变为Available,此时可以被新的PVC申请
-
/nfsdata/pv1中的hello文件已经被删除了,因为PV的回收策略设置为Recycle,所以数据会被清除,如果希望保留数据,可以将策略设置为Retain
-
通过kubectl apply更新PV
-
回收策略已经变为Retain
- 重新创建mypvc1
- 在mypv1中创建文件hello
- mypv1状态变为Released
- kubernetes并没有启动pod recycle-for-mypv1
- PV中的数据被完整保留
-
虽然mypv1中的数据得到了保留,但其PV状态会一直处于Released,不能被其他PVC申请,为了重新使用存储资源,可以删除并重新创建mypv1,删除操作只是删除了PV对象,存储空间中的数据并不会被删除
-
新建的mypv1状态为Available,可以被PVC申请
-
PV还支持Delete的回收策略,会删除PV在Storage Provider上对应的存储空间,NFS的PV不支持Delete,支持Delete的Provider有AWS EBS,GCE PD, Azure Disk, OpenStack Cinder Volume等
-
-
-
PV动态供给
- 在前面,提前创建了PV,然后通过PVC申请PV并在Pod中使用,这种方式叫做静态供给
- 与之对应的是动态供给,即如果没有满足PVC条件的PV,会动态创建PV,相比静态供给,动态供给有明显的优势,不需要提前创建PV
- 动态供给通过StorageClass实现,StorageClass定义了如何创建PV
-
StorageClass standard
-
StorageClass slow
-
这两个StorageClass都会动态创建AWS EBS,不同点在于standard创建的是gp2类型的EBS,而slow创建的是io1类型的EBS,
-
StorageClass支持Delete和Retain两种reclaimPolicy,默认是Delete
-
PVC在申请PV时,只需要指定StorageClass,容量以及访问模式即可
-
-
以数据库为例子:如何为mysql数据库提供持久化存储
- 创建PV和PVC
- 部署mysql
- 向mysql添加数据
- 模拟节点宕机故障,kubernetes将mysql自动迁移到其他节点
- 验证数据一致性
-
首先创建PV和PVC,配置文件为mysql-pv.yml
-
mysql-pvc.yml
-
创建mysql-pv和mysql-pvc
-
部署mysql,配置文件为
-
PVC mysql-pvc bound的PV mysql-pv将被mount到mysql的数据目录var/lib/mysql
-
mysql被部署到k8s-node2,通过客户端访问Service mysql:kuberctl run -it --rm --image=mysql:5.6 --restart=Never mysql-client – mysql-hmysql -ppassword
-
更新数据库
- 切换到数据库mysql
- 创建数据表my_id
- 插入一条记录
- 确认数据已经写入
-
关闭k8s-node2,模拟节点宕机故障
-
一段时间后,kubernetes将mysql迁移到k8s-node1
-
验证数据一致性
-
mysql服务恢复,数据也完好无损
-
-
-