基于hubot搭建chatOps

浅谈chatOps,并使用钉钉集成hubot实现chatOps模式。

Posted by odin on March 22, 2020

本文基于个人的理解谈一谈chatOps和使用hubot搭建钉钉的交互。

1.聊聊chatOps

早期chatOps是由Github提出的一种方式,他们发现在工作中需要不停反复的运行一些命令,如:

1
2
3
4
5
git checkout -b feature/xxx
# do sth.
git commit -m "Bump version"
git push origin feature/xxx
# create pull request

开发过程中不光需要进行代码提交这些,还有确认持续集成通过,代码部署,确认各项指标正常,代码合并等一系列的繁琐工作。除此之外还有很多类似的重复机械的命令占据了很多,往往消耗了开发、测试、以及运维人员很多的时间,于是他们开发了hubot这个机器人用来帮助他们完成一系列这些重复机械的工作。Hubot被称为Github最忙碌的员工。而后又使用Coffeescript对项目进行了重写,在Github上也受到了广泛的好评。 在谈论devOps的今天,chatOps又冒了出来,指用作聊天交谈的方式完成一些工作和执行一些指令。人们通过聊天工具(bearyChat、slack、hipChat等等)向机器人发送消息,机器人收到消息后根据一定的规则完成一些动作。

(chat Bot主要架构形式)

这便是chatOps的理念,目的是释放一些繁琐机械的工作将其交给机器人自动化完成,开发、测试、运维人员可以更加专注于工作。

ChatOps在CommandOps阶段已经非常成熟,国外不少公司已经开始大规模的使用,而NLPOps则处于发展阶段,VoiceOps则基本还处于萌芽状态。

2.关于Bot

市场上开源的Bot(使用最广的):

  • hubot:JavaScript、CoffeeScript实现,由Github开源并自身在用。
  • Lita:Ruby实现,支持容器部署。底层采用了Redis做存储。
  • ErrBot:Python实现。支持和主流的聊天工具如Slack, Telegram等进行集成.

    Errbot引入了一个工作流 (Flow)的概念,使得在聊天软件中进行流程化操作成为可能,例如权限审批等操作。

本人在使用过程中选择了hubot,Lita和Errbot有兴趣的可以自行了解。

3.hubot

3.1) hubot能干什么

首先我们可以通过命令行的方式和hubot进行交互

1
2
odin_test> odin_test echo "hello word"
odin_test> "hello word"

同样我们也可以通过聊天工具集成进行交互 不光如此,它还可以帮助我们执行代码部署,查看issue的状态,执行自定义的命令,甚至能直接展示监控系统的图表。

(为网络图片)
3.2)chatOps带来的好处
  • 释放重复机械繁琐的工作,开发人员可以更加专注于重要的内容。
  • 移动办公,可以通过移动端简单的指令完成工作,随时随地。
  • 信息透明,操作可以很及时方便的让团队成员看到。
3.3)依赖环境
需要依赖 使用版本 检查版本
node.js 12.12.0(貌似需要6.0以上即可) node -v
npm 6.13.4 npm -v

由于电脑源码编译太久而且尝试了2次都莫名的遇到编译报错。后使用在线安装node,但是ubuntu使用apt-get和centos使用yum安装均版本很低。推荐node n版本控制工具,可以任性的安装不同版本node并支持任性切换。

1
2
// 安装node版本控制工具
$ npm install -g n

安装完后即可使用工具安装node

1
2
3
4
// 安装指定版本node
$ n 版本号   
// 安装最新版本node
 n latest

切换node版本

1
$ n

即可选择所要切换的node版本

4.hubot安装和搭建

node和npm依赖环境搭建完成后。hubot的安装和搭建也很简单,官方文档给出的步骤:hubot_doc

1
2
3
4
5
6
// 安装Hubot Generator,之前在使用Racher的时候的自定义模板时也有使用类似的功能,其实就是yoman,提供一些简化我们使用方式。
%  npm install -g yo generator-hubot

% mkdir myhubot
% cd myhubot
% yo hubot

执行完成后需要响应的注册hubot信息,如:hubot user、hubot name、description、adapters。信息注册完成后即可安装完成。 如上即为安装完成。

hubot创建文件可能需要一致,安装部署过程中出现yo hubot时一直报错,throw err看了是调用node.js的文件执行时open文件权限被拒绝。用sudo到root执行还是一样。折腾了大半天。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@node1 ~]# mkdir myhubot && cd myhubot
[root@node1 myhubot]# yo hubot  (提示没有权限)
/usr/local/nodejs/lib/node_modules/yo/node_modules/mkdirp/index.js:90
                    throw err0;
                    ^
Error: EACCES: permission denied, mkdir '/root/.config'
    at Error (native)
    at Object.fs.mkdirSync (fs.js:922:18)
    at sync (/usr/local/nodejs/lib/node_modules/yo/node_modules/mkdirp/index.js:71:13)
    at Function.sync (/usr/local/nodejs/lib/node_modules/yo/node_modules/mkdirp/index.js:77:24)
    at Object.get (/usr/local/nodejs/lib/node_modules/yo/node_modules/configstore/index.js:38:13)
    at Object.Configstore (/usr/local/nodejs/lib/node_modules/yo/node_modules/configstore/index.js:27:44)
    at new Insight (/usr/local/nodejs/lib/node_modules/yo/node_modules/insight/lib/index.js:37:34)
    at Object.<anonymous> (/usr/local/nodejs/lib/node_modules/yo/lib/cli.js:172:11)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)

[root@node1 myhubot]# chmod g+w /root   (修改root目录权限)

后来观察hubot路径是root用户角色创建,后将其改为普通用户即能正常创建,不再报错。

看到一篇博文中特别指明,使用 请用普通用户进行创建。,具体原因是什么没有解释。

5.Adapters

hubot已经有很多通讯工具进行了适配,如bearyChat、slack、HipChat等,选择这些通讯工具搭建较为简单,根据工具提供的接入文档进行即可。 由于我们公司使用的内部通讯工具是钉钉,在此主要介绍hubot-dingtalk的适配器。但是hubot对钉钉的支持还偏弱。Github上该插件还未支持钉钉webhook hubot-dingtalk可在Github上搜索,hubot-dingtalk

github上hubot-dingtalk插件作者对标记的TODO如下

TODO


  • 接入主动发消息webhook
  • 优化消息显示

关于hubot-dingtalk插件配置也比较简单,Github上描述很清楚了,直接跟随Github配置即可。

遇到一个X-Powered-By的header请求头,无效的字符串异常错误,将文件437行set(X-Powered-By’)什么的那行(大概记得是这个,没有及时记下,现在想不起来了)注释掉即可

6.更改部分配置

初始化完成后结构如下

6.1)external-scripts.json
1
2
3
4
5
6
7
8
9
10
11
12
[
  "hubot-diagnostics",
  "hubot-help",
  "hubot-heroku-keepalive",
  "hubot-google-images",
  "hubot-google-translate",
  "hubot-pugme",
  "hubot-maps",
  "hubot-redis-brain",
  "hubot-rules",
  "hubot-shipit"
]   

hubot-heroku-keepalive: 为heroku自动启动可以删除,保留的话启动会抛异常连不上heroku。

(ERROR hubot-heroku-alive included, but missing HUBOT_HEROKU_KEEPALIVE_URL. heroku config:set HUBOT_HEROKU_KEEPALIVE_URL=$(heroku apps:info -s | grep web-url | cut -d= -f2)

hubot-redis-brain: hubot默认使用redis作为持久化,若不想使用自行删除即可。

6.2)hubot-scripts.json

此文件hubot项目现在已经废除,可以删除。若保留启动hubot将出现如下警告:

WARNING Loading scripts from hubot-scripts.json is deprecated and will be removed in 3.0 (https://github.com/github/hubot-scripts/issues/1113) in favor of packages for each script. our hubot-scripts.json is empty, so you just need to remove it.

7.启动hubot

默认启动,项目路径下执行bin/hubot , 默认启动端口为8080. 若端口被占用也可手动修改端口启动PORT=8100 bin/hubot 若想验证hubot是否安装完成,可在启动hubot后在命令行使用myhubot ping命令查看,如果能看到回复PONG即说明安装完成。

1
2
3
// myhubot 为你创建的hubot的名称,请根据具体名称修改。
myhubot> myHubot ping
myhubot> PONG

所有hubot命令可使用help查看。

8.hubot回复模式

在script/example.coffe的实例文件中可以看到,消息的返回模式有三种,send、reply、emote

1
2
3
4
5
      res.send "Badgers? BADGERS? WE DON'T NEED NO STINKIN BADGERS"
      
      res.reply "I'm afraid I can't let you do that."      
      
      res.emote "makes a freshly baked pie"

其中send和reply类似都是直接回复,如: emote的回复形式为引用回复,如:

9.hubot交互模式

hubot默认为直接回复,即你发给他什么消息hubot立即处理返回。但是当我们需要如下的交互模式呢?

你:执行文件

hubot:好的,请问你要执行的文件名是什么

你:test

hubot:好的,执行完成。

或是

你:添加项目权限。

hubot:好的,请问你需要添加什么项目的权限。

你:xxx_project。

hubot:好的,请问你需要分配什么权限角色。

你:访客。

hubot:好的,添加xxx_project访客角色权限成功。

当你要hubot使用以上交互模式的话,hubot-conversation 插件可以满足你的需求。该插件提供了一些交互式的方法。

1
npm install hubot-conversation

安装该插件后即可根据你自己的需要设计你自己的交互对话方式。如下所示: 72b771bb555fd6e3ef652d048a1003e1.png

9.2)conversation explmate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
robot.respond(/clean the house/, function(msg) {
        var dialog = switchBoard.startDialog(msg);

        msg.reply("Sure, where should I start? Kitchen or Bathroom");
        dialog.addChoice(/kitchen/i, function(msg2) {
            msg2.reply("On it boss!");
        });
        dialog.addChoice(/bathroom/i, function(msg2) {
            msg.reply("Do I really have to?");
            dialog.addChoice(/yes/, function(msg3) {
                msg3.reply("Fine, Mom!");
            });
        });
    });

该explmate为robot接收一个clean the house的消息后以reply的形式返回Sure, where should I start? Kitchen or Bathroom 消息,用户再次发送kitchen或者是bathroom,robot将根据用户的再次确认发送消息进行reply。 如用户确认消息为kitchen,则robot以reply的形式回复On it boss! 如用户确认消息为bathroom,则robot以reply的形式回复Fine, Mom!

1
2
3
4
5
6
7
8
9
10
11
robot.respond(/jump/, function(msg) {
        var dialog = switchBoard.startDialog(msg);
        msg.reply("Sure, How many times?");

        dialog.addChoice(/([0-9]+)/i, function(msg2) {
            var times = parseInt(msg2.match[1], 10);
            for (var i = 0; i < times; i++) {
                msg.emote("Jumps"); //We can use the original message too.
            }
        });
    });

该explmate为robot接收一个jump的消息后以reply的形式返回Sure, How many times?询问你要多少次。robot接收一个纯数字的确认消息并返回相应次数的的Jumps 如:用户发送确认消息:4 则将接收到4条robot返回消息 robot:Jumps robot:Jumps robot:Jumps robot:Jumps