探讨分享 - 容器与持久化存储

本文内容来源于3月28日有容云Docker技术交流群微信群分享活动,根据有容云技术实施团队原创分享内容整理而成。对Docker技术感兴趣、或对本文中细节需继续探讨的朋友,欢迎加入有容云Docker技术交流群参与讨论!(关注有容云微信公众号,回复“加群”)

 

分享主题

 

  • 容器正逐渐成为云上应用的标准部署单元,容器该如何解决持久化存储的需求?

  • 容器编排系统已成当红炸子鸡,在无状态的容器中,存储系统面临哪些新的挑战?

  • 容器与持久化存储系统是融合架构还是分离架构?

 

本次交流与大家围绕上述几个问题探讨容器和持久化存储相关知识。

 

容器对存储插件的定义

 

以Docker为例,Docker对存储卷定义了一组简单的接口,外部存储只要实现简单的接口便可以和外部存储对接。

 

 

Docker daemon和plugin daemon基于unix域套接字,使用Restful API进行通信,下面是详细的API:

 

  • Plugin.Activate :                    握手。

  • VolumeDriver.Create :           创建卷。

  • VolumeDriver.Mount :            挂载卷。

  • VolumeDriver.Path :               获取卷的路径。

  • VolumeDriver.Unmount :        卸载卷。

  • VolumeDriver.Remove :          删除卷。

  • VolumeDriver.List :                 获取volume列表。

  • VolumeDriver.Get :                 获取volume信息。

  • VolumeDriver.Capabilities :     获取volume属性。

 

从上面这组接口可以看出,Docker容器是通过mount的方式将外部存储挂载到本地目录,尽量使内部应用程序对存储是无感知的,应用程序就像使用本地目录一样使用外部存储卷,而将外部存储的管理交给存储Plugin负责(如Flocker、RancherConvoy,REX-Ray等)。

 

容器正逐渐成为云计算平台应用程序的标准部署单元,容器能轻易的将各式各样的应用程序及其runtime打包成统一的对象,于是编排调度系统能把各种应用程序当成统一的容器进行处理,大大简化编排调度系统的复杂度。结合Docker对存储插件的定义,不难看出Docker希望容器的运行环境独立而纯粹,不希望引入有状态和复杂的存储系统。

 

存储插件

 

Convoy作为一个Dockervolume plugin,支持不同的后端存储,为Docker提供MountPoint,也就是一个的目录,可能是挂载了后端存储、本地块设备或者就是本地目录。

 

Convoy的代码从结构、风格和使用的库,都与Docker十分相似,并且比Docker简单很多。在源码级别上值得留意的点,我感觉有两点。①插件式结构与Interface的运用。② 作者对事物的抽象能力与方法。

 

1、Convoy Daemon (Convoy/Daemon) 

 

Daemon是主要的功能模块,可以接收来自Convoy client和Docker的命令,对Backend存储进行了抽象,以便统一管理。下面先从Daemon的启动开始。

 

1.1Daemon进程启动

 

1)执行命令: convoy daemon --drivers glusterfs --driver-opts glusterfs.servers=192.168.0.3 --driver-opts glusterfs.defaultvolumepool=vol2

2)Convoy程序解析参数,获得Daemon子命令,调用到daemon.Start函数(convoy/daemon/daemon.go),Start函数中主要围绕Daemon Struct建立所需要环境和配置。

 

 

3)Driver初始化,优先从配置文件读取信息忽略命令行输入的参数,如果配置文件不存在则根据命令行参数初始化。

 

图2. Convoy配置文件内容

 

遍历DriverList,找到配置文件或命令行指定的Driver,执行初始化函数Init,并添加到Daemon.ConvoyDrivers中。

 

4)根据Convoy的工作目录的内容,更新管理元数据,图1中也有相应的模块。

    • NameUUIDIndex: volume name : volume UUID

    • SnapshotVolumeIndex:snapshot UUID : volume UUID

 

 

图3.convoy工作目录和volume配置文件

 

5)Router注册:Router提供两部分的路由,并将Daemon的Router指向该Router。

① 处理Convoy Client的命令Client Request Router,处理客户端发送的http request。

 

 

②处理来自Docker的请求Docker Volume Plugin Router,Convoy本身就是Docker的Volume Plugin,提供了如下的接口。

 

 

6) http server启动,根据sockFile=/var/run/convoy/convoy.sock 和 上一步骤的Router,启动http server。

 

2.2 Daemon的请求处理逻辑

 

Daemon启动后便可以处理请求(Convoy client或Docker),主要处理逻辑Router收到HTTP请求,将请求分发给各个模块:Docker、Volume、Snapshot、Backup。这个4个逻辑模块根据Drivername(指定的或者默认的)从Daemon.ConvoyDrivers中获取对应的Driver。ConvoyDrivers中的Driver是实现了ConvoyDriver interface的结构。

 

图4.convoy daemon请求处理逻辑

 

从图4中可以看出ConvoyDriver接口规定了3组接口对应Volume,Snapshot,Backup的操作,用于操作Backend Storage。逻辑处理最终调用这些接口访问Backend Storage。

 

2.3 ConvoyDriver implement

 

截止到0.4.3版本,Convoy支持4中后端存储(实现了ConvoyDriver接口),如下表。Convoy是如何对后端存储进行抽象和管理的,主要使用了4种结构Driver:

 

 

Volume,Snapshot,Device:

 

  • Driver:主要实现了ConvoyDriver接口,提供对Volume,Snapshot,Backup等功能。

  • Volume:管理提供到Docker或者Convoy Client的Volume。

  • Snapshot:用于管理Volume的快照。

  • Device:管理后端存储提供的存储空间,如:Devicemapper的Device;Glusterfs的Volume;Vfs的目录等。

 

图5.ConvoyDriver的实现

 

图5Device结构内容,记录了该Driver的后端存储的信息。

 

 

2.4 Objectstore提供实现备份的框架

 

Objectstore模块是实现BackupOperations接口所需要的基本功能,目前实现了两种备份后端:S3和VFS。提供了两种备份方案:DeltaBlockBackup(增量块)和BackupFile(备份文件)。

 

  • Devicemapper使用DeltaBlockBackup方式备份,实现了DeltaBlockBackupOperations接口。

  • Vfs使用BackFile方式备份。

  • Volume,Snapshot,Backup用于管理备份存储的数据。

  • ObjectStoreDriver后端备份存储需要实现的接口。

  • S3ObjectStoreDriver,VfsObjectStoreDriver实现ObjectStoreDriver。

 

Ebs在实现BackupOperations接口时,使用Ebs自身的Client来实现Backup。Ebs本身就是一个分布式存储系统,不再需要额外的Objectstore对其进行备份。

 

图6. objectstore框架

 

通过Vfs备份的目录结构:

 

 

Volume.Cfg的内容,保存图6中的Volume结构

 

 

Backup_[id].cfg,保存图6中的Backup结构

 

 

 

Blocks目录保存了Snapshot存储的真实数据,以Block的形式存储在不同目录。

 

 

容器、应用程序、持久化存储

 

容器与持久化存储,在我看来本不该拿来一起讨论,二者关联性是比较弱的。容器是一种打包方式,基于这种打包方式带来了一系列的好处,如部署、程序运行环境统一,编排,调度等,诚然这些貌似与外部持久化存储真心没太大关系。其实对持久化存储真正有需求的是容器里面的应用程序,应用程序对存储的需求是多种多样的。基于容器化应用程序带来的好处,运维工程师都是期望能将更多的应用程序容器化,以减轻运维负担。

 

对于无状态应用程序,容器化几乎带来的只有好处。但对于一些有状态的应用程序,如数据库,需要进行容器化时,便面临持久化存储的问题。下面是一个外部持久化存储解决mysql容器化问题的例子。

 

三台运行Mysql数据库的主机将持久化存储系统的虚拟磁盘映射上,Mysql将数据写入这些虚拟磁盘中。

 

 

当其中一个MySQLl数据库发生故障时,在新的主机上将故障主机的虚拟磁盘映射上,供MySQL使用,可以快速恢复数据库故障。

 

 

此时,将MySQL数据库容器化将变得十分简单,编排调度系统,能够快速发现MySQL集群异常,并快速调度其他主机上,减少故障时间。

 

 

由上述讨论,其实无论容器在或不在,存储还是存储。当然为了适应容器的快速迁移(相对于虚拟机),多种多样的应用程序对存储也提出了细粒度控制、应用感知、快速创删等新的需求,但存储作为以稳定性为重的基础设施,依然万变不离其宗。

 

持久化存储系统的选择

 

 

持久化存储系统可分为开源存储系统和商业存储系统。通常商业存储系统会由厂商解决所有问题,这里就不谈商业化存储了。开源分布式存储方案如下:

 

  • 块存储: Ceph rbd,Sheepdog

  • 文件存储: Glusterfs,Cephfs,Hdfs

  • 对象存储: OpenStack Swift,Ceph Rgw

 

块存储、文件存储、对象存储三种存储访问方式不同的存储系统,最合适容器的,我想应该是对象存储系统,对象存储系统是通过URL访问的,应用程序只需要知道对象存储系统的URL就可以直接访问存储系统,这种方式更贴近容器的无状态、临时性和快速调度。

 

为什么选择分布式存储系统?

 

1. 云计算时代,传统存储不能满足虚拟化、容器对存储的需求

 

  • 传统存储缺少灵活性,虚拟机、容器的部署及其负载是快速变化的,并且容器还是快速迁移的。

  • 传统存储缺少自动化

  • 传统存储缺少细粒度控制

  • 传统存储的配置是非常严格的

 

2. 构建存储的TCO(总拥有成本)十分高昂

 

  • 数据量成指数级增长,但存储的预算却没有相应的增长,传统存储的价格是无法承受之痛。

  • 数据规模快速增长,企业往往需要过度预算,过度采购,因为传统存储的扩展,升级和替换是十分昂贵的。

 

3. 高昂的存储系统运营成本(OPEX)

 

  • 需要专业的存储管理团队,不仅需要学习专业的存储知识,还要学习存储厂商指定的技巧。

  • 处理存储系统问题是相当花费时间。

    

当然开源分布式存储系统,只解决了第1,2点,第3点并没有得到有效的解决,反而有点加深的趋势。

 

Q&A

 

Q1:有容云在Ceph上遇到哪些坑?都是怎么解决的?

A:有容云并没有使用ceph,我们考虑到Ceph本身过于庞大和复杂,产品化难度太大,于是完全自研一套分布式存储产品。

 

Q2:Ceph做过哪些优化?

A:Ceph结与Linux都有许多参数进行调优,Ceph本身也有多种Cache,目前也使用Spdk进行优化。

 

Q3:问个与存储无关的问题,在优化了DockerFile后,构建Java镜像还是大约要6分钟左右,还有其他优化方案吗?每天开发环境要构建上100次感觉太慢了。

A:这个需要先找到构建镜像的瓶颈在哪里,是否存在需要在网络上下载安装包,还是编译时间太长,导致构建缓慢。针对瓶颈解决问题。

 

Q4:Gluster与Ceph的区别是啥?应用场景有哪些不同?

A:Gluster支持文件接口,Ceph支持块,文件,对象接口;简单的Gluster比较简单,社区版本就已经足够稳定,但是海量小文件问题比较突出。Ceph随着OpenStack已经十分火了,社区很活跃,也有不少存储厂商基于Ceph做分布式存储产品。

 

Q5:我用了Glusterfs,我想问下有什么需要注意和优化的地方?

A:Glusterfs社区版本就足够稳定了,在规划初期尽量避免出现单卷出现海量小文件问题。

 

Q6:Convoy不支持Ceph?并没有说明Docker怎么与Ceph结合使用。

A:Convoy不支持Ceph,并且已经不再更新,Docker跟Ceph结合非常简单,或者说Docker跟所有外部存储结合都非常简单,就像分享内容提到的满足几个接口就行了。

 

Q7:对象存储,和块存储是不是有不同的技术选型?

A:当然两者应用场景不一样,块存储主要是在虚拟化环境、数据库场景。对象存储优势在于大规模海量数据和HTTP接口上。 针对不同的应用场景选型,如果需要非常大规模的,跨区域的场景建议使用OpenStack Swift,简单好用。如果应用场景既需要块存储,对象存储只需要中小规模的情况,一个Ceph搞定所有,也是不小的诱惑。如果公司内部没有专业的研发和运维团队,谨慎使用开源存储上生产。

 

Q8:开源化存储Ceph和Sheepdog的Iops能达到多少?这两种存储的使用场景。

A:具体的IOPS跟物理的存储介质和如何设置Cache的关系太大了,Ceph用的最多的地方就是块存储,Sheepdog是块存储。个人感觉,Ceph的设计比较学院派,大而全,数据拆分很细,元数据很多,维护难度较大,但是社区活跃,找人比较容易一些。Sheepdog体量小,架构复杂度较低,但出问题估计找人难度大。两者都可以块存储,应用场景类似。

 

Q9:Docker已经提供了Volume功能,Convoy做为Docker的插件,在那方面有做改进或者优化?而且我们在实际部署Docker应用的时候,一般都没有考虑过存储的问题,都是通过存储工程师分配好的文件(包含共享存储),为何要引入Convoy?

A:Docker的Volume是使用本地存储系统,通过Volume Plugin机制访问外部存储,如Convoy就是Docker Volume Plugin的一种实现。

 

Q10:Ceph的稳定性和性能如何?

A:无异常情况稳定性还是可以的,分布式存储系统性能都是个问题,最好有专门的工程师进行调优和维护,任何软件长时间运行总是会出问题的,必须找到人救火。

 

Q11:我刚来没太看清楚,但是对最后那个MySQL的例子比较感兴趣,我的理解是三个MySQL实例同时连接到存储,然后一个挂了后,另起一个实例,我的问题是,这之前的三个存储是共享数据的Cluster集群环境嘛?如果是怎么保证数据的一致性和写入冲突问题?

A:多个MySQL最好不要挂同一个存储空间,数据的性能瓶颈在于存储端,多个挂一个存储卷并不会提升性能。通常都是有上层业务来实现分表分库,负载均衡,从而避免一致性问题。例子中是每个MySQL实例挂载一个单独卷。

 

Q12:Kafka、Zk、Redius这些本地集群化组件,是否有必要容器化部署,有什么衡量标准?

A:还是容器化带来一系列好处吧,快速部署,开发测试运行环境统一、灵活,扩容缩容等。具体没什么衡量标准,由架构决定是否需要容器化。建议尽可能多的容器化。

 

Q13:能说下Ceph的瓶颈在哪方面吗?

A:磁盘和网络,计算机体系结构中最慢的两个部件。Ceph的代码级没有什么可以优化的空间。当然Ceph的强一致性,造成io路径加长会影响性能。

 

 

分享:探讨分享 - 容器与持久化存储

有容云-构筑企业容器云 www.youruncloud.com

温馨提示

对Docker容器技术或容器生产实施感兴趣的朋友欢迎加群讨论。我们汇集了Docker容器技术落地实施团队精英及业内技术派高人,在线为您分享Docker技术干货。我们的宗旨是为了大家拥有更专业的平台交流Docker实战技术,我们将定期邀请嘉宾做各类话题分享及回顾,共同实践研究Docker容器生态圈。

加微信群方法:

1.关注【有容云】公众号

2.留言”我要加群”

QQ群号:454565480

有容云微信二维码