GitHub CI/CD | PM2 之 Node 应用文件监听自动重启

1,898 阅读4分钟

前言

最近在做前后端项目的自动部署,原理是通过 github 的 action,在代码 push 到仓库时,自动触发项目打包和部署。有兴趣的小伙伴可以看看我之前的文章有详细的说明。GitHub CI/CD 基础,前端项目云服务器自动化部署
前端项目部署,我们只需要将打包后的 dist 文件夹传输到服务器的目录下即可,网页刷新,就能得到最新的页面。
node 应用部署,我们采用的是 pm2 在服务器管理,同样的方式我们将 node 相关代码传输到服务器上,node 进程是不会重启的。还需要手动登录到服务器去重启对应 Node 应用进程。于是乎,如何不操作服务器,文件变更自动重启 Node 进程呢?

PM2 是什么?

首先,简单介绍下 PM2, 可能还有小伙伴不知道什么是 PM2,PM2 是 node 进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控、自动重启、负载均衡等,而且使用非常简单。更多使用说明请查看官方文档

常用命令

# 启动
$ pm2 start [file_name]

# 重启
$ pm2 restart [app_name|app_id|all]

# 删除
$ pm2 delete [app_name|app_id|all]

# 停止
$ pm2 stop [app_name|app_id|all]

# 显示所有进程状态列表
$ pm2 list

# 查看单个进程详细信息
$ pm2 describe [app_name|app_id]

# 查看进程日志
$ pm2 logs [app_name|app_id]

# 监控
$ pm2 monit

PM2 文件监听-自动重启

最简单的方式就是我们可以再上面的启动命令后面添加 --watch,例如:

pm2 start ./app.js --name app1 --watch

不过 --watch 的方式只能监听 app.js 文件变更,如果想监听特定的文件或文件夹,就得通过配置文件启动。

PM2 配置文件方式启动

除了上面的基础命令行方式启动,我们还可以指定一个配置文件来启动,需要创建一个 ecosystem.config.js 文件。

配置文件

module.exports = {
  apps : [{
    name   : "app1",
    script : "./app.js"
  }]
}

apps中可以同时设置多个应用。通过下面的命令我们就可以批量启动或停止多个应用。

通用配置文件启动

# Start all applications
pm2 start ecosystem.config.js

# Stop all
pm2 stop ecosystem.config.js

# Restart all
pm2 restart ecosystem.config.js

# Reload all
pm2 reload ecosystem.config.js

# Delete all
pm2 delete ecosystem.config.js

最重要的一点就是,我们可以有更多的可选项,例如设置 监听路径

module.exports = {
    apps : [{
      name   : "app1", // app name
      script : "./app.js", // 启动执行文件
      cwd: '/www/server/node/app1/', // script 执行目录
      watch: [ // 监听文件路径
        'app.js',
        'config',
        'controller',
        'utils',
        'models',
        'router',
        'views',
      ],
      watch_delay: 1000, // 文件变化后,延迟重启时间
      ignore_watch: ['node_modules', 'bin', 'client-vue'] // 监听忽略路径
    }]
  }

上面最重要的属性就是 watch 属性,它可以为 Boolean, 为 true 时等价于 pm2 start ./app.js --name app1 --watch。watch 为 Array 时,就可以自定义监听文件路径。

配置文件基础选项

除了上面示例配置项,还有如下常用选项,更多请查看 PM2官网-高级选项

字段类型示例描述
name(string)“my-api”应用名称(默认启动文件名)
script(string)”./api/app.js”启动文件的相对路径
cwd(string)“/var/www/”启动文件所在的目录
args(string)“-a 13 -b 12”传给启动脚本的参数
interpreter(string)“/usr/bin/python”启动文件解释器绝对路径(默认 node)
interpreter_args(string)”–harmony”传给解释器选项
node_args(string)解释器选项别名

github action 前后端完整部署流程

name: release

on:
  push:
    branches: master

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: 签出代码
        uses: actions/checkout@master
      - name: 安装 nodejs
        uses: actions/setup-node@v2
        with:
          node-version: "14"
      - name: 安装依赖
        run: npm install
        working-directory: client-vue/mobile
      - name: 前端项目打包
        run: npm run build
        working-directory: client-vue/mobile
      
      - name: 发布腾讯云
        uses: wlixcc/SFTP-Deploy-Action@v1.0
        with:
          username: 'root'
          server: '${{ secrets.TENCENT_SERVER_HOST }}'
          ssh_private_key: '${{ secrets.TENCENT_SERVER_PRIVATE_KEY }}'
          local_path: 'client-vue/mobile/dist/*'
          remote_path: '/www/wwwroot/app1-cline/'
          args: "-o ConnectTimeout=5"
  deploy-serve:
    runs-on: ubuntu-latest
    steps:
      - name: 签出代码
        uses: actions/checkout@master
      - name: 准备好要发布的文件
        run: |
          mkdir deploy
          rsync -av --progress . deploy --exclude .github --exclude client-vue --exclude .gitignore --exclude .github --exclude .git
      - name: 发布腾讯云
        uses: wlixcc/SFTP-Deploy-Action@v1.0
        with:
          username: 'root'
          server: '${{ secrets.TENCENT_SERVER_HOST }}'
          ssh_private_key: '${{ secrets.TENCENT_SERVER_PRIVATE_KEY }}'
          local_path: 'deploy/*'
          remote_path: '/www/server/node/app1-server/'
          args: "-o ConnectTimeout=5"

前端的部署部分不过多讲解,还不了解的可以看看我前一篇文章
这里主要讲解下后端部署流程。在上面的 deploy-serve job 就是后端部署任务,和前端部署部署几乎相似,区别在于多了一个步骤 准备好要发布的文件, 这个步骤其实就是提前筛选出需要上传的后端代码,因为我们的项目前后端代码放在一起,所以需要把后端代码筛选到 develop 文件夹,上传时就直接上传 develop 文件夹就可以了。

总结

通过上面的操作,上传的服务器的 node 后端代码,就能自动重启 Node 服务器。至此,也彻底将我的一个 记账本 app 实现了全流程 DevOps。修改代码提交,就能前后端自动部署的体验确实方便不少,能让开发者更加专注业务开发,而不必花费大量时间在繁琐的部署流程。