Volume 提供了很是好的数据持久化方案,不过在可管理性上还有不足。node
拿前面 AWS EBS 的例子来讲,要使用 Volume,Pod 必须事先知道以下信息:mysql
当前 Volume 来自 AWS EBS。sql
EBS Volume 已经提早建立,而且知道确切的 volume-id。数据库
Pod 一般是由应用的开发人员维护,而 Volume 则一般是由存储系统的管理员维护。开发人员要得到上面的信息:安全
要么询问管理员。服务器
要么本身就是管理员。app
这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一块儿了。若是系统规模较小或者对于开发环境这样的状况还能够接受。但当集群规模变大,特别是对于生成环境,考虑到效率和安全性,这就成了必需要解决的问题。ide
Kubernetes 给出的解决方案是 PersistentVolume 和 PersistentVolumeClaim。学习
PersistentVolume (PV) 是外部存储系统中的一块存储空间,由管理员建立和维护。与 Volume 同样,PV 具备持久性,生命周期独立于 Pod。spa
PersistentVolumeClaim (PVC) 是对 PV 的申请 (Claim)。PVC 一般由普通用户建立和维护。须要为 Pod 分配存储资源时,用户能够建立一个 PVC,指明存储资源的容量大小和访问模式(好比只读)等信息,Kubernetes 会查找并提供知足条件的 PV。
有了 PersistentVolumeClaim,用户只须要告诉 Kubernetes 须要什么样的存储资源,而没必要关心真正的空间从哪里分配,如何访问等底层细节信息。这些 Storage Provider 的底层信息交给管理员来处理,只有管理员才应该关心建立 PersistentVolume 的细节信息。
k8s-master nfs-server
k8s-node1 k8s-node2 nfs-client
全部节点安装nfs
yum install -y nfs-common nfs-utils
在master节点建立共享目录
[root@k8s-master k8s]# mkdir /nfsdata
受权共享目录
[root@k8s-master k8s]# chmod 666 /nfsdata
编辑exports文件
[root@k8s-master k8s]# cat /etc/exports /nfsdata *(rw,no_root_squash,no_all_squash,sync)
配置生效
[root@k8s-master k8s]# export -r
启动rpc和nfs(注意顺序)
[root@k8s-master k8s]# systemctl start rpcbind [root@k8s-master k8s]# systemctl start nfs
做为准备工做,咱们已经在 k8s-master 节点上搭建了一个 NFS 服务器,目录为 /nfsdata
:
下面建立一个 PV mypv1
,配置文件 nfs-pv1.yml
以下:
① capacity
指定 PV 的容量为 1G。
② accessModes
指定访问模式为 ReadWriteOnce
,支持的访问模式有:
ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
ReadWriteMany – PV 能以 read-write 模式 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
以下:
PVC 就很简单了,只须要指定 PV 的容量,访问模式和 class。
执行命令建立 mypvc1
:
从 kubectl get pvc
和 kubectl get pv
的输出能够看到 mypvc1
已经 Bound 到 mypv1
,申请成功。
上面已经建立好了pv和pvc,pod中直接使用这个pvc便可
与使用普通 Volume 的格式相似,在 volumes
中经过 persistentVolumeClaim
指定使用 mypvc1
申请的 Volume。
经过命令建立mypod1
:
可见,在 Pod 中建立的文件 /mydata/hello
确实已经保存到了 NFS 服务器目录 /nfsdata
中。
若是再也不须要使用 PV,可用删除 PVC 回收 PV。
当 PV 再也不须要时,可经过删除 PVC 回收。
未删除pvc以前 pv的状态是Bound
删除pvc以后pv的状态变为Available,,此时解除绑定后则能够被新的 PVC 申请。
/nfsdata文件中的文件被删除了
由于 PV 的回收策略设置为 Recycle
,因此数据会被清除,但这可能不是咱们想要的结果。若是咱们但愿保留数据,能够将策略设置为 Retain
。
经过 kubectl apply
更新 PV:
回收策略已经变为 Retain
,经过下面步骤验证其效果:
① 从新建立 mypvc1
。
② 在 mypv1
中建立文件 hello
。
③ mypv1
状态变为 Released
。
④ 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,而后经过 PVC 申请 PV 并在 Pod 中使用,这种方式叫作静态供给(Static Provision)。
与之对应的是动态供给(Dynamical Provision),即若是没有知足 PVC 条件的 PV,会动态建立 PV。相比静态供给,动态供给有明显的优点:不须要提早建立 PV,减小了管理员的工做量,效率高。
动态供给是经过 StorageClass 实现的,StorageClass 定义了如何建立 PV,下面是两个例子。
StorageClass standard
:
StorageClass slow
:
这两个 StorageClass 都会动态建立 AWS EBS,不一样在于 standard
建立的是 gp2
类型的 EBS,而 slow
建立的是 io1
类型的 EBS。不一样类型的 EBS 支持的参数可参考 AWS 官方文档。
StorageClass 支持 Delete
和 Retain
两种 reclaimPolicy
,默认是 Delete
。
与以前同样,PVC 在申请 PV 时,只须要指定 StorageClass 和容量以及访问模式,好比:
除了 AWS EBS,Kubernetes 支持其余多种动态供给 PV 的 Provisioner,完整列表请参考 https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner
下面演示如何为 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
:
kubectl run -it --rm --image=mysql:5.6 --restart=Never mysql-client -- mysql -h mysql -ppassword
更新数据库:
① 切换到数据库 mysql。
② 建立数据库表 my_id。
③ 插入一条数据。
④ 确认数据已经写入。
关闭 k8s-node2
,模拟节点宕机故障。
验证数据的一致性:
因为node2节点已经宕机,node1节点接管了这个任务。
经过kubectl run 命令 进入node1的这个pod里,查看数据是否依旧存在
MySQL 服务恢复,数据也无缺无损。
本章咱们讨论了 Kubernetes 如何管理存储资源。
emptyDir 和 hostPath 类型的 Volume 很方便,但可持久性不强,Kubernetes 支持多种外部存储系统的 Volume。
PV 和 PVC 分离了管理员和普通用户的职责,更适合生产环境。咱们还学习了如何经过 StorageClass 实现更高效的动态供给。
最后,咱们演示了如何在 MySQL 中使用 PersistentVolume 实现数据持久性。