凡墙皆门:移动云自动化运维平台的破墙与进化之路

戴声 2017-12-26 10:03:15

本文根据戴声老师在〖Gdevops 2017全球敏捷运维峰会广州站〗现场演讲内容整理而成。

 

(点击“此处”获取戴声演讲完整PPT)

 

讲师介绍

戴声,中国移动“移动云”运维研发团队leader,Python开发高级工程师。目前负责移动云整体自动化运维架构设计及运维平台开发。在大规模OpenStack云环境的标准化、自动化运维、监控系统、DevOps工具链应用等方面有较丰富经验。

 

移动作为传统运营商,在实施自动化运维方面时还是遇到了颇多困难,今天就借这个机会跟大家分享一下“移动云”如何在一年多的时间里,实现从纯人工到自动化的运维转变。

 

 
 
 

运维:传统到自动化的一般路径

 
 

 

事实上,近几年接受了诸多运维大会的“洗脑”,对于一个运维团队的运维开发之路,我们比较遵从这样一个理念,即做自动化运维,一般是经历下面四个步骤:

 

 

  1. 标准化。包括整个环境、服务的标准化。进行标准化后,事实上整个环境已变成相对可控了。所有的厂家或者是不同的单位按照我们的这些规则来部署之后,很多的东西包括自动化都变成了可能,所以马上就进入了第二个阶段。

  2. 脚本化与工具应用。这时我们从人工运维往上跳了一个台阶,很多东西都变得可以用脚本或工具来实现,便慢慢开始积累更多的原子脚本。

  3. 平台化服务化。随着运维规模的不断扩大,这些脚本慢慢变得混乱和复杂,有些也变得不太适用某些场景,所以我们开始考虑如何把这些所有脚本及工具整合成一个平台,来实现我们的配置管理、资源服务,以及怎样把所有的运维动作场景化。

  4. 智能化。在上述三步的基础上,慢慢考虑如何利用长期积累下来的数据,推动整个平台往智能化方向发展。

 

这样的路径大家都比较认可,事实上,我们在完成了第一步的标准化之后开始尝试后续的步骤,这也是接下来演讲的主要内容:我将从工具化与脚本化的阶段开始,介绍我们一步步打造移动云自动化运维平台的若干经验。

 

 

1、成员

 

要干事,先要人。那人怎么来?我们团队在最早的阶段,大家都是偏传统运维的,要转型做运维开发,难度相对比较大,所以人手没有办法,不是很多。团队成员最好来自业务运维、系统运维、网络运维等各个层面。此外,团队在初期刚成立时可以是虚拟团队的形式。比如我们刚开始要做这个事情,只有三个人,并且每个人都兼任各自的日常运维工作,每天加班加点开始搞。同时,因为人少且做的事情任务杂,产品、需求、开发、运维都要管,所以这里对人的要求:一个是口才要好,因为如果你没有办法引导需求,甚至PK不过运维同事就比较难搞了;另一个技能是要会写代码,一个工具出了问题要能背锅,能把自己的东西搞定、解决好,并提供给运维同事使用。

 

2、开发方式

 

这里和大家提一个建议,不管以前是怎样的,从现在开始一定用敏捷的方式来做,并且story一个一个迭代,最好是采用完整的DevOps流程。我们已经接受了这么多的DevOps理念,作为运维出身的人首先自己要能够把它实践下来。为什么呢?

 

  • 第一个是因为要快,因为已经完成标准化了,所以系统运维、主机运维或者是网络运维他们可能都说自己有一些自动化的东西想开发,如果你的速度比他慢,就很难再推翻他们的系统,而如果要把这些别人做出来的烟囱给整合起来也费神费力。

  • 第二,我们可能也需要让运维同事去推动包括研发以及其它部门来使我们的整套业务系统都变成DevOps。这时如果你说我们运维团队自己的运维系统开发都做不了DevOps,如何让人信服?如何去推动其它部门来配合你呢?所以自己一定要把这套东西先给实践下来。

 

3、目标

 

必须要能够解决实际的问题,而且这个实际的问题也必须是实打实地、快速地去解决,才能有利于你的这套系统或者工具的推广。就像前面说的,如果你不做,别人就要做,最后成了一大堆烟囱。

 

在工具选用这个阶段,基于自身的实力,我们不是马上着手做开发,而是考虑能否借助一些开源的力量,于是进行了一个比较深入的选型调研,最终选定了Ansible、Zabbix和ELK stack三个工具。

 

我们是怎么考虑这个事情的呢?

 

  • 第一,选用的工具必须功能足够强大,要比其它运维同事自己所用的工具好使,功能范围要更广;

  • 第二,要足够易用,因为可能有一些同事要把原有的一些脚本迁移到你的系统平台上去,学习曲线不能太陡峭;

  • 第三,要有利于二次开发。我们的志向肯定不止一次搞几个工具解决问题就算了,要考虑后面如何扩展和整合。

 

选用这三个工具,是从监控告警系统、批量管理和制作系统三个方面来考虑。其中,Ansible是我们选择的批量管理系统,最主要考虑到的是:它是基于ssh的、无需agent的特性,以及丰富的plugin模块和权限控制的能力,而其roles机制也更利于我们进行场景的整合。而且它是基于Python开发的,便于上层运维平台(也是Python)的集成,于是就PK掉了Saltstack和Puppet。第二,我们用了一套Zabbix。众所周知,Zabbix是一个功能完整集成、拥有丰富的监控模板支持、易用的界面,适配几乎所有采集协议,具备完整的监控告警能力,而Nagios、Ganglia和Cacti都不能称之为完整的监控告警系统,它们都只是涉及部分单一的功能,监控告警功能上需要与其它系统或者插件进行集成。

 

另一方面,我们监控的主机数还没有过万,因此考虑选择Zabbix这套东西,在我们这个规模下面,事实上它是足够的。足够就好是我们的理念。

 

最后一个是ELK,我想这个不用过多解析了,因为其它的产品它均没有合适的检索能力。

 

当把这三个工具做起来后,是不是就可以热火朝天地开始大量往上面填充脚本呢?实际上,这时Ansible成为了首当其冲的问题。因为Ansible为了方便批量主机操作,我们往往会做大量的主机互信,这时候只要有一个密码,就可以全网进行批量操作,研发或各个运维团队的人共用一套Ansible去执行现网操作。假设操作错误,很多机器倒了,我们却无法得知是谁造成的,这是非常危险的!

 

怎么办?我们在上面加了一层接口,给它做了一个叫“walker”的批量操作平台。事实上它就是一个批量操作平台,底层是借用Ansible来实现的。这个东西其实比较简单好做。做完这个之后,发现批量操作时安全的问题还是没有解决到,所以上层又加了一些用户、认证、鉴权、审计等功能。

 

 

这样做下来,这套东西就可以开始使用了,然而我们不可能每次做批量操作的时候都需要输入大量的IP地址或主机名,操作起来还是非常不方便的。这里有的人可能会想,那你搞一个CMDB吧。一听到CMDB,可能大家头就大了,CMDB这么庞大的东西,怎么做?我们这里取了一个巧,找了一个办法,这也是当时和很多互联网企业交流取经回来的。我们只做了一个轻量资产库,需要要用到什么程度,就做一个什么程度的东西。上面只是存放了所有主机的状态信息、地址等。

 

那这些主机的信息手工录入吗?当然不是,就算有工夫去录入,那怎么保真?有没有现成的信息的可以调用呢?有!就是Zabbix。Zabbix是有自动发现能力的,通过把Zabbix的这些实时保真的主机信息获取过来,我们做了一个轻量的资产库。

 

以上的东西完成之后,我们其实已经实现了一个比较完整的批量操作平台。

 

最后,在这个基础上,如果让批量操作平台对外提供一个接口,可以把它配置到Zabbix的actions上执行,那这几个系统就贯穿起来得到了整合。比如说ELK可能发现一些error,导致Zabbix触发了一个告警,于是Zabbix调用接口执行批量操作平台执行一些预设的处理脚本解决问题,从而消除告警,就完成了一个告警闭环。

 

这套系统在初期就可以很快地搭建起来。开发中有什么难点呢?

 

  1. 第一,我们用了前后分离,前端用Angularjs,后端用flask,比较快速地实现。

  2. 第二,在认证鉴权上,用了Python的isdangerous的模块实现了一套完整的JWT协议的认证方式。

  3. 第三,Ansible的接口也是一个坑。Ansible在V1时,官方提供的接口是ansible.run(),这个接口非常简单易用。但到了AnsibleV2,这个接口被撤销了,需要我们花比较多的时间去研究它的代码,基本上把Ansible的代码看了一遍,重写了一个Ansible的接口。

 

对于并发任务的执行,早期我们采用Python的threading实现了简单的用异步能力。事实上平台的使用者主要集中在我们的运维同事,所以其实并发量也不会非常高。大家知道这个threading效率非常差,但是它能足够解决问题。

 

最后,我们对接了一个Zabbix的接口,实际上Zabbix接口还是比较完善的,文档也比较齐全。

 

做完以上这套系统,我们觉得能够解决大部分的问题了。但事实上,这个阶段由于脚本的野蛮生长,它们开始逐步变得不可控。于是我们尝试梳理这些已有脚本,我们认为应该是这样的:

 

 

然而事实上它们是这样的:

 

 

这时就有点绝望了,因为运维的场景非常多,它们其实都有自己的需求或者应对的设备,因为像移动这样的运营商在集采时,设备种类非常多,即使前面部署应用时我们做了标准化,但还是有一些基于硬件的东西没办法标准化、有一些业务层面的也没法标准化,那像这种场景怎么办?

 

我们想了一个办法,比如说网络设备的管理这件事,我们的考虑是能不能把网络设备这些底层设备的指令封装起来,然后上面再盖一层,把这些各种各样的命令进行规整,再把各种各样命令拼装起来做成网络运维自动化场景。用这种方式可以将杂乱的网络运维脚本整合为一个工具包。

 

 

于是我们做了一个叫Forward的网络设备管理工具,把大量的网络管理脚本给整合起来了。它包含三层框架,底层是各种各样的网络设备,紧接着我们做了一层框架,把这些设备给拉横了、拉平了,在组装场景时这些操作是一致的。当然,也会有一些比较基础的东西,比如说写日志或是异常处理。目前我们也把这个工具开源了,地址-https://github.com/tecstack/forward。

 

做完这套东西,我们又开始思考,这套方法能不能复制?主机或是虚拟化的管理等能不能也依靠这些东西去做?事实上是可以的,可以给我们不同的运维专业同事梳理出代码目录,做一些基础的方法和类,然后再让他们去填充这些底层的场景和上层的服务。

 

 

于是我们把原先一些乱七八糟的东西整了一下,做成了五个层面的工具包,有主机层面、物理主机管理层面,也有虚拟化管理层面的。事实上,我们的虚拟化管理最早是用自己的脚本去开通,用自己的方法去管理,现在比较系统化地做成一个完整的工具包,也有网络运维的工具包。基于我们自己运维过程中总结的基础组件、中间件的标准化推送、组件管理的方法,我们也将其整合成了“组件推送”的工具包。通过这种方法,让这些脚本慢慢可控,可控了以后,可以用刚才提到的批量管理平台去执行。

 

通过这种方式,运维团队的日常脚本慢慢形成比较有价值的经验资产。

 

执行时我们又发现了一个问题,其实它并没有真正解决很多实际落地的运维场景,比如说现在想要调用一个网络工具包的某个命令,执行完之后,再去调一个组件工具包的命令,然后我再把某一个文件发回来,再把结果发一个邮件等。因此我们开始实现下一步的功能——场景化的编排。

 

这个编排功能的作用是什么?事实上,光有了前面基础的能力和工具包是不够的,我们虽然可以利用这些工具包来帮助我们去管理一些资源或者做一些业务运维操作,但这些工具包如果只是每次至执行一步单步的的操作还不能实现一个完整的场景,还得再给它新增一些辅助性的单步的操作能力,再把这些能力编排起来。

 

比如说除了刚刚讲到的这种命令或脚本的批量执行外,我们还做了文件管理和一些场景的审核功能(例如,现在我要封堵一个客户虚拟机的IP,可能需要有网络管理跟主机的同事一起审核)。所以,假设我要新增一个应用,它可能是下面几个步骤编排起来:

 

  1. 审核通过

  2. 新增一个虚拟机

  3. 在这个虚拟机上推送一个中间件

  4. 在这个中间件上分发一个应用并启动

  5. 把虚拟机、中间件、应用在Zabbix监控起来

  6. 发送邮件通知,事情搞定了

 

这里面其实只做了一些单步的步骤,然后把这些单步的步骤做成了一个场景的编排,编排完了,如果这时变成了真正可以提供给所有人使用的一些小应用、小工具,那这个东西就非常好用了。

 

这里有一个背景要补充介绍下,我们的运维团队并不是什么事都包的,还有一个“服务台”的团队,他们比较擅长的不是技术,而是跟客户沟通,但他们有一个指标,就是对投诉的拦截率有多少,在他们的层面如果不能解决,再给我们运维同事派工单。事实上,我们可以把这些编排出来的小场景程序提供给服务台的同事。所以这时大家都比较爽,为什么呢?因为对二线运维同事来说,他没有工单要处理了,很多故障和投诉已经在服务台团队利用小场景程序解决了;而服务台这边也很爽,因为他们有拦截率的要求,靠这个运维同事提供的东西可以很快地提高他们的故障和投诉处理率(拦截率)。

 

当然,除了服务台以外,还有更多对资源有需求,或者需要对资源做操作的,是我们的研发,研发经常向我们的运维同事说:你给我一个虚拟机、给我一个数据库、给我配一条网络策略,或者我要看哪个状态信息。像这种事情,也能够通过这种编排小程序提供给他了。

 

 

那做这个东西有什么实现上的问题呢?最主要的问题是命令/脚本的批量执行,因为慢慢的,平台的使用量大起来了,像之前threading的多线程方式已不适用了,效率出现了较大问题。所以这时我们考虑使用了一个简单好用的分布式异步队列Celery,加上一套RabbitMQ,从而解决了并发量的问题。

 

第二个问题是文件管理。如果说用nfs的方法,IO性能可能不太行。我们想了一个办法,找了一个东西叫Minio。Minio可以实现AWS的S3的协议,而后端的存储它不管,可以用各种高可用方式去扩展,所以这也是一个可扩展的文件管理方式,是一种对象存储。

 

最后的问题是前端,我们改用了VUE.js。

 

全部做下来,我们发现对业务场景编排用得非常多,而对资源的管理场景则非常少,为什么?因为每一次组件的推送或者是我创建某一个虚拟机,我们做完了之后发现我的这些数据并没有存下来,只是帮你创建了资源,但并没有数据的维护。所以又绕回去刚刚那个问题了,我们是不是需要一个CMDB?或者说我这个资源管理服务,它其实并不完善,我是不是应该做一个比较完善的资源管理的服务来提供各种各样的资源?

 

 

因此,我们继续开始做下一件事情,就是把我们之前所做的工具包进一步的完善起来,在上面给它做了一个资源管理服务的模块,从而让我们的运维同事可以用他们非常熟悉的方式去管理这些资源,因为我们帮他做完了上层的管理模块。但在做完这个管理模块的过程中,我们没有CMDB(这里仍是一个问题,后面解决)。第二就是解决了自动配置监控告警,比如说创建了某个资源,删除了某个资源,操作了某个资源等相关的监控,把它自动化地监控起来。

 

还是回到资源配置管理这个问题,绕不开,必须做。后面我们做起来了,这里我们实现的CMDB跟最早传统意义上的ITIL中描述的CMDB有些不同,因为它并不是一个大而全的CMDB,里面并不包含资源服务功能,更多的是提供一个数据信息模型,以及这个模型的对外提供的数据服务。而对资源的管理则提到外面去,独立出来。

 

 

第二,我们有一个对配置管理额外的需求。这时我们正在推进整个“移动云”在各个业务部门和研发之间的DevOps流程。大家应该了解,在做DevOps时,自动化配置管理这个坎是绕不过去的,你必须要能够管住应用的配置信息,使它必须能够在不同的环境之间进行切换,而且必须要有接口,可以自动。在这件事情上,我们想了一个办法,就是给它做了一个配置项的管理。

 

这个配置项的管理是基于配置项级的管理(相对应的,另外一种则是配置文件级的管理),并且每一个配置项可以实现不同环境之间的切换。在实现上,底层对接了etcd+confd/disconf两套配置管理工具,从而解决了多环境下的应用配置项的秒级发布功能,并且额外做一些配置信息的备份、回滚、防篡改等必要的功能。由此,可以给DevOps提供了一个比较好的配置管理服务的能力。

 

这些东西全部做下来之后,我们发现自己”好象”做了一个运维平台,有了比较完整的功能:第一个是场景自动化,像刚才所讲的,场景可以进行编排。第二个是资源服务化了,有物理机、虚拟机、网络设备等各种各样的资源,并且可以推送各种各样的基础组件,并且这个资源服务化可提供给我们的DevOps使用。第三个是配置自动化。配置自动化也是DevOps的一环。我们可以借此使整个DevOps流程跑起来。

 

 

 
 
 

一些经验思考

 
 

 

1、在功能上,要讲求实用主义,好用为王。

 

大家对于传统企业、运营商的印象,大概都是:今年年初要规划,然后年终看有没有做出来。其实最好不要这样,因为需求和应用场景是一直都在变的,所以我们可以有规划,但不要一味地按照规划去做,必须是解决最实在的问题,才能更好地使运维平台在运维团队里推进。

 

2、在进度上,不要着急,但速度要快!

 

其一,运维平台做出来的功能必须符合DevOps流程,是DevOps所需要或是符合DevOps的才做,如果还是传统老运维那一套的类似需求,则一概拒绝实现。其二,运维开发本身要遵循DevOps敏捷迭代和持续发布,使运维需求得到快速响应,将运维同事的其它“法外”小工具小系统扼杀在摇篮里。避免烟囱林立的局面,也省去整合的痛苦。可怎么才能快起来?这个要看自己团队的实力,我个人觉得可以更多地借用开源,更快地提升实现的速度。

 

3、在对运维团队的引导上,要立足全员开发。

 

不能将开发局限在三五个运维研发的同事身上。避免这种局面:发现有人负责开发运维系统了,整个运维团队有什么需求,全部向他们提,这样的话其实又回到传统运维老路子上去了。这种方式不仅不能提升运维团队的整体效率,最后也会压垮运维开发团队,不是一个可持续的工作模式。

 

所以运维开发团队的职责是,向整个运维团队提供更多的通道,或者说提供通道框架能力(比如我们通过做这种场景的通道,可以让你编排,然后让运维同事再组装上小应用去解决实际的问题和场景),并且要不停地迭代出新的功能,每一次迭代新功能,根据运维同事的反馈去考虑后续的开发,去考虑应该跟进还是引导,这样才能锤炼出好的运维平台。

 

以上是我们在运维平台开发过程中的一些体会,最后用加缪的一句话来作结:“凡墙皆是门”。我们在做自动化运维平台的过程中,每一次碰壁都是一次进化,都能助你锤炼出更好用的自动化运维平台。。

   

 
 
 

Q&A

 
 

 

Q1:您好,这个平台这么大,部门分得这么散,你们是怎么把这个标准比较有效地推广到全公司的运维里面去,或者是让开发的都知道要按你的规则来走?

A1:这个事情不在本次分享我讲到的内容里面,而是在正式做自动化运维开发之前要完成的工作。这里首先你肯定会有一个PK,肯定会有拍桌子、瞪眼睛的过程,这个过程是跑不掉的,毕竟涉及各方的工作量。但在这个过程中,首先你得对这自己设计的一套标准部署方案有信心,要实力过硬,要相信一套好的部署方案,除了能解决运维的困难,也能释放研发团队大量的时间。第二,部署的过程必须是运维自己来实施,这样就天生有了部署标准的控制权。第三,我觉得应该争取得到各团队的自上而下的支持。 

 

Q2:您好,我也来自运营商的,对你们团队怎么运作很感兴趣,你们是如何组建这个团队的,驱动力是什么,在这个过程这么“撞墙”,然后穿过“墙”的?

A2:我觉得我刚刚说的比较多是技术上的“撞墙”问题,这里您提的应该是人方面的撞墙。首先,其实对我们来讲,最早是我们都靠人力运维的方式,甚至我们去外买一些厂家的平台,这实际上经历了较长的时间,然而事实证明这种方式不能很好地解决我们的问题。因此,我们团队的人其实也是从零开始的,一开始也是一边维护,一边研究工具,一遍开发,再引导整个运维团队去使用和改变运维方式。在这种模式下,自动化运维才慢慢做起来了,也吸引了更多的关注,并随着成果和效益的出现,慢慢去形成相对比较独立的运维开发团队,大概是这么一个过程。

活动预告