这篇文章是运维开发探索系列之Gaea篇的第二篇。

前置导读

如果你还未读过鄙人撰写的此系列文章的前面几篇的话,那么赶紧先去瞧一瞧吧:

传送门:运维开发探索 开篇

传送门:运维开发探索 Gaea.01

这是运维开发探索系列之Gaea篇的第二篇,在这篇文章里,鄙人将会谈及关于运维平台工具开发的一些自己的见解以及具体的一些方法。

运维人员做开发?

在鄙人的一篇翻译文章里,原文作者谈论到了“运维”的本职定位,在鄙人看来,运维的本职定位,不是救火队员,不是流程人员,而是“资源管理者”。那么,为了使得资源更好的被利用,更加高效的被调度,一些运维平台的开发便是难免需要的,这也正是很多企业划分出“框架研发”、“基础服务研发”、“DevOps团队”等组织的原因之所在。

当运维尝试去做一些开发的时候,其实就是在实现一个“服务”的理念,他们是在为Developer或是自身Ops提供服务,这其实和研发人员面向业务的产品研发有着很大的差异。按照鄙人的见解和总结,运维工具应有以下几个特征:

  • 要求实用,实用,再实用;

    首先需要明白,它是一个运维工具,也就是说,它实际的用户量是非常有限的,因而你要考虑的,也许不是界面上的花哨,而更多的应该是实用性,也就是“它是否解决了你目前所遇到的一些矛盾”。

  • 需求很难定位;

    很多时候,运维人员只是意识到需要做一些开发任务来改变现状,但其实具体要做成什么样,自己也是含糊不清的。这就需要在动手之前首先做好原型设计,并且充分和自己的用户(可能是自己团队的成员,也可能是研发人员)沟通好需求和实现目标。在这里,鄙人推荐前期可以先使用Mindject + Axure RP实现一个思维导图 + 原型设计图,毕竟运维平台的开发不像产品开发,它不需要完全遵循业界软件工程所要求的那一系列步骤,然后据鄙人一些浅薄的经验看来,做一些需求的明确分析和UI设计还是非常有必要的。另外,为了更加明确需求以及提升其价值,快速的迭代开发以及不断的重新定位也是十分有必要的。

  • 不必完美主义

    这一点自不必多说,如果一个tricky的技术问题预计会花费你很多精力才能解决,而它其实并不是很影响整个工具的运转,那么也许你可以先抛到一边,让用户用起来再来迭代吧!

作业系统的实现思路

如何实现一个Job System? 我想你需要考虑以下几点:

  • Job 是否具有原子性?

    它是否有明确的成功、失败的判断依据,是否有第三状态(没成功,但也不算失败这种)。就Gaea来说,它实际上是Salt Job的封装,所以它和Salt Job一样,分为Timeout、Failed、Success三种状态,而这三种状态落到的都是最终机器的实体,可以说这个机器Timeout了,但是另外一个Minion是Success的。

  • Job 是需要同步,异步还是分布式的 Run?

    理清这个的目的在于帮助设计后面运行Job的Daemon服务。首先,由于Gaea Job 是基于Salt实现的,而Salt-master可以不仅仅只落在单台机器上,所以它是分布式(Ps. 失控这本神作尤其推崇分布式的理念)的,另外,有些Job在于实时探测一些机器端口的健康性,有些Job需要抓取大量的机器的Metrics并收集起来,所以Gaea Job本身也是需要同时支持同步异步特性的。

    所以,在这里,鄙人的技术选型是Celery + RabbitMQ,Celery支持分布式的异步任务下发,而RabbitMQ消息队列可以辅助实现Job的优先级、Job的状态追踪等功能。

  • Job 的目标实体是什么? 如何满足用户的Target需求?

    一个Job的目标实体可能是一个Instance,也可能是一台机器,明确Job的Target是开发工具去满足用户Target需求的前提。以Gaea为例,它的目标实体,很显然,就是一台台服务器,那如何满足用户的Target需求呢,用户可能需要根据OS版本、IP网段甚至非常特殊化的特定过滤条件,那么Gaea最终的选择(参考了Puppet、Ansible的做法)是仅认可组的方式。

    这里组的概念分为物理组和逻辑组,物理组即以应用为视角,划分出来的组别,它们是相对稳定的,而逻辑组则是根据一些规则筛选出来的机器组成的组别,比如需要根据OS版本过滤? Ok,使用salt grains撰写一个规则作为group的定义即可,需要IP网段过滤? Ok,同样用salt grains写一个吧,需要联合几个物理组和逻辑组? 当然可以! 逻辑组还可以被用户主动刷新,来获取最新的满足规则的机器分组。

  • Job 的执行结果如何展现? 用户关心怎样的Job Report?

    用户fire一个Job的最初动力便是想借助它实现一些目的。所以用户最关心的会是各个目标实体最终的Job状态,以Gaea为例,用户最希望呈现的效果应该是这样的:它需要能展现当前进行中、已完成、已失败、计划中的Job的概要情况;它需要能展现某个Job具体预备推送的目标机器,实际推送的情况,Job完成的明细和时间;它需要能展现一台机器的Job执行历史和具体完成时间;etc..

  • 怎么实现Job的中断、计划任务以及实时进度感知?

    如果一个Job Fire下去之后发现根本不应该执行,怎么办? 有时候,也许用户还需要定期的执行一些Job,或是了解当前Fired Job的实时进展。这些需求都是十分合理的,但是如何去实现呢? 以Gaea为例,Job的打断是通过Celery Task ID索要到任务信息,进一步发送Celery信号量来实现效果,而由于用户的Schedule Job是可以灵活多变的,所以Gaea选择了“以Celery为执行器,以Linux Cron.d控制下发逻辑”,是的,没有错,通过Gaea Job Template操控Cron执行内容,从而实现灵活的Cron配置,而Linux Cron的稳定性也是毋庸置疑的。那么,怎么实现实时Job进度更新呢? 答案是Salt Event Watcher + Redis + Key订阅 + EventSource!!

且听下回分解..

关于Gaea的一些Job System原型设计理念的分享就是这些,下一篇文章可能会是关于Gaea前端展示的一些Tech Point,敬请期待..