码农这个行业里前端是个另类,在大牛眼里前端“毫无难度”可言,在小白眼里前端炫酷的“所见即所得”。也许正是因为前端的低门槛、不需要什么复杂的开发环境甚至有“记事本”就能开发,以至于很多小公司的前端工程师从未正视过前端部署问题(包括我所在的公司)。
小公司人力有限,所以多数小公司的技术团队配置都是后端居多,在后端眼里前端就切切页面然后往服务器丢一下就好了嘛。然而就是这个问题困扰了我很久,我一直觉着这样 FTP 的方式往服务器拖前端内容“非常傻”,又苦于没有太好的思路和解决方案(其实主要受制于不懂后端🌚)。
直到…….看到了 Webhook …..
原理
其实网上这类教程很多了,但是多数写的都是思路和大概的流程,毕竟咱都是小白爬上来的,深知宝宝们心里有多苦😢,所以本文就详细说一下吧。
基本原理是后端开一个单独的端口跑一个服务器,只监听固定的接口请求(A接口),通过 GitHub 的 Webhook 功能关联上此接口,这样每次向 GitHub 提交东西都是自动发出一个 post 请求到 A 接口,A接口收到 post 会执行一个 shell 脚本,自动通过 Git 方式拉取 GitHub 上的静态资源(HTML、CSS、JS)
所以分解一下就是三个过程
- 目标位置创建 Git 仓库
- shell 脚本
- 服务端监听接口post(Node、PHP等后端语言均可),GitHub/GitLab 开启 Webhook
操作
以 Node.js 的后端环境为例,假设正式服务器是基于 express
在 /root 目录下创建 testWebhook 项目
目标位置创建 Git 仓库
首先你要在你想要需要部署静态资源的位置创建 Git 仓库,这里可以直接使用 git clone
去直接 clone
并关联,不推荐 git init
再 git remote add
,因为对于此处而言只是要不断的 检出 新版本,并不需要对远端仓库有什么提交性质的操作。具体的作用看下一步的 shell 脚本就明白了。
|
|
shell 脚本
新建 deploy.sh 内容如下,主要功能就是 GitHub post 过来的时候,目标路径去远端的 Git 仓库更新代码并 checkout
最新版本
|
|
开启服务器监听 post
创建一个简单的 Node 服务器,只监听 GitHub Webhook,每次接口被触发的时候执行本地 deploy.sh,具体步骤如下:
初始化
npm
,然后本地安装github-webhook-handler
中间件,用来配置 GitHub Webhook ,此插件可以配置secret
参数,这个参数是用来验证接口安全的,具体后面再说。其实这个地方很多教程都说要全局安装
github-webhook-handler
,可是我实在不明白为什么要全局安装,而且我尝试过全局安装 require 的时候会提示模块不存在,还请知道的同学指点一二。1234npm initnpm install github-webhook-handler --save-dev# GitLab 中# npm install gitlab-webhook-handler --save-dev你甚至可以将上一步的 shell 也放在这个文件夹中,方便统一管理。
开启服务器监听 post
1234567891011121314151617181920212223242526272829303132333435363738394041424344var http = require('http')var createHandler = require('github-webhook-handler')// GitLab 中// var createHandler = require('gitlab-webhook-handler')var handler = createHandler({ path: '/testwebhook', secret: 'testwebhook' })// 上面的 secret 保持和 GitHub 后台设置的一致function run_cmd(cmd, args, callback) {var spawn = require('child_process').spawn;var child = spawn(cmd, args);var resp = "";child.stdout.on('data', function(buffer) { resp += buffer.toString(); });child.stdout.on('end', function() { callback (resp) });}http.createServer(function (req, res) {handler(req, res, function (err) {res.statusCode = 404res.end('no such location')})}).listen(7777)handler.on('error', function (err) {console.error('Error:', err.message)})handler.on('push', function (event) {console.log('Received a push event for %s to %s',event.payload.repository.name,event.payload.ref);run_cmd('sh', ['./deploy.sh'], function(text){ console.log(text) });// 此处相对路径必须 './' 开头})/*handler.on('issues', function (event) {console.log('Received an issue event for % action=%s: #%d %s',event.payload.repository.name,event.payload.action,event.payload.issue.number,event.payload.issue.title)})*/写好就可以启动了
12#启动监听node deploy.jsGitHub/GitLab 中的设置
在 GitHub 中点击仓库的 Settings/Webhooks,如图
PlayloadURL 上填你的服务器IP+端口+接口,如“ http://192.168.0.1:3000/testwebhook ”
Secret 填约定密钥,这样保证只有你从 GitHub 往你的服务器 Post 时是可信赖的。填好后,GitHub 就立即 Post,你可以看到是否成功,如果显示为一个红色的 ”X“ ,那就要排查一下是不是哪里错了,通常都是 deploy.js 或者 deploy.sh 中的路径错误。
如果你使用的 GitLab,设置基本相同。
补充黑科技
用 Node 的同学应该都会遇到和我一样的困惑,这个 Node 每次启动了都是前台运行啊,那岂不是我的 bash 一直不能关闭,一直开着??当然不是!这就要祭出 Linux 上常用到的黑科技了 —- forever 进程守护了
简单说 forever 可以挂起任务,让它们后台运行,使用也很简单
|
|
再次补充说明
如果用 CentOS6 的同学连不通的时候注意一下防火墙是否开放了端口,操作如下
|
|
参考资料:
使用 GitHub / GitLab 的 Webhooks 进行网站自动化部署
Webhook 实践 —— 自动部署
利用Github的Webhook功能和Node.js完成项目的自动部署
CentOS防火墙开放和关闭端口(iptables)