Node + Git + Webhook 自动化部署

前言

以前断断续续在重构一个项目,而后发现功能一开始设计太多了,可能须要花大量时间来增长,可是核心功能基本完成,因而想着能不能半上线状态,而后经过更新提交git,让服务器部署自动更新。这以前接触过git hook是能够实现的,所以这里记录一篇文章边捣鼓边写。php

正文

准备

首先肯定须要完成的内容,明确需求:html

1.监听指定 git 提交
2.执行指定多个脚本

并且由于我这边是须要分别对clientserver 目录分别执行部署命令。因此须要特别处理。前端

首先去域名管理那边增长一条A记录指向新的项目名称.由于Webhooks是须要外网域名的,所以先提早加一条。new.xxx.comnode

而后就是须要对服务器上Nginx作转发配置。nginx

个人nginx是好久以前配置的git

etc/nginx/conf/vhost里增长一个文件,里面写入以下内容:github

server
        {
                listen 80;
                server_name new.xxx.com;
                index index.html index.htm index.php default.html default.htm default.php;

                location / {

                        proxy_pass http://127.0.0.1:8801;
                }
                access_log off;

        }

将本地的8801转发出去。web

而后重启一下Nginx nginx -s reloadmongodb

而后git clone 仓库typescript

由于项目用了mongodb数据库:
须要建立一个对应的数据库并添加权限。

1. 切换数据库到 abc
2. 指定了数据库 abc ,拥有权限: userAdmin
 db.createUser(
   {
     user: "123",
     pwd: "123",
     roles: [ { role: "userAdmin", db: "abc" } ]
   }
 )
 3. 验证下上面建立的帐号 123

 db.auth('123','123')
 => 1

配置webhook

这个实际上是最简单的,只要在你的github对应的项目仓库右侧选择settings

而后选择webhooks

imgn

选择add webhook

而后按照以下配置便可:

imgn

这里须要记住你本身设置的secret 以及你定义的推送动做,我这里是pushCode

开始写脚本

写以前先来看下最终的目录结构:

├── README.md
├── clean.sh // 清理缓存,而且执行git命令
├── client
│   ├── autoClient.sh // client端自动监听
│   ├── build
│   ├── config
│   ├── package.json
│   ├── public
│   ├── scripts
│   ├── src
│   ├── tsconfig.json
│   ├── tsconfig.test.json
│   ├── tslint.json
│   ├── www
│   ├── yarn.lock
├── deploy
│   └── index.js // 监听webhook事件而后依次执行 clean.sh autoClient.sh autoServer.sh
├── package.json
├── server
│   ├── autoServer.sh // server端自动监听
│   ├── dist
│   ├── package.json
│   ├── src
│   ├── tsconfig.json
│   ├── tslint.json
│   └── yarn.lock

由于项目缘由,脚本还须要作一些定制。
首先是client端,由于前端是用了typescript + React全家桶 因此打包起来特别慢,当在服务器build的时候,由于阿里云内存给的不够,因此会很卡。基于这个考虑,是打算本地bulid完以后,推送到git上,服务器去git pull

并且前端还有个考虑是用什么跑前端代码。由于服务器没装相似服务,所以打算用node框架koa起一个HTTP服务来跑。

代码以下:

www目录中

app.js

const Koa = require('koa')
const morgan = require('koa-morgan')
const path = require('path');
const static = require('koa-static')
const fs = require('fs')
const app = new Koa();
// logger
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms'));
// static assets
app.use(static(path.join(__dirname,'../build')));
//异步读取文件的形式
// app.use(async (ctx,next) =>{
//     ctx.type = 'html';
//     ctx.body = await fs.createReadStream(path.resolve(__dirname, '..', './build', 'index.html'));
// })
module.exports = app;
index.js

'use strict';
const app = require('./app');
const PORT = process.env.PORT || 8801;
console.log('client start')
app.listen(PORT, () => {
  console.log(`App listening on port ${PORT}!`);
});

这样经过命令node ./www/index.js可以监听同级build目录。

固然这比较粗暴,还须要慢慢改进。

咱们须要在client目录下创建autoClient.sh

#! /bin/bash
cd ./
echo 'client build'
kill -9 $(lsof -i:8801 |awk '{print $2}' | tail -n 2) 
node ./www/index.js

用来自动执行监听动做。

由于屡次推送监听的前端端口一致,若是不处理会报错。须要先根据端口号8801结束进程而后从新开启服务。

而后是server端,由于整个后端是用koa完成的,项目比较小,在服务端即时编译花费不了多少时间,所以直接执行yarn start( "start": "yarn run build && yarn run watch",)用来编译和监听。

server目录里创建autoServer.sh

#! /bin/bash
cd ./
echo 'server start'
kill -9 $(lsof -i:8866 |awk '{print $2}' | tail -n 2) 
yarn run start

一样咱们须要在执行监听以前结束上一个端口的进程。

而后咱们来看clean.sh 这个shell脚本是用来清理client目录下build文件夹。

#! /bin/bash
rm rf ./client/build
git reset --hard origin/master
git clean -f
git pull

能够看到 先清理了缓存而后再向服务器拉取代码.

最后咱们来看部署的脚本deploy/index.js

var spawn = require('child_process').spawn
var http = require('http')
var spawn = require('child_process').spawn
var createHandler = require('github-webhook-handler')
var handler = createHandler({ path: '/pushCode', secret: 'xxx' }) // 根据git上webhook的配置填写
http.createServer(function (req, res) {
  handler(req, res, function (err) {
    res.statusCode = 404;
    res.end('no such location')
  })
}).listen(7777)

handler.on('error', function (err) {
  console.error('Error:', err.message)
})

// 监听 push 事件
handler.on('push', function (event) {
  console.log('Received a push event for %s to %s',
    event.payload.repository.name,
    event.payload.ref)
    init() // 每次拉取都从新监听
}
)
function rumCommand( cmd, args, cwd, callback ) {
  var child = spawn( cmd, args, {cwd: cwd} )
  var response = ''
  child.stdout.on('data', function( buffer ){ response += buffer.toString(); })
  child.stdout.on('end', function(){ callback( response ) })
}

function init() {
  rumCommand('sh', ['../clean.sh'], './' ,function( result ) { // 清理缓存
    console.log(result)
  })

  rumCommand('sh', ['../server/autoServer.sh'], '../server' ,function( result ) { // cLient端更新
    console.log(result)
  })
  
  rumCommand('sh', ['../client/autoClient.sh'], '../client' ,function( result ) { // server端更新
    console.log(result)
  })

}

init() // 脚本运行第一次默认指向一次

这里须要声明的是由于多目录下执行脚本须要对应的环境。所以才把脚本都分开放。

部署

部署咱们只须要对pm2 start deploy/index.js

而后就能够在本地开发完以后推送,服务器就能自动拉取代码而且部署。

相关文章
相关标签/搜索