使用 Github 的 Webhook 功能进行自动化部署

背景描述

我的服务器上面部署了几个网站应用,拿我的应用在线书签管理系统来说,有一个PC版本,这个是后台跟前端代码在同一个项目的。每一次不管是更新后台代码还是前端代码,我都要使用ssh服务连接到服务器,更新代码然后重新执行命令pm2 restart my-bookmark重启服务。还有一个Mobile版本的,这个版本只是一个前端代码,这个使用Vue开发的,由于我的服务器内存只有1G,导致无法在服务器上打包,所以我需要在本地机器上打完包之后再把最终文件推送到Github,然后再登陆服务器把我推送到Github上的代码clone下来,完成更新。有时候要是经常更新,这种繁琐的重复性操作实在是无聊而且耽误时间。为了解决这题,今天研究了一下Github的Webhook服务,彻底解决此问题。做到的效果就是,当我对 Github 推送 push 代码的时候,我的服务器就自动 git pull 最新代码,然后重启服务(如果需要)。

Webhook配置

进入你的GitHub项目,点 Settings --> Webhooks 进入配置页面,大概如下所示:

稍微解释一下几个配置的意义:

  • Payload URL:这是你服务器的处理url。比如http://webhook.lcq.comhttp:://111.231.72.58:7777/webhook
  • Content Type:按照自己需求选吧。我找的一个 NPM 包是需要选择 application/json 类型的。
  • Secret:密钥。自己填就好了,待会儿服务器要用到的。有了这个密钥,其他人随便给你发的就会触发error了。
  • Which events would you like to trigger this webhook:我其实只要 push 事件通知我就好了。测试的话,你可以选第二个全部试试。第三个就是更加精细的定制化了。
  • Recent Deliveries:这是触发日志事件。成功失败都有详细信息提示。

更加详细的一些信息,参考 Github 的 Webhook 官方文档。

服务器实现

我自己也懒得写了,是用了一个别人写好的 NPM 包 github-webhook-handler。如果你不熟悉Node.js,那么你自己去找相应语言的开源实现,实在找不到,按照官方文档自己写一个也不难的。原理反正就是能接收Post请求就行了。我自己利用那个 NPM 的包服务端大概简单实现如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var http = require('http')
const { exec } = require("child_process");
var createHandler = require('github-webhook-handler')
// path 请按照实际情况填写,secret 就是你在GitHub设置webhook的时候自己填的
var handler = createHandler({ path: '/', secret: 'you secret' })

// 每个项目有推送的时候,相对应的命令执行。
const repUpdate = {
"webhook": "cd /var/www/webhook && git fetch && git reset --hard origin/master && pm2 restart webhook", // 不要忘了,自更新
"blog-static": "cd /var/www/static/blog && git fetch && git reset --hard origin/master",
"my-bookmark": "cd /var/www/my-bookmark && git fetch && git reset --hard origin/master && pm2 restart my-bookmark",
"mobile-my-bookmark-static": "cd /var/www/mobile-my-bookmark/dist && git fetch && git reset --hard origin/master"
}

function excute(repName) {
let cmd = repUpdate[repName];
if (!cmd) return;
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.log(`exec error: ${error}, ${stdout}, ${stderr}`);
}
});
}

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)
excute(event.payload.repository.name);
})

然后,简单测试了一下,满足了自己的需求。爽,哈哈哈!当然,这只是一种简单的需求,我只处理了push事件。还可以利用这个做一些复杂需求,比如团队中有谁提交,有谁发pull Request,都可以发邮件给其他成员等等。大家根据需求挖掘吧。

您的支持将鼓励我继续创作!
0%