回顾一下自己部署服务的变化:

最初学习的时候,部署 ASP, PHP 是通过 FTP(甚至 Web)将 ASP/PHP 文件上传到服务器上。 后来知道有版本控制器之后,将代码托管到版本库,手动通过 ssh 登录服务器更新代码来部署服务, 再后来,知道利用 fabfile.py 等来自动化 ssh 到更新,到部署的过程了。 再后来,学会使用 CI,通过 travis / Jenkins 来自动部署服务。 一直到 ChatOps 实践之前,最便捷的方式是登录 Jenkins,输入 commit sha 来指定构建的版本,进行服务部署。 虽然如此,还是避免不了比较繁琐的人工操作。

Slack / BearyChat / 微信等 IM 发展,已经开始提供 hook 或类似的功能,可以很方便地将聊天跟机器人集成起来, 那么通过 IM 上的聊天来指挥机器人协助我们完成工作也不是难事,自然也可以通过这个方式进行服务部署。

在 vanke 的时候噢,也考虑过通过 BearyChat 的 outgoing 机器人完成服务部署的工作,但疲于业务开发,一直没有实践机会。最近再空闲时间进行了一次简单的 ChatOps 实践:

这次实践使用 BearyChat + GitHub + Hubot + Jenkins 完成部署。

我是会画图的好孩子

由于 BearyChat 和 Hubot 之间已经由 BearyChat 完成,所以整个过程主要在于编写 Hubot。定义 Hubot 命令,然后请求 Jenkins 进行构建。

先在 BearyChat 上创建 hubot 机器人,获得 hubot token,并填入 hubot URL.

根据 https://hubot.github.com 搭建 Hubot 框架

$ npm install yo hubot generator-hubot hubot-bearychat

$ yo hubot

这时候已经可以启动 hubot:

启动之前需要配置环境变量:

  • HUBOT_BEARYCHAT_TOKENS: BearyChat hubot 机器人提供的 tokens

HUBOT_BEARYCHAT_TOKENS=TOKEN ./bin/hubot -a bearychat

hubot 默认监听 8080 端口,可以配置 nginx 做一次反向代理。

启动之后,可以回到 BearyChat,测试 hubot 机器人是否配置成功。

hubot 默认实现了 time 命令,在 BearyChat 私聊 hubot 机器人 time。若返回 Server time is: Wed Nov 09 2016 17:04:15 GMT+0800 (CST) 的消息,表示 hubot 配置成功,接着开始编写命令。

命令处理逻辑都放在 scripts/ 中。

Hubot 默认支持 coffee,但不支持 ES6。 如需要支持 ES6,这里可以在 scripts/ 下新建 000-es6-support.coffee

'use strict'
require 'babel-register'
module.exports = (robot) => {}

同时也需要安装相应的库,babel-register, babel-preset-es2015, babel-plugin-add-module-exports 等。

准备好 Hubot 框架,就可以开始配置 Jenkins 编写相应脚本了。

完整安装了 Jenkins 之后会安装上 GitHub 的 plugins,新建一个 Job 并配置 GitHub 仓库,勾选 Build Triggers 下的 Trigger builds remotely (e.g., from scripts),并填入 Authentication Token

这里还利用了 https://wiki.jenkins-ci.org/display/JENKINS/Build+Token+Root+Plugin 这个插件,支持通过 POST URL 来触发 Build Job

scripts/ 下新建 jenkins.js

'use strict';
require('babel-register');
const JENKINS_URL = process.env.JENKINS_URL;
const JENKINS_JOB_NAME = process.env.JENKINS_JOB_NAME;
const JENKINS_JOB_TOKEN = process.env.JENKINS_JOB_TOKEN;
module.exports = (robot) => {
  robot.respond(/jenkins:build/i, (res) => {
    const url = JENKINS_URL + "/buildByToken/build?job=" + JENKINS_JOB_NAME + "&token=" + JENKINS_JOB_TOKEN;
    robot.http(url).post()((_err, _res, _body) => {
      robot.logger.debug(_body);
      res.reply("Building");
    });
  });
};

执行程序之前,需要设置 4 个环境变量:

  • HUBOT_BEARYCHAT_TOKENS: BearyChat hubot 机器人提供的 tokens
  • JENKINS_URL: Jenkins 的地址
  • JENKINS_JOB_NAME: 想要构建的 Job 名
  • JENKINS_JOB_TOKEN: Job 对应的 Token

$ source $(cat .env | xargs) && ./bin/hubot -a bearychat

回到 BearyChat 私聊 hubot: jenkins:build,如果 jenkins 开始构建,说明 hubot 配置已经成功。 让 hubot 加入到 讨论组后,也可以在讨论组中 @hubot jenkin:build 触发构建。

上例子中的 jenkins.js 只支持一个 job ,命令也只支持 jenkins:build。当然可以修改成支持不同 job。例如 jenkins build fooJob, jenkins build barJob 分别构建 fooJob 和 barJob.