小项目自动化部署用 Jenkins 太麻烦了怎么办
导读
本文介绍用 Webhooks 代替 Jenkins 更简单地实现自动化部署。不论用 Jenkins 还是 Webhooks,都需要一定的服务端基础。
Webhooks 的使用更简单,自然功能就不如 Jenkins 丰富,因此更适合小项目。
背景
笔者一直在小厂子做小项目,只做前端的时候,部署项目就是 npm run build
然后压缩发给后端。后来到另一个小厂子做全栈,开始自己部署,想着捣鼓一下自动化部署。
Jenkins 是最流行的自动化部署工具,但是弄到一半我头都大了。我只是想部署一个小项目而已,结果安装、配置、启动 Jenkins 这工作量好像比我手动部署还大呢,必须找个更简单的办法才行。果然经过一番捣鼓,发现 Webhooks 又简单又实用,更适合我们小厂子小项目。
原理
首先我们的项目应该都放在 Git 平台上,主流的 Git 平台上都有 Webhooks。它的作用是:在你推送代码、发布版本等操作时,自动向你提供的地址发一个请求。
你的服务器收到这个请求后,要做的事情就是调用一段事先写好的脚本。这段脚本的任务是拉取最新代码、安装依赖(可选)、打包项目、重新启动项目。
这样当你在 Git 平台上发布版本后,服务器就会自动部署最新代码了。
实现
实现步骤可以和上面的原理反着来:先写好脚本,然后启动服务,最后创建 Webhooks。
在此之前,你的服务器需要先安装 Git,并能够拉取你的代码。这部分内容很常规,看官可以在其他地方搜到。
1. 自动部署脚本
Nuxt
自动部署脚本就是代替我们手动打包、部署的工作。在 Linux 中,它应该写在一个 .sh 文件里。我的前端项目用 Nuxt 开发,脚本主要内容如下:
# 进入项目文件
cd /usr/local/example
# 拉取最新代码
git pull
# 打包
npm run build
# 重启服务
pm2 reload ecosystem.config.js
你可以在 Git 上随便更新点内容,然后在 XShell 或其他工具打开服务器控制台,执行这段代码,然后到线上版本看更新有没有生效。
笔记一开始经过了一番折腾,发现最好得记录部署日志,那样方便排查问题。完整脚本如下:
# 日志文件路径
LOG_FILE="/usr/local/example/$(date).txt"
# 记录开始时间
echo "Deployment started at $(date)" > $LOG_FILE
# 进入项目文件
cd /usr/local/example
# 拉取最新代码
git pull >> $LOG_FILE 2>&1
# 打包
npm run build >> $LOG_FILE 2>&1
# 重启服务
pm2 reload ecosystem.config.js >> $LOG_FILE 2>&1
# 记录结束时间
echo "Deployment finished at $(date)" >> $LOG_FILE
Eggjs
笔者后端用了 Eggjs,其自动部署脚本如下:
# 日志文件
LOG_FILE="/usr/local/example/$(date).txt"
# 记录开始时间
echo "Deployment started at $(date)" > $LOG_FILE
# 进入项目文件
cd /usr/local/example
# 拉取最新代码
git pull >> $LOG_FILE 2>&1
# Egg 没有重启命令,要先 stop 再 start
npm stop >> $LOG_FILE 2>&1
npm start >> $LOG_FILE 2>&1
# 记录结束时间
echo "Deployment finished at $(date)" >> $LOG_FILE
Eggjs 项目没有构建的步骤,其依赖要事先安装好。因此如果开发过程中安装了新依赖,记得到服务端安装一下。
Midwayjs
由于 Eggjs 对 TypeScript 的支持比较差,笔者后来还用了 Midwayjs 来开发服务端,其脚本如下:
# 日志文件
LOG_FILE="/usr/local/example/$(date).txt"
# 记录开始时间
echo "Deployment started at $(date)" > $LOG_FILE
# 进入项目文件
cd /usr/local/example
# 拉取最新代码
git pull >> $LOG_FILE 2>&1
# 重装依赖
export NODE_ENV=development
npm install >> $LOG_FILE 2>&1
# 构建
npm run build >> $LOG_FILE 2>&1
# 移除开发依赖
npm prune --omit=dev >> $LOG_FILE 2>&1
# 启动服务
npm start >> $LOG_FILE 2>&1
# 记录结束时间
echo "Deployment finished at $(date)" >> $LOG_FILE
Midwayjs 的自动部署脚本比较特殊:在 npm install
之前需要先指定环境为 development
,那样才会安装所有依赖,否则会忽略 devDependencies
中的依赖,导致后面的 npm run build
无法执行。这点也是费了笔者好长时间才排查清楚,因为它在 XShell 里执行的时候默认的环境就是 development
,但是到了 Webhooks 调用的时候又变成了 product
。
2. 启动一个独立的小服务
上面这些脚本,应该由一个独立的小服务来执行。笔者一开始让项目的 Eggjs 服务来执行,也就是想让 Eggjs 服务自动部署自己,就失败了。原因是:脚本在执行到 npm stop
时,Eggjs 服务把自己关掉了,自然就执行不了 npm start
。
笔者启动了一个新的 Eggjs 服务来实现这个功能,使用其他语言、框架同理。其中执行脚本的控制器代码如下:
const { Controller } = require('egg');
const { exec } = require('child_process');
class EggController extends Controller {
async index() {
const { ctx } = this;
try {
// 执行 .sh 脚本
await exec('sh /usr/local/example/egg.sh');
ctx.body = {
'msg': 'Deployment successful'
};
} catch (error) {
ctx.body = {
'msg': 'Deployment failed:' + JSON.stringify(error)
};
}
}
}
module.exports = EggController;
如果启动成功,你应该可以在 Postman 之类的工具上发起这个控制器对应的请求,然后成功执行里面的 .sh 脚本。
注意这些请求必须是 POST 请求。
3. 到 Git 平台创建 Webhooks
笔者用的是GitCode,其他平台类似。到代码仓库 -> 项目设置 -> WebHook 菜单 -> 新建 Webhook:
- URL:上面独立小服务的请求地址;
- Token:在 Git 平台生成即可;
- 事件类型:我希望是发布版本的时候触发,所以选
Tag推送事件
。
创建好之后,激活这个 hook,然后随便提交些新东西,到代码仓库 -> 代码 -> 创建发行版:
填写版本号、版本描述后,滑到底部,勾选“最新版本”,点击发布按钮。
这样就能触发前面创建的 WebHook,向你的独立小服务发送请求,小服务就会去调用自动部署脚本。
怎么样,是不是比 Jenkins 简单太多了。当然功能也比 Jenkins 简单太多,但是对小厂子小项目来说,也是刚好够用。
来源:juejin.cn/post/7406238334215520291