Back
Featured image of post 浅谈ChatOps

浅谈ChatOps

浅谈ChatOps

背景

本文源自我在技术团队的一次分享。 八月的时候我调研了下ChatOps概念,并通过钉钉机器人成功落地。

至于当时为什么要做ChatOps呢,主要是因为实力不足(不懂算法,监控数据量有限),无法推进AIOps进行运维平台的迭代升级。而ChatOps作为一个新兴的概念(其实也不新了),也属于智能运维的范畴,在国内还没有什么很红的应用方案。

其次是当时出现了一些日常操作的痛点,比如某次研发小伙伴在午饭前上了一次线,午饭期间出现重大故障,只能捧着饭碗从食堂火速跑回工位回滚处理,再比如临睡前懒得去登陆监控页面的我想看下当前负载较大的服务器状况…

在这样的契机下,经过一系列脑洞挖掘出一些潜在的用途后,一款python+dingtalk的简单原型就出来了。部署简单,实用,可定制性强。

概念

理解什么是ChatOps,只需要了解两个要点

  • 会话驱动
  • 机器执行

也就是说,这个系统是通过对话式的聊天进行驱动的,而背后真正的执行者从人变成了机器人。

概念最早源于Github的Hubot项目,开发者可以通过在pull request页面@机器人进行一些常规的分支合并等操作。

比如当下火热的kubernetes代码库, 一个叫k8s-ci-robot的机器人频频出现在开发者的视线。当然它在ChatOps的实践上已经走得很成熟了,可以胜任的一些常规操作包括:提醒代码库管理者review期限, 自动测试,自动加标签,自动格式检查,自动关闭长时间的issue,随机指定管理人员进行代码review等等。

这在很大程度上减轻了项目的管理工作负担,从简化的流程上间接提高了效率。

优点

了解了什么是ChatOps后,我们可以总结下所谓的ChatOps能给我们带来什么?

概括下来,ChatOps大概有以下几个收益:

  • 公开透明
  • 上下文共享
  • 移动高效

第一个,显而易见的,所有操作都是在聊天平台中公开的,有聊天记录可以查询,所有人都能看到彼此的操作记录,由此带来的第二个好处,就是上下文共享,一些繁琐复杂的操作流程,可以通过查看记录了解进度,协调,这样工作承接会更加有序。

还有一个很明显的好处就是移动高效,因为我们的操作端从电脑转移到了手机,pad等移动设备,也不需要输入冗长的命令,做很多次点击等操作,实际上会提高处理效率。

使用场景

脑洞一番后,总结了一些可使用的场景。

第一个,运维巡检,比如哪个夜黑风高的晚上,临睡前的我预感不妙,要看下现在硬件容量有可能爆满的服务器详情,这样可以提前处理下。

另一个,就是告警查询,有时候告警泛滥,我如果不登陆监控页面的话,不清楚哪些告警已经处理了,哪些没有处理。这时候我可以@机器人来一个当前告警清单。

第三个呢,就是紧急回滚。如同前文所说,比如哪天我们上好线,初期观察没啥问题,出去吃饭了,结果吃饭过程中出现大量告警,直接@机器人回滚操作,简单又高效。

第四个呢,就是我们经常需要做的,硬件信息查询,比如服务器外网IP,硬件配置,比登陆CMDB查询方便多了。

架构

一个完整的ChatOps落地包括这四个层面的架构,有人(不限于运维,研发,甚至可以是运营),有聊天平台(比如国内的钉钉,微信),有机器人(比如github的hubot),有支持机器人操作的基础设施,包括服务器,脚本,后端服务等等。

后端服务作为ChatOps的主要开发对象,暂时没有很契合的开源方案,需要开发者自己开发相关逻辑。

等级演变

下面分析下ChatOps的演变路线。

在ChatOps之前,运维是直接对接监控系统的,没有聊天软件来进行信息同步。同时,告警处理和事件处理等运维操作都是基于Ad-hoc命令,通过shell客户端进行的。


到了Level1后呢,我们会针对告警创建不同的讨论群,比如某应用触发告警了,运维在群里通知开发进行处理。在这个层级,事件的发送者还是人。
Level 2A后,我们已经可以把这些告警信息、事件详情等进行分类通知,比如硬件类告警专门发到一个群,应用类告警发到另一个群。这时候,事件的发送者变成了监控系统,然后还支持事件恢复通知。
Level 2B支持从监控系统中拉取数据发送到聊天平台了,比如查询CMDB获取硬件信息,工单系统啊,监控指标啊等信息。此时信息更加丰富了。
到了level3后就是全自动化的交互。比如可以更新工单,事件状态,发出指令并查看执行结果。最重要的是我们能通过聊天工具跟监控系统等内部系统进行交互。
到了level4后,交互的中间人变成了机器人,机器人可以把对话转发到工单系统中,然后监控关键字并发送更新信息,更新知识库,总之就是交互更加智能。
到了level5后。机器人演变成人工智能了,对于自然语言的理解有很大的提高,并可以根据知识库和历史记录推荐具体的解决方案了。此时可以认为达到了AIOps的层级了。

方案选型

当今市面上开源机器人主要包括这三家

  • Hubot
  • Lita
  • Err

第一个就是我们前面所说的github开发的Hubot, 而Lita是一个ruby版本的Hubot,使用redis进行数据持久化, ErrBot是基于python开发的,内部支持rocketchat这个开源的聊天平台。

这几个选型的缺点都是对国内聊天软件的支持度不够,不符合我们的使用习惯,另外就是hubot已经超过两年没有更新了,Errbot也是,rocketchat插件年久失修,新版本都不再支持。

而钉钉集成的机器人,使用outgoing功能接受信息并进行处理,集成在当前的监控体系下,是一个最好的选择。

实现逻辑

首先,我们要先开发一个后端服务,作为和钉钉机器人的交互对象。具体接口功能包括

  • 接收钉钉机器人的GET请求,作为健康检查。返回200
  • 接收钉钉机器人转发的各种Post请求,并进行处理
  • 回传处理结果给钉钉机器人

然后,通过钉钉开发者后台创建一个内部应用,填入后端服务器的链接(此处GET请求属于健康检查,需要正常返回200即可)。

最后,创建一个内部群,添加内部应用的机器人,将机器人token配置为后端服务的发送token。

要点:

  • 钉钉机器人有qps上限(20次/min),此处可以借助queue模块实现频次控制。 示例代码如下:
    que = queue.Queue(20)

    while True:
        conn, address = sock.accept()
        now = time.time()
        que.put(now)
        if que.full():
            elapse_time = now - que.get()
            if elapse_time < 60:
                sleep_time = int(60 - elapse_time) + 1
                logging.warn('当前发送频率已达限制每分钟20次上线,将等待 {}s'.format(str(sleep_time)))
                time.sleep(sleep_time)
        p = Process(target=handle_request, args=(conn,))
        p.start()
        conn.close()
  • 对于请求的body解析要考虑交互的不同输入情况,比如大小写匹配,空格过滤等。
  • 做好Exception处理并进行提示。比如频次上限后的错误信息。
  • 有默认帮助信息,便于使用(此处我设置空白输入和help两种模式触发)。
  • 敏感token和密钥等通过configparser模块与代码分离。 示例代码如下:
def calc_sign(timestamp):
    app_secret = config['dingtalk']['app_secret']
    app_secret_enc = app_secret.encode('utf-8')
    string_to_sign = '{}\n{}'.format(str(timestamp), app_secret)
    string_to_sign_enc = string_to_sign.encode('utf-8')
    hmac_code = hmac.new(app_secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
    sign = base64.b64encode(hmac_code).decode('utf-8')

    return sign
  • 请求body的senderStaffId对应webhook的atUserIds,markdown格式需要在text处也写入@信息。
    示例代码如下:
def send_markdown(post_userid, send_msg):
    message = {
        "msgtype": "markdown",
        "markdown": {
            "title":"运维机器人",
            "text": '@' + post_userid + '\n' + send_msg
        },
         "at": {
             "atUserIds": [
                 post_userid
             ],
             "isAtAll": False
         }
    }

    return json.dumps(message)

参考文档

  1. https://www.jianshu.com/p/7aa2ced21302
  2. https://www.ibm.com/garage/method/practices/manage/chatops/
  3. https://github.com/zhuifengshen/DingtalkChatbot/blob/master/dingtalkchatbot/chatbot.py
  4. https://developers.dingtalk.com/document/robots/enterprise-created-chatbot?spm=ding_open_doc.document.0.0.34f16573JlceHR#topic-2097982
  5. https://community.ibm.com/HigherLogic/System/DownloadDocumentFile.ashx?DocumentFileKey=f6d1c85a-f2b2-9061-64e4-17be48ed3756&forceDialog=0
Built with Hugo
Theme Stack designed by Jimmy