您的位置:首页 > 其它

Kubernetes存储系统介绍及机制实现

2018-01-22 21:47 781 查看
本文分为三大部分。第一部分主要介绍Kubernetes中常用的几种存储,及其使用场景和生命周期等等。第二部分试图介绍一些设计原则和基本架构,并简要介绍各种存储plugin的实现机制及持久卷的一些特性,例如访问模式、回收策略等等。动态卷供给是一个Kubernetes独有的功能,这一功能允许按需创建存储卷,使管理员不必预先创建存储卷,而是随用户需求进行创建。第三部分会介绍一下v1.9中存储的一些新特性。

一、Kubernetes中存储的应用场景

在Kubernetes中部署和运行的服务大致分为:

1. 无状态服务

Kubernetes使用ReplicaSet来保证一个服务的实例数量,如果说某个Pod实例由于某种原因挂掉或崩溃,ReplicaSet会立刻用这个Pod的模版新启一个Pod来替代它。由于是无状态的服务,新Pod与旧Pod一模一样。此外Kubernetes通过Service(一个Service后面可以挂多个Pod)对外提供一个稳定的访问接口,实现服务的高可用。

2. 普通有状态服务

和无状态服务相比,它多了状态保存的需求。Kubernetes提供了以Volume和Persistent Volume为基础的存储系统,可以实现服务的状态保存。

3. 有状态集群服务

和普通有状态服务相比,它多了集群管理的需求。要运行有状态集群服务要解决的问题有两个,一个是状态保存,另一个是集群管理。Kubernetes为此开发了StatefulSet(以前叫做PetSet),方便有状态集群服务在Kubernetes上部署和管理。

简单来说是通过Init Container来做集群的初始化工作,用Headless Service来维持集群成员的稳定关系,用动态存储供给来方便集群扩容,最后用StatefulSet来综合管理整个集群。



分析以上的服务类型,Kubernetes中对于存储的使用主要集中在以下几个方面:

服务的基本配置文件读取、密码密钥管理等;

服务的存储状态、数据存取等;

不同服务或应用程序间共享数据。

二、Kubernetes中几种常见的存储系统

目前Kubernetes所支持的Volume Plugins如下表所示。



Kubernetes已经提供非常丰富的Volume和Persistent Volume插件,大家可以根据自己业务的需要,使用这些插件给容器提供存储服务。每一种Plugin的使用方法和注意事项在此不做赘述,请参考Kubernetes Volume 的官方文档[1]。

容器存储接口(Container Storage Interface,CSI[2])是一项跨行业标准倡议,旨在降低云原生存储开发工作的门槛,从而进一步确保兼容性水平。Kubernetes v1.9已经引入了CSI的一套alpha实现版本,将新分卷插件的安装流程简化至与安装pod相当,并允许第三方存储供应商在无需接触核心Kubernetes代码库的前提下开发自己的解决方案。

如果上述的这些Plugin不满足业务要求, 你可以通过以下两种途径进行二次开发。

可以使用FlexVolume实现自己的Volume插件。此Plugin仍是alpha版本,后向兼容性需要考虑。具体方法在此不做赘述,参考FlexVolume的社区文档[3]。

推荐使用CSI。目前还只是alpha版本,使用时需要在feature-gate中enable,不推荐在production环境中使用。v1.9已经把CSI作为in-tree plugin,把out-off-tree volume插件的开发从 Kubernetes 中脱离出来,极大地方便了插件的开发、维护和集成。如何使用CSI,可参考How to Use Kubernetes 1.9.0 with CSI[4]。

三、Kubernetes存储的设计与基本架构

Kubernete存储在设计的时候遵循着Kubernetes的一贯哲学,即声明式(Declarative)架构。同时为了尽可能多地兼容各种存储平台,Kubernetes以in-tree plugin的形式来对接不同的存储系统,满足用户可以根据自己业务的需要使用这些插件给容器提供存储服务。同时兼容用户使用FlexVolume和CSI定制化插件。相比较于Docker Volume,支持的存储功能更加丰富和多样。



Kubernetes中mount 一个PV的基本过程包括:

用户通过API创建一个包含PVC的Pod;

Scheduler把这个Pod分配到某个节点,比如Node1;

Node1上的Kubelet开始等待Volume Manager准备device;

PV controller调用相应Volume Plugin(in-tree或者out-of-tree),创建PV,并在系统中与对应的PVC绑定;

Attach/Detach controller或者Volume Manager通过Volume Plugin实现device挂载(Attach);

Volume Manager等待device挂载完成后,将卷挂载到节点指定目录(mount), 比如/var/lib/kubelet/pods/xxxxxxxxxxx/volumes/aws-ebs/vol-xxxxxxxxxxxxxxxxx;

Node1上的Kubelet此时被告知volume已经准备好后,开始启动Pod,通过volume mapping将PV已经挂载到相应的容器中去。



其实对于Kubernetes中大部分的Volume Plugin来说,mount的过程遵循着如下的规则:

/some/global/mount/path -> /var/lib/kubelet/pods/<pod uid>/volumes/<volume plugin>/<volume name>/ -> container volume


这种方式的好处相当于热插拔,一旦Pod挂掉,kubelet可以马上重启,并快速mount volume,不会出现类似于device busy的情形。

但是对于hostpath这个Plugin而言,直接就是
/some/global/mount/path -> container volume


四、Persistent Volume与Persistent Volume Claim

一个运行中的容器,缺省情况下,对文件系统的写入,都是发生在其分层文件系统的可写层的(Copy-on-Write)。当迁移的应用程序从开发到生产环境时候,开发人员面临着巨大的挑战。当容器挂掉、崩溃或运行结束时,任何与之相关的数据都会丢失。为了解决这个问题引发的数据丢失,我们需要将数据存储持久化,也可以称为Persistent Volume。

Kubernetes使用两种资源管理存储:

PersistentVolume(简称PV):由管理员添加的的一个存储的描述,是一个全局资源,包含存储的类型,存储的大小和访问模式等。它的生命周期独立于Pod,例如当使用它的Pod销毁时对PV没有影响。

PersistentVolumeClaim(简称PVC):是Namespace里的资源,描述对PV的一个请求。请求信息包含存储大小,访问模式等。

Kubernetes中的Volume则是基于Docker进行扩展,使用Docker Volume挂载宿主机上的文件目录到容器中。

一般来说,Kubernetes中Pod通过如下三种方式来访问存储资源。

直接访问



该种方式移植性较差,可扩展能力差,把Volume的基本信息完全暴露给用户,有严重的安全隐患,同时需要协调不同users对Volume的访问。

静态provision



动态provision



StorageClass将说明Volume将由哪种Volume Plugin创建、创建时参数以及从其他功能性/非功能性角度描述的后台volume的各种参数。一般为storage cluster的一些配置信息,以及label注释信息。



一般来说,PV和PVC的生命周期分为5个阶段:

Provisioning,即PV的创建,可以直接创建PV(静态方式),也可以使用StorageClass动态创建

Binding,将PV分配给PVC

Using,Pod通过PVC使用该Volume

Releasing,Pod释放Volume并删除PVC

Reclaiming,回收PV,可以保留PV以便下次使用,也可以直接从云存储中删除



根据这5个阶段,Volume的状态有以下4种:

Available:可用

Bound:已经分配给PVC

Released:PVC解绑但还未执行回收策略

Failed:发生错误

五、v1.9中对存储做了哪些更改

引入了CSI alpha版本的实现,可见第二部分关于CSI的介绍。

修复Bug:删除运行状态container的PVC

这个bug会导致数据丢失。社区的解决办法是引入一个Finalizer来保护PVC。

详细的步骤请参考相关的Proposal[5]及其代码实现[6]。

简单来说,这个Fianlizer类似于垃圾回收(GC)里面的指针计数,当这个使用这个PVC的POD都被删除(deleted)或处于完成状态(completed)时,才可以删除这个PVC。从而避免了删除正在运行中的container的PVC,从而引发数据丢失。

Q&A

Q:Kubernetes和Cloud Foundry有什么区别,优势在什么地方?

A:Cloud Foundry更像是Application PaaS,Kubernetes主要是Container PaaS。CF不会直接把container层暴露给用户,Kubernetes则不然,你可以直接访问container。个人觉得kubernetes的部署和使用更简单,更直接,操作起来也更方便。

Q:请问对于Galera Cluster的集群存储如何设计存储方案,CSI有考虑有状态储存的解决方案吗?

A:对于有状态服务,请使用StatefulSet来部署你的应用。Volume只是一个存储的地方。StatefulSet会负责给Pod设置顺序等等,保证是有序的,优雅的删除停止和扩展。

Q:有没有对象存储,比如Ceph RGW,在Kubernetes集群中的使用案例,比如用户通过客户端上传、下载PVC中的数据之类的?

A:有试过RGW来存储数据,但是性能不是很好,速度要慢很多。在Kubernetes集群中可以使用RGW来存储一些静态的文件,比如配置文件,Nginx静态html文件之类,用户也可以下载PV中的数据。不建议对RGW中的数据进行频繁的更改。

Q:能否详细说下CSI?

A:CSI 在kubernetes v1.9才引入。这部分内容比较多,可以去看看CSI文档[2],以及Kubernetes官方的介绍[7],以及这个feature实现代码[8]。

Q:RBD用什么插件,有没有什么坑?

A:需要在kubelet节点上安装ceph-common这个包,在volume mount的时候,会调用相关的命令。基本上没什么坑,RBD提供的volume还是很好使的。

Q:存储这块IO性能下降大概多少呢,有实测过吗?

A:存储的性能与Cluster的能力、存储的类型有很大关系。实测过RBD的IO性能,当然case by case,当时测出来的结果还是很不错的,相比较与CephFS、GlusterFS。

Q:多个Pod共享一个Nas,是否可行,需要注意什么?

A:可行,但是需要注意Volume的读写权限,这个可以通过mount时候的PV的access mode进行设置,比如ReadWrite、ReadWriteOnce等等。

Q:CSI和社区孵化的volume provisioner有什么区别?

A:CSI的主要目的还是为了给容器存储定义一个统一的接口,方便进行定制化,以及新功能添加。社区孵化的volume provisioner,你指的应该是external-storage这个项目吧,这个项目的主要目的是为了方便对in-tree的那些Plugin进行修改和定制,这样可以独立地进行更新。

Q:请问你现在有把MySQL可以放进PV里面么?求介绍这方面的经验。

A:如果只是单节点的MySQL,直接放进PV就好了,跟其它正常服务一样。对于多节点的MySQL Cluster,在部署的时候就需要注意了,建议部署成StatefulSet,有状态的服务。之前有试过用Galera Cluster For MySQL来部署集群,发现效果不是很好,尤其是在随意启停Pod的时候,Cluster的没办法自组成新的集群,新节点也无法加入集群。你可以再次试验下,确认一下。

后来使用MySQL Cluster CGE,效果很好,Cluster能够及时回复并重新组织起来。

相关链接:

https://kubernetes.io/docs/concepts/storage/volumes/

https://github.com/container-storage-interface

https://github.com/kubernetes/community/blob/master/contributors/devel/flexvolume.md

https://blog.thecodeteam.com/2017/12/19/use-kubernetes-1-9-0-csi/

https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/postpone-pvc-deletion-if-used-in-a-pod.md

https://github.com/kubernetes/kubernetes/pull/55824

http://blog.kubernetes.io/2018/01/introducing-container-storage-interface.html

https://github.com/kubernetes/kubernetes/pull/54529

转载自 Docker 微信公众号。作者:徐迪。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: