联想企业网盘基于 Docker 构建分布式部署框架实践

1,044 阅读10分钟
原文链接: dockone.io

【编者的话】本文首先介绍了企业级分布式系统部署所面临的挑战,并且结合联想云存储自有框架研发经验分享了一些解决问题的思想和具体做法。最后还与Kubernetes项目进行了简单对比。

众所周知,企业网盘在这两年呈现爆发式增长,越来越多的企业选择企业网盘,来解决企业在业务过程中面临的数据集中存储、共享、分发、协同办公以及移动化等痛点需求。同时将企业网盘整合到各个业务系统中,大幅提高企业的数据流转效率和安全!

而联想企业网盘增长尤为迅速,仅联想私有云网盘业务15年较14年增长300%。大家都知道历史上所有的私有云的产品在迅猛发展的过程中,部署实施交付始终是一个巨大的挑战。其中,解决分布式部署交付的问题是诸多挑战中的核心。

我们的联想企业网盘在业务发展之初就开始考虑如何高效的交付,经过团队持续的提升和优化,功夫不负有心人,我们逐步实现了一套基于Docker的分布式部署和运维框架“DragonBall”。这也使得交付的环节成为我们用户满意度非常高的一个环节,也成为了联想企业网盘的一个核心竞争力!

相信所有80后都对龙珠这个名字很有感情,没错,集齐龙珠就可以召唤神龙!在分布式系统的场景中,召唤神龙的意义就是充分发挥分布式架构的强大威力。DragonBall项目经过一段时间的发展和完善,部署10台规模小微集群的时间从三五天缩减到10分钟左右。

由于“分布式部署”这个话题牵扯细节众多,下文将重点介绍联想私有云网盘在这方面的经验与实践:

分布式系统部署的主要挑战

分布式系统部署和交付的挑战并不单纯来自技术方面,很多时候我们还需要从项目管理的角度来思考,但基本上都逃不过这些最直接的挑战:

  • 对实施人员要求很高
    以RedHat系统举例,配置Yum源、安装各种依赖包、配置调试网络、设置SELinux、改防火墙规则、配置ulimit、写启动脚本、下源码make ……这个列表还可以接着写很长。可能有人说合格的运维本来就应该会这些啊!没错,即使你已经滚瓜烂熟,但谁又能保证这么多操作没有错误呢?这些重复劳动居然不能自动化?简直丧心病狂!

  • 软件环境和依赖包的兼容性问题
    OK,假定你已经按照研发提供的list完成了所有依赖包的安装,高高兴兴准备启动服务了,那么恭喜你,你已经站在了另一个大坑边上:版本兼容噩梦。

    由于各种操作系统发行版之间的差异,基本上你无法遇到完全一致的软件环境,各种依赖库、依赖库的依赖库,版本、编译参数、patch千差万别。

  • 各模块之间启动顺序无法保证
    当模块间存在强依赖时,保证正确的启动顺序非常重要。

  • 伴随着节点数量的增加,工作量和操作错误概率呈指数增长
    很多配置项需要在每一个节点配置与其他所有节点相关的参数,这样的话总配置项就变成了N*(N-1),当N大于10的时候,这种配置将变成灾难。

    而且只要是有人参与的操作一定有机会犯错,节点数的增加将大大提高出错概率。

  • 客户生产环境往往与前期沟通差距很大,经常需要部署人员现场随时调整部署方案
    其实大部分客户非常配合,也最大努力的提供必要信息,但是很多情况下设计好的部署方案必须临时调整。


联想企业网盘如何解决这些问题

分层部署,隔离问题,分而治之

将整个部署过程分成三个层面:资源层、容器层、应用层
03.png

资源层

完成操作系统层面配置和部署,包括内核升级、Docker服务部署、安全策略配置、SSH公钥分发等。

资源层的安装需要登录每台服务器并root身份运行DragonBall.bin,此时内置脚本将提示用户完成本地设置,并选出一台服务器充当“portal”,即DragonBall的Web配置界面,同时portal管理了一个私有的docker-registry用于分发Docker镜像。

通过资源层的部署,DragonBall向上层交付了资源操作平面。

资源操作平面具备向任意服务器导入镜像、起停容器的能力,同时DragonBall也能够实时监控基本的资源使用情况,如内存、CPU、IO、连接数等等。

容器层

在资源操作平面上,部署实施人员可以通过portal提供的Web界面方便的编排容器和服务器之间的关系。通过“添加设备”功能还能够很方便的加入新的服务器资源。

通过容器层的部署,DragonBall向上层交付了容器操作平面。容器操作平面具备对任何一个实现了DragonBall服务规范的服务进行启动、停止、状态监控、参数配置、通知其他服务状态变化的能力。

应用层

应用层向最终用户交付系统能力。在容器操作平面上,通过编排各种服务之间的关系,发挥分布式系统架构的威力。

业界有句老话,简单就是灵活!在DragonBall框架下只有两种类型容器: Service和Backend。

Service容器负责对外提供服务访问点。既可以自己处理请求,也可以将请求分发给Backend;Backend容器真正处理Service请求。在配置Service的Backend时,也可以将其他Service当成Backend。

两种类型容器间一个显著区别是Service容器内集成了负载均衡和故障剔除机制(通过内置nginx实现),而Backend容器则不具备这些机制。


Docker社区建议一个Docker跑一个进程,这听起来不错,但是当系统内有成千上万的进程时,这种策略似乎不便于配置管理。Kubernetes项目提出的pod概念很棒,2015年Docker社区也发布了Docker Compose。但是很遗憾,我们启动项目时还没有接触到这些出色的项目。经过大量测试后,我们沿用了一个容器跑几个进程的土办法。
通过Service、Backend模式,我们可以构造出Service依赖树,树的根节点对系统外提供服务。

Service依赖树将在容器启动阶段发挥重要作用。当启动某服务时,DragonBall框架将递归检查此服务的Backend(或充当Backend的Service),先启动依赖树的叶子节点并保证状态正常后再逐级回溯启动上级服务。这种机制保证了各模块的启动顺序。

最终,我们可以看到并监控各服务的运行状况了。

通过三层结构,DragonBall将各种问题分开处理,降低了整体复杂度。

构建标准化镜像,将差异封印在容器中

企业级分布式系统的正常运转,仅仅依靠精巧的框架和机制是不够的。真正的业务还要由勤奋的程序猿来添砖加瓦。

那么如何将不同厂商、不同语言、不同配置模式的模块快速部署到正确的位置,又如何保证模块配置正确并按照正确顺序启动呢?
为了解决这个问题,DragonBall定义了标准模块镜像。

首先一个标准模块需要按如下结构规划目录:
my_service
    ├── action
    │   ├── config_change
    │   │   └── 1_load_config.py
    │   ├── info
    │   ├── start
    │   │   ├── 1_start.sh
    │   │   └── 2_watch_dog.sh
    │   ├── status
    │   └── stop
    │       └── do_nothing.sh
    ├── log
    ├── module
    └── storage

其中log最容易理解,用于模块记录日志使用。

  • storage目录用于存储持久化数据。
  • module目录用来放置模块自身文件。
  • action目录提供了一种简单粗暴的操作模式,模块需要编写对应脚本放到对应目录下面。当目录对应的事件发生时,DragonBall框架将按照ascii顺序依次同步调用脚本(默认执行超时时间为1分钟)。


action目录下的status和info用于输出容器的当前状态和容器的描述性信息。

然后使用ADD命令把my_service加入镜像中,Dockerfile大概是这个样子:
FROM dragonballbase:centos6

ADD my_service   /opt/dragon_ball/service/my_service
RUN    /opt/dragon_ball/bin/run.sh

然后我们的每日构建系统会自动将镜像build出来,第二天的bin包中将包含此模块镜像。

最后,当DragonBall框架启动模块容器时会按照配置将storage、log目录挂载到容器外,同时调用start目录中的所有脚本,至此模块启动完成。

从网状配置模式到星形配置模式

为了避免网状配置,最初的DragonBall框架采用全局配置文件的模式。
即部署人员在Web界面完成配置之后,DragonBall框架会生成一个巨大的配置文件,配置文件描述了整个系统的所有物理机情况、模块情况、Service依赖树、服务访问点等等。

任何一个模块看到这个配置文件后即可获得所有需要的信息。而当任何配置发生变化后,框架只需要重新生成该配置文件并通知每个模块即可。

通过这种模式确实简化了整体配置复杂度,但是也引入了一些问题:
  • 任何配置发生变化后,所有模块都会收到更新通知,浪费了系统资源
  • 连续改变配置后,不同网络延迟的容器收到的配置可能短时间不一致
  • 配置推送失败后没有可靠的补救措施


为了解决上述问题,DragonBall框架集成了Consul服务,通过watch机制,只有当前模块相关的信息发生变化时才会收到通知。为了快速适配一些第三方模块,我们还大量采用了Consul Template,有兴趣的朋友可以深入了解一下

与Kubernetes有何区别

很多人可能会问这不跟Kubernetes干的事情一样吗?很多功能还不如Kubernetes强大,为什么要重新造轮子?

Kubernetes是很棒的开源项目,拥有很多值得借鉴的理念,但其核心目的并不是解决分布式系统的快速部署问题,其自身的部署也是具有一定难度的,而DragonBall在项目启动之初就把简单、迅速、友好作为第一设计目标。

本文作者:联想企业网盘 袁磊