今天我们来了解一下数据持久化的问题。

一、volume

本节我们讨论Kubernetes的存储模型Volume, 学习如何将各种持久化存储映射到容器。
我们经常会说: 容器和Pod是短暂的。 其含义是它们的生命周期可能很短, 会被频繁地销毁和创建。 容器销毁时, 保存在容器内部 文件系统中的数据都会被清除。

为了持久化保存容器的数据, 可以使用Kubernetes Volume。

Volume的生命周期独立于容器, Pod中的容器可能被销毁和重建, 但Volume会被保留。

本质上, Kubernetes Volume是一个目录, 这一点与Docker Volume类似。 当Volume被mount到Pod, Pod中的所有容器都可以访问这个Volume。 Kubernetes Volume也支持多种backend类型, 包括emptyDir、 hostPath、 GCE Persistent Disk、 AWS Elastic Block Store、NFS、 Ceph等。

1.emptyDir

emptyDir Volume对于容器来说是持久的,对于Pod则不是。当Pod从节点删除时, Volume的内容也会被删除。但如果只是容器被销毁而Pod还在, 则Volume不受影响。也就是说: emptyDir Volume的生命周期与Pod一致。

模拟一下producer-consumer场景,它们共享了一个Volume,producer负责写,consumer负责读。

怎么给k8s容器内传文件 k8s复制文件到容器_怎么给k8s容器内传文件

  1. 文件最底部volumes定义了一个emptyDir类型的Volume shared-volume。
  2. producer容器将shared-volume mount到/producer_dir目录。
  3. producer通过echo将数据写到文件hello里。
  4. consumer容器将shared-volume mount到/consumer_dir目录。
  5. consumer通过cat从文件hello读数据。
  6. mountPath指在容器中的挂载点
    实现在share-volume读写数据的效果

    在node1上查询容器的名字

    分别查询它们的mount
    k8s_consumer_producer-consumer_default_425531ec-7f6c-4764-a99a-00732692e2e6_0

    k8s_producer_producer-consumer_default_425531ec-7f6c-4764-a99a-00732692e2e6_0

    果然是挂载同一个目录下。

emptyDir是Host上创建的临时目录, 其优点是能够方便地为Pod中的容器提供共享存储, 不需要额外的配置。 它不具备持久性, 如果Pod不存在了, emptyDir也就没有了。 根据这个特性, emptyDir特别适合Pod中的容器需要临时共享存储空间的场景, 比如前面的生产者消费者用例。

二、hostPath

hostPath Volume的作用是将Docker Host文件系统中已经存在的目录mount给Pod的容器。 大部分应用都不会使用hostPath Volume, 因为这实际上增加了Pod与节点的耦合, 限制了Pod的使用。 不过那些需要访问Kubernetes或Docker内部数据(配置文件和二进制库) 的应用则需要使用hostPath。

如果Pod被销毁了, hostPath对应的目录还是会被保留, 从这一点来看, hostPath的持久性比emptyDir强。 不过一旦Host崩溃, hostPath也就无法访问了。

三、外部storage provider

这里我们用阿里云的服务器来作为我们的storage provider,接着来说一下怎么挂载的。我们使用的是nfs实现k8s数据持久化
服务器端:
先创建一个目录作为共享文件目录:

mkdir -p /usr/local/kubernetes/volumes

给目录增加读写权限

chmod a+rw /usr/local/kubernetes/volumes

安装nfs服务端

apt-get update 
apt-get install -y nfs-kernel-server

配置nfs服务目录,打开

vi /etc/exports

在尾部新增一行

/usr/local/kubernetes/volumes *(**insecure**,rw,sync,no_subtree_check)

这里加入insecure是因为使用了大于1024的端口进行传输,接着查询rpc的端口

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_02


搞定后就重启服务

/etc/init.d/nfs-kernel-server restart

使用shoumount测试

showmount -e 服务器ip

客户端:(需要在所有节点都安装)

apt-get install -y nfs-common

创建nfs客户端挂载目录

mkdir -p /usr/local/kubernetes/volumes-mount

将服务器的目录挂载到nfs客户端上

sudo mount 服务器ip:/nfs/data /usr/local/kubernetes/volumes-mount

怎么给k8s容器内传文件 k8s复制文件到容器_Pod_03


怎么给k8s容器内传文件 k8s复制文件到容器_Pod_04


怎么给k8s容器内传文件 k8s复制文件到容器_Pod_05


可以看到所有的节点已经挂载成功。

四、持久化volume

1、实现存储持久化
PersistentVolume(PV) 是外部存储系统中的一块存储空间, 由管理员创建和维护。 与Volume一样, PV具有持久性, 生命周期独立于Pod。
PersistentVolumeClaim(PVC) 是对PV的申请(Claim) 。 PVC通常由普通用户创建和维护。 需要为Pod分配存储资源时, 用户可以创建一个PVC, 指明存储资源的容量大小和访问模式(比如只读) 等信息, Kubernetes会查找并提供满足条件的PV。
有了PersistentVolumeClaim, 用户只需要告诉Kubernetes需要什么样的存储资源, 而不必关心真正的空间从哪里分配、 如何访问等底层细节信息。 这些Storage Provider的底层信息交给管理员来处理, 只有管理员才应该关心创建PersistentVolume的细节信息。(对用户透明,分配的事情交给k8s

书上使用的是在master-node上创建挂载盘,所以得当它是服务器,操作如上面写到的。
搞定后检查一下挂载情况,输入

showmount -e

怎么给k8s容器内传文件 k8s复制文件到容器_怎么给k8s容器内传文件_06


ok!

然后创建一个pv的yml文件,内容如下:

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_07


里面的参数含义:

  • capacity:指定PV的容量为1GB。
  • accessModes:指定访问模式为ReadWriteOnce, 支持的访问模式有3种: ReadWriteOnce表示PV能以read-write模式mount到单个节点,ReadOnlyMany表示PV能以read-only模式mount到多个节点,ReadWriteMany表示PV能以read-write模式mount到多个节点。
  • persistentVolumeReclaimPolicy:指定当PV的回收策略为Recycle, 支持的策略有3种: 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。
  • path:指定PV在NFS服务器上对应的目录。(path建立后记得给读写权限!!!!要不容器不能在里面读写)

检查一下pv的情况,输入

kubectl get pv

怎么给k8s容器内传文件 k8s复制文件到容器_Pod_08


ok!现在创建pvc mypvc1,配置yml文件

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_09


这里的storageClassName指申请pv的class,和pv文件中的storageClassName对应随后输入kubectl get pvckubectl get pv

怎么给k8s容器内传文件 k8s复制文件到容器_容器_10


可以看到在mypv1的claim一栏,已经有一个叫mypvc1的申请了空间。接着可以在pod中使用存储了,配置yml文件。

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_11


在volumes中指定挂载到刚才申请的mypvc1中。对pod进行操作,

怎么给k8s容器内传文件 k8s复制文件到容器_怎么给k8s容器内传文件_12


然后去server的pv检查一下

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_13


成功实现持久化2、回收pv

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_14


(这里发现好似不能删除,只能同时把pod一起给删掉,要不pvc的状态一直是terminating,如有误烦请指教~)(参考自https://zhuanlan.zhihu.com/p/68601257)

连pod一起删除后查询一下pv的情况

怎么给k8s容器内传文件 k8s复制文件到容器_容器_15


因为pv的回收策略是Recycle,所以数据会一起被清除;如果我们希望保留数据,可以设置策略为Retain。

修改yml文件后,查询pv的状态。

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_16


已经变成retain。现在进行测试新的回收策略是否生效:

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_17


在mypod1下创建一个文件夹

怎么给k8s容器内传文件 k8s复制文件到容器_kubernetes_18


持久化成功。接着进行删除pvc和pod,

怎么给k8s容器内传文件 k8s复制文件到容器_docker_19


一锅端后hello还在,说明策略有效。

三、数据库例子(书上说的常见例子)
三、数据库例子(常见例子)
本节演示如何为MySQL数据库提供持久化存储, 步骤为:

  1. 创建PV和PVC。
  2. 部署MySQL。
  3. 向MySQL添加数据。
  4. 模拟节点宕机故障, Kubernetes将MySQL自动迁移到其他节点。
  5. 验证数据一致性。

1.先创建pv和pvc(记得先创建挂载盘的文件夹)

怎么给k8s容器内传文件 k8s复制文件到容器_容器_20


怎么给k8s容器内传文件 k8s复制文件到容器_docker_21


检查一下pv和pvc的情况

怎么给k8s容器内传文件 k8s复制文件到容器_docker_22

哎mysql不知道为啥一直重启,没办法测试…先放着吧…以后再填坑…