花1.png

Nuxt3全栈项目使用GitHub Actions自动化部署到云服务器(包含pm2、gh、Nginx代理)

概述:从零到1实现自动化部署一个Nuxt3的全栈项目,并使用Nginx代理到指定域名,包含提交release文件到github,gh拉取release文件到云服务器进行部署,并介绍了部署私有github的授权流程

开发环境

云服务器操作系统:Ubuntu22

Node:v20.12.2

pm2:v5.4.2

nuxt 3.14.1592

vue 3.5.13

vue-router 4.5.0

本地

创建nuxt3项目

npx nuxi@latest init nuxt3_test

根目录增加pm2配置文件ecosystem.config.cjs

// ecosystem.config.cjs 
module.exports = {
  apps: [
    {
      name: "BlogHomeNuxt",
      exec_mode: "cluster",
      script: ".output/server/index.mjs",
      args: "", // 传递给脚本的参数
      watch: false, // 开启监听文件变动重启
      // ignore_watch: ["node_modules", "public", "logs"], // 不用监听的文件
      exec_mode: "fork",// 自家主机window cluster_mode 模式下启动失败
      instances: "2", // max表示最大的 应用启动实例个数,仅在 cluster 模式有效 默认为 fork
      autorestart: true, // 默认为 true, 发生异常的情况下自动重启
      // max_memory_restart: "1G",
      // error_file: './logs/app-err.log', // 错误日志文件
      // out_file: './logs/app-out.log', // 正常日志文件
      merge_logs: true, // 设置追加日志而不是新建日志
      log_date_format: "YYYY-MM-DD HH:mm:ss", // 指定日志文件的时间格式
      min_uptime: "60s", // 应用运行少于时间被认为是异常启动
      max_restarts: 30, // 最大异常重启次数
      restart_delay: 60, // 异常重启情况下,延时重启时间
      env_production: {
        // 环境参数,当前指定为生产环境
        NODE_ENV: "production", 
        PORT: "3000",
      },
    },
  ],
};

安装Pm2测试本地服务启动

#安装pm2
npm i pm2 -g
# 到项目根目录执行ecosystem.config.cjs
# 因为"type": "module",情况下需要cjs配置文件
>npm run build
>pm2 start ecosystem.config.cjs
[PM2][WARN] Applications BlogHomeNuxt not running, starting...
[PM2] App [BlogHomeNuxt] launched (2 instances)
┌────┬─────────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name            │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼─────────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0  │ BlogHomeNuxt    │ default     │ 0.0.0   │ fork    │ 23700    │ 0s     │ 0    │ online    │ 0%       │ 31.9mb   │ test     │ disabled │
│ 1  │ BlogHomeNuxt    │ default     │ 0.0.0   │ fork    │ 21996    │ 0s     │ 0    │ online    │ 0%       │ 31.8mb   │ test     │ disabled │
└────┴─────────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

创建github仓库

创建新github仓库按命令执行

配置github action

GitHub Actions 的配置文件叫做 workflow 文件,存放在代码仓库的**.github/workflows**目录。

workflow 文件采用 YAML 格式,文件名可以任意取,但是后缀名统一为.yml,比如foo.yml。一个库可以有多个 workflow 文件。GitHub 只要发现.github/workflows目录里面有.yml文件,就会自动运行该文件。

创建publishFlow.yml文件测试是否可以正确创建release版本

github action基础可以看阮一峰教程:https://www.ruanyifeng.com/blog/2019/09/getting-started-with-github-actions.html

获取账户的token

因为是测试下面的权限全部勾选,如果想要仔细了解请查阅资料

复制创建的token

设置secrets变量

进入Settings =>Actions secrets and variables =>actions 配置变量

填写刚才复制的token

在根目录增加.github\workflows\publishFlow.yml

#publishFlow.yml 自动化部署名称
name: Publish test

# 触发部署的条件: 当 main 分支, 监听tag的版本提交 例如:提交v1.0.0版本就会触发构建
on:
  push:
    tags: # 此处不仅限于监听分支, 还可监听 tag
      - 'v*'
    paths-ignore: # 下列文件的变更不触发部署,可以自行添加
      - README.md
      - LICENSE

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest # 使用ubuntu系统镜像运行自动化脚本
    steps: # 进入自动化步骤
      # 第一步,下载代码仓库
      - name: Checkout
        uses: actions/checkout@main

      # 打包构建
      - name: Build
        uses: actions/setup-node@main
        with:
          node-version: '20.18.0'
      - run: npm i pnpm -g
      - run: pnpm install
      - run: npm run build
      - run: tar -zcvf release.tgz .output
      # 发布版本 Release
      # 与 Github 建立连接( 此处用于将 release.tgz 上传到 github 上 )
      - name: Create Release
        id: create_release
        uses: actions/create-release@main
        env:
          GITHUB_TOKEN: ${{ secrets.TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          draft: false
          prerelease: false
      - name: 获取分支名称
        id: branch-names
        uses: tj-actions/branch-names@v8
      - name: 在标签分支上运行。
        run: |
          echo "运行于: ${{ steps.branch-names.outputs.tag }}"
      # 上传构建结果到 Release
      # 将 release.tgz 上传到 github 上
      - name: Upload Release Asset
        id: upload-release-asset
        uses: actions/upload-release-asset@main
        env:
          GITHUB_TOKEN: ${{ secrets.TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./release.tgz
          asset_name: release.tgz
          asset_content_type: application/x-tgz

测试action,获取release版本

git tag v1.0.1
git push origin v1.0.1

查看构建流程

云服务器

购买云服务器:阿里云、腾讯云、华为云等,选择ubuntu操作系统

安装宝塔面板

1、命令安装

我是用的是ubuntu操作系统所以使用命令安装稳定版

wget -O install.sh https://download.bt.cn/install/install_lts.sh && sudo bash install.sh ed8484bec

2、安装结束后会显示外网地址

3、安装完成根据获取的账户密码进行访问宝塔面板

gh鉴权拉取代码

如果使用的私有仓库需要鉴权,全流程参考:gh鉴权拉取私有仓库

# 安装gh
sudo apt install gh
cd /www/server/
gh repo clone user/nuxt_test
cd nuxt_test
gh release download v1.0.1

此时我们查看我们的文件已经有release文件了

安装Node环境和pm2

1、选择node项目后会提示安装node环境

2、进入node版本管理器:①更新版本列表,如果没有最新版本,则选择②切换一下registry源。③下载20.12.2的node版本也是我本地开发版本。④切换到v20.12.2版本

3、点击模块进入并安装[email protected]版本,如果提示安装失败,①多且切换一下registry源,重新进入页面刷新下看看,有时候提示失败但是已经安装上去了,去/www/server/nodejs/v20.12.2/lib/node_modules/pm2查看是否存在pm2包,为什么使用[email protected]版本,因为需要和node版本匹配,也是我测试多次发现的错误问题。

4、进入像文件内,解压之前下载的release文件,执行pm2命令

> tar -zxvf release.tgz
> cd /www/server/nuxt_test
> pm2 start ecosystem.config.cjs
[PM2][WARN] Applications BlogHomeNuxt not running, starting...
[PM2] App [BlogHomeNuxt] launched (2 instances)
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0  │ BlogHomeNuxt       │ fork     │ 0    │ online    │ 0%       │ 29.6mb   │
│ 1  │ BlogHomeNuxt       │ fork     │ 0    │ online    │ 0%       │ 27.6mb   │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

此时我们已经可以通过ip:3000来访问我们的项目了

安装并配置Nginx代理

我们此时启动到我们服务器的3000端口,所以我们需要**[ip]:3000**才可以访问,那么我们想要直接访问ip直接访问到我们的页面有两种方法,1、改变我们服务启动发端口。2、使用Nginx代理。

使用Nginx代理的原因还有就是可以配置我们的域名代理到我们的3000端口。

由于没有购买域名,此次就使用80端口代理到3000端口来使用。

1、进入宝塔的反向代理页面,没有安装的话会提示你安装。

2、①是我们需要填写的访问地址也就是我们的IP公网地址,②是我们要代理到的地址也就是我们的IP:3000

3、此时我们直接访问我们的IP地址不需要使用3000也可以访问了

修改yml文件内容连接服务器实现自动化部署

修改yml文件

# 自动化部署名称
name: nuxt_test

# 触发部署的条件: 当 main 分支, 有 push 的操作, 即可触发。
on:
  push:
    tags: # 此处不仅限于监听分支, 还可监听 tag
      - 'v*'
    paths-ignore: # 下列文件的变更不触发部署,可以自行添加
      - README.md
      - LICENSE

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest # 使用ubuntu系统镜像运行自动化脚本
    steps: # 进入自动化步骤
      # 第一步,下载代码仓库
      - name: Checkout
        uses: actions/checkout@main

      # 打包构建
      - name: Build
        uses: actions/setup-node@main
        with:
          node-version: 'v20.12.2'
      - run: npm i pnpm -g
      - run: pnpm install
      - run: npm run build
      - run: tar -zcvf release.tgz .output
      # 与 Github 建立连接( 此处用于将 release.tgz 上传到 github 上 )
      - name: Create Release
        id: create_release
        uses: actions/create-release@main
        env:
          GITHUB_TOKEN: ${{ secrets.TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          draft: false
          prerelease: false
      - name: 获取分支名称
        id: branch-names
        uses: tj-actions/branch-names@v8
      - name: 在标签分支上运行。
        run: |
          echo "运行于: ${{ steps.branch-names.outputs.tag }}"
      # 上传构建结果到 Release
      # 将 release.tgz 上传到 github 上
      - name: Upload Release Asset
        id: upload-release-asset
        uses: actions/upload-release-asset@main
        env:
          GITHUB_TOKEN: ${{ secrets.TOKEN }}
        with:
          upload_url: ${{ steps.create_release.outputs.upload_url }}
          asset_path: ./release.tgz
          asset_name: release.tgz
          asset_content_type: application/x-tgz

      # 部署到服务器
      - name: Deploy
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }} # 公网 IP 或 域名
          username: ${{ secrets.USERNAME }} # 登录名
          password: ${{ secrets.PASSWORD }} # 密码
          port: ${{ secrets.PORT }} # 端口
          # 类似在服务端的终端-执行以下操作
          # 1. 找到需要存放文件的地方
          # 2. 拉取release版本
          # 3. 解压 release.tgz 文件
          # 5. 重启 pm2, 并执行 ecosystem.config.cj ,
          script: |
            export NODE_HOME=/www/server/nodejs/v20.12.2/
            export PATH=$PATH:$NODE_HOME/bin
            cd /www/server/nuxt_test
            sudo git pull
            sudo rm -f release.tgz
            sudo gh release download ${{ steps.branch-names.outputs.tag }}
            sudo tar -zxvf release.tgz
            pm2 restart ecosystem.config.cjs

配置github变量

变量配置可以参考之前TOKEN的配置,以下做新增加的变量说明

HOST:# 公网 IP 或 域名

USERNAME:# 云服务登录名

PASSWORD:# 云服务器密码

PORT:22 # 一般默认为22端口

错误:pm2命令报错: command not found

由于宝塔使用了多版本的node管理所以我们需要连接后后设置一下环境变量

....
export NODE_HOME=/www/server/nodejs/v20.12.2/
export PATH=$PATH:$NODE_HOME/bin
....

最后执行命令

更改app.vue文件

// app.vue
<template>
  <div>
    <h1>哈哈哈哈哈哈 弯的four</h1>
    <NuxtRouteAnnouncer />
    <NuxtWelcome />
  </div>
</template>

git add .
git commit -m "构建"
git push
git tag v1.1.1
git push origin v1.1.1

直接输入IP查看页面

总结

整体的思路是利用github action的命令来实现自动化部署

步骤就是提交上传自己的tag为release文件,然后连接云服务拉取git项目,使用gh拉取release版本文件解压,然后执行pm2命令进行服务启动

Created By @Seeyou | 稀有博客