首页 存档 技术 查看内容

容器与持久化存储:容器的开源分布式存储方案选型

2018-3-30 13:00 |来自: 互联网 344 0

摘要: 导读:容器得到了越来越广泛的使用,以下问题困扰架构师: 容器正逐渐成为云上应用的标准部署单元,容器该如何解决持久化存储的需求? 容器编排系统已成当红炸子鸡,在无状态的容器中,存储系统面临哪些新的挑战? ...

导读:容器得到了越来越广泛的使用,以下问题困扰架构师:


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

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

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


本文探讨了容器和持久化存储相关知识,由张朝潞在高可用架构群分享,转载请注明来自高可用架构公众号 ArchNotes。



张朝潞

有容云平台存储架构师


张朝潞,有容云平台存储架构师。曾工作于UIT、华三、腾讯、专注分布式存储的研究和开发,对云计算存储解决方案方面有很深的技术造诣和行业理解。


一.容器对存储插件的定义


以 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、Rancher Convoy,REX-Ray 等)。


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


二、存储插件


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


Convoy 的代码从结构、风格和使用的库,都与 Docker 十分相似,并且比 Docker 简单很多。


(小编:下面展开介绍一下 convoy 源代码的部分模块,不需要了解细节的读者可以直接跳到第三部分:容器、应用程序、持久化存储。)


Convoy 在源码级别上值得留意的点,我认为有两点:①插件式结构与 inte**ce 的运用。② 作者对事物的抽象能力与方法。


1、convoy daemon (convoy / daemon)


图 1 中黑色部分


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


1.1、daemon 进程启动


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。


(1) 处理 convoy client 的命令 Client Request Router,处理客户端发送的 HTTP request。

(2) 处理来自 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 个逻辑模块根据 driver name( 指定的或者默认的 ) 从 daemon.ConvoyDrivers 中获取对应的 Driver。 ConvoyDrivers 中的 Driver 是实现了 ConvoyDriver inte**ce 的结构。


图 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 的实现


图 5 Device 结构内容,记录了该 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 将数据写入这些虚拟磁盘中。



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



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



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


四、持久化存储系统的选择


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


开源分布式存储方案如下:


  • 块存储: ceph rbd, sheepdog

  • 文件存储: glusterfs, cephfs, HDFS

  • 对象存储: OpenStack swift, ceph rgw


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


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


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


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

  • 传统存储缺少自动化

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

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


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


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

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


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


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

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


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


Q

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部