2016-07-13 00:00:00

Node.js:使用hook+shell+git进行自动化构建

自动化构建的含义是很多的,本文只讨论项目的自动化部署方面.

Node.js项目的线上部署流程相对其他语言的项目来说,还算比较简单.但是,一旦需要部署的服务器增多,再简单的部署流程都会耗费很多时间,这时,shell脚本能够帮助我们自动完成服务器内部的部署,我们所需要做的,就是远程触发shell脚本的运行

git远程仓库一般都支持hook(钩子),我们可以设置一个地址,让远程仓库在指定的事件被触发时自动发送一个POST请求,服务器拿到POST之后自动执行shell脚本,shell执行git的拉取代码与重启服务的命令,来进行持续集成.这个流程本文简称为hook+shell+git

与jenkins的对比

目前自动化构建的方案,比较流行的是docker+jenkins

对于本文的自动化部署,相较于hook+shell+git的方案,即便使用了docker免去了java环境的安装,jenkins仍然有一些缺点:

  1. 配置比较繁琐,需要填写的私密数据很多
  2. 无法做到全自动,还是得手动打开jenkins按下立即构建
  3. jenkins需要拉取代码至本机,我们还得另写脚本将其打包,之后发送至服务器再解压,相比git+shell多了整整两次数据传输
  4. jenkins发送至服务器的包在解压前,需要删除旧代码,无法利用之前已经安装好的node_modules,npm install将耗时巨大

因此,本文自动化部署node.js的方案采用hook+shell+git

webhook

以github为例,hook被称为webhook,在仓库的Settings->Webhooks & Services中,可以方便地添加webhook,设置POST地址,如下图

触发器方面,github给出了三个选择,本文选择第一项,即只有push触发,其中第三项提供了多达二十种可选事件 ,非常方便

读者可以在github上初始化一个example仓库,来进行本文的自动化部署

node.js项目

在本地使用express.js,完成一个简单的执行shell脚本的app,取名为webhook

express webhook

在router中添加一个webhook.js,专门来处理webhook路由的post请求

var express = require("express");
var child_process = require("child_process");

var router = express.Router();

/* POST webhook */
router.post("/", function(req, res, next) {
  var std = "Now deploying!"
    child_process.execFile("/alidata/www/courseline.sh",[],{ 
      env : {
        PATH : process.env.PATH,
        HOME : process.env.HOME
      }
    },function(err,stderr,stdout){
      console.log(err,stderr,stdout);
    });

  res.send(std);
});

module.exports = router;

/alidata/www/courseline.sh路径则为服务器上的shell脚本路径

别忘了在app.js添加路由

...
var webhook = require("./routes/webhook");
...
app.use("/webhook", webhook);
...

如果线上服务器已经有express.js跑在3000端口上,那么还需要将本项目的默认端口修改为其他

线上部署的时候可以使用PORT=7777 npm start来指定端口,不过如果使用pm2或者其他管理工具,修改端口会稍微麻烦一点,这里直接修改项目的默认端口

bin/www中,修改var port = normalizePort(process.env.PORT || "3000");中的3000端口为其他端口,本文以7777为例

之后将此项目部署在服务器上

运行

这里我踩了一个坑,pm2的1.1.3版本不能用child_process来调用pm2命令, 会报JSON的错误TypeError: Converting circular structure to JSON,#2077

pm2维护团队号称下一次更新会解决这个问题,但是截止本文发布,pm2已经累积了400+的issue,不清楚pm2目前是个什么状态

使用forever来启动这个项目,即可正常监听

安装forever

npm install -g forever

启动webhook项目

forever start bin/www

shell 脚本进行自动部署

在编写shell脚本前,先在需要自动化部署的项目中初始化git

cd path/to/project
git init .
git remote add origin url/to/remote/git
git pull origin develop

最后一步拉取的分支可以自由选择

现在来编写webhook项目中指定执行的那个shell脚本,/alidata/www/courseline.sh

cd path/to/project
pm2 stop your-project
git pull origin develop
npm install
pm2 start your-project

编写完毕后,再给shell脚本加上执行权限,chmod 777 *.sh.可以直接跑一下这个脚本,测试一下是否有问题.

自动化部署

修改github仓库中webhook的POST,改为服务器http://host:7777/webhook

现在,对github仓库上任一的push,都会触发POST请求,POST被收到后会自动运行shell脚本,来进行自动化部署

之后就是配置nginx来进行反向代理,还可以修改webhook的Secret字段,加一步服务器验证

另外,github上除了支持自定义webhook外,也支持功能更加强大的service,例如集成测试用的Travis CI,CircleCI,以及魔性的Slack

自动化部署的意义是很大的,例如我有一次手动部署时忘记了npm install,导致新加进来的模块没有被require到,直接502瘫掉了nginx,排错排了几个小时才排出来.使用hook进行自动化部署,就可以完全避免这种错误

本文链接:https://smallpath.me/post/Node.js:使用git和webhook进行自动化构建

-- EOF --