Vue项目自动部署【精简版】NuxtJS + GitHub Actions + Linux 自动部署学习(包含阿里云Linux ECS购买过程、传统部署流程、pm2、Github Actions)

购买阿里云Linux服务器

如果已有服务器请直接跳转到【传统部署方式】

登录阿里云,访问 云服务器 ECS 购买地址:https://ecs-buy.aliyun.com/

也可从首页导航菜单进入。

购买方式

  • 一键购买 - 整合了一些常规配置选项,选择后直接确认订单。
    • 一键购买提供的实例规格(服务器配置)都是【突发性能实例 t5】
  • 自定义购买 - 按步骤完全自定义选择配置(推荐)
    • 有更多的实例规格选择

当前购买的配置,在后期都可以通过升级调整,优惠按照当时的活动。

比如今天选好了配置并购买,第二天升级,优惠保持不变(客服说的,大致意思是这个,最好再和客服确认清楚)

本人的购买原则是【便宜】,下面是具体介绍。

下面是自定义购买的一些介绍,没讲到的就是默认选择了。

付费模式

在这里插入图片描述

客服和我说,如果不经常使用,可以选择【按量付费】。

我的考虑是:

  • 本人懒得管理,所以不会主动去操作停机
  • 依然是因为懒得管理,万一里面不小心放了个消耗流量应用,或存在被外部持续访问的各种可能性,本人又不是很懂,担心这种风险导致流量超额
  • 包年包月有优惠

所以我这样的懒人就选择了【包年包月】

地域及可用区

在这里插入图片描述

刚进来默认选择的是【南京】,还有其他选择。

客服的说法是:访问服务器的IP地域 距离 服务器地域 越近,访问速度越快。

推荐购买离你所属地区近的地域。

另一个考虑:【张家口】和【呼和浩特】本人购买时有优惠(该优惠主要是 t5 相对便宜些,其他的没变化)。

所以本人买的最便宜的【张家口】(t5 17.1元/月)

实例

由于本人只是个人学习用,彼时只是发布一个站点,没有任何数据交互,所以选择了1核1GB。并且选择了最便宜的 t5 实例。

本着不够用的话后期再升级的目的,选择了最便宜的实例。

实例规格 - 突发性能实例 t5:

在这里插入图片描述

在【自定义购买】页面可以查看明细对比。

【突发性能实例 t5(后面简称 t5)】相对便宜很多。

它的 “平均基准CPU计算能力” 特意标识了 20%。

大致意思就是当服务器CPU占用超过20%后,会很卡。

其他的实例就是当CPU占用达到100%后才会很卡。

这是阿里云发现很多用户的ECS并没有经常被使用,而提供出的一种优惠选择。

更详细的介绍可以百度,有很多文章讲的很细。

本人之前有一次购买经验,仅供参考:

当时搭建了一个自用的后台系统。

购买的配置是1核1GB(还是标准型的),mysql数据库,20GB数据盘,1M带宽。

使用时访问很慢,于是升级为1核2GB,并升级了带宽(1M 升级为 4M),之后访问正常。

原因没搞懂,因为懒。。。

镜像

因为学习Linux系统,所以镜像选择了 Ubuntu 最新版本。

主要原因:社区庞大。

参考文章:CentOS和Ubuntu有什么区别,哪个更好?

远程连接 Ubuntu 后的界面:

在这里插入图片描述

存储

使用了默认的配置,这次没有购买数据盘。后期需要再升级。

在这里插入图片描述

网络和安全组

下一步进入【网络和安全组】,根据个人需要配置,本人看不懂所以基本上都是默认选择。

  • 带宽计费模式:同收费模式一样,本人选择了【按固定带宽】收费
  • 带宽值:网友都是1M就够了,这次就选择了1M,不够再升级

参考文章:

系统配置

下一步进入【系统配置】。

在这里插入图片描述

登录凭证:

  • 密钥对,需要创建密钥
    • 官方文档
    • 注意:如果使用SSH密钥对登录Linux实例,将会禁用密码登录
  • 自定义密码
    • 可以用ssh连接服务器时通过输入密码登录
  • 创建后设置 - 不设置 密钥对/密码 默认选择了这项
    • 创建实例(购买后),如需登录,需要重置密码(设置密码),或创建密钥对。

购买时长

购买时长是一直保持在底部的,可以即时计算价格。

根据本人计算,时间越久,优惠越大,建议购买长点的,因为续费很贵!!!!!!

(官方有续费优惠活动,但是力度不大。也可选择到期重新买,只是需要手动转移数据等事情)。

连接测试

购买成功后,通过网站右上角进入控制台:

在这里插入图片描述

查看云服务器ECS -> 查看实例 -> 实例详情 ->重置密码:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

重置密码后需要重启实例。

使用win10系统的内置应用 openSSH 连接远程服务器,如果没有安装,需要手动安装一下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

安装后打开命令行工具或 Powershell:

# Linux 默认登录名 root
# ip 输入实例的公网IP(在实例详情中可以找到)
ssh [登录名]@[ip]
# 执行命令后会要求输入密码(密码不会显示在命令行中,输完直接回车即可)

连接成功:

在这里插入图片描述

端口添加访问权限

本案例发布的项目使用Nuxt默认3000端口,阿里云服务器默认没有为这个端口添加访问权限,需要手动添加:

进入控制台-安全组,点击进入安全组规则:

在这里插入图片描述

手动添加规则:

在这里插入图片描述

Linux常用命令

  • cd 切换目录
  • ls 查看当前目录下文件
  • ls -a 查看所有文件(包含.开头的隐藏目录)
  • df 查看磁盘占用
  • apt install <appname> 安装软件
  • apt remove <appname> 写在软件
  • rm <filename> -i 彻底删除文件(会询问)
  • clear 清空命令行
  • exit 退出连接
  • whereis <appname> 查看软件安装路径
  • env 显示环境变量
  • echo $PATH 打印path路径变量
  • cat <filepath> 查看文件全部内容
  • rm rf * 强制删除当前目录下所有文件

软件安装

新安装的ubuntu系统的 /etc/apt/source.list 中的源比较旧了,需要更新一下,更新方法:apt -y update

否则安装软件会失败,例如安装 unzip

Reading package lists... Done
Building dependency tree
Reading state information... Done
Package unzip is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'unzip' has no installation candidate

unzip安装

如果服务器未安装unzip,使用unzip命令失败会提示安装unzip:

apt install unzip

nvm - node版本管理工具

node多版本管理工具主流有:nvm 和 n。

具体选择可以百度,搜索“管理 node 版本,选择 nvm 还是 n?”。

这里使用 nvm官方安装教程

  1. 下载 nvm 安装脚本 并 运行
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
# or
# wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
  1. linux下安装完后执行 nvm -v 如果报找不到该命令

官方:关闭终端,重新打开,再次执行。

  1. 接着就可以安装node了
nvm install node
# or
# nvm install 12.17.0
# 查看node版本列表
nvm list
# 指定node版本
nvm use 12.17.0

传统部署方式

传统部署流程

  • 配置 Host + Port

  • 压缩发布包

  • 把发布包传到服务端

    • Linux 上的 scp 命令
  • 解压

  • 安装依赖

  • 生产环境启动服务

配置 Host + Port

nuxt.config.js中的server属性

  • host
    • 默认 localhost 只能本地访问
    • 对外访问需设置为 0.0.0.0
      • 会监听所有网卡地址
  • port - Nuxt 默认 3000

压缩发布包

需要传到服务器上的文件包括:

  • .nuxt
  • static
  • nuxt.config.js
  • package.json
  • package-lock.json

上传到 Linux 服务器

vscode 终端连接服务器

# 连接服务器
ssh [username]@[ip]
# 展示目录
ls
# 创建目录
mkdir realworld-nuxtjs
# 进入目录
cd realworld-nuxtjs/
# 展示路径
pwd
# 登出
exit
# 上传本地资源到服务器(此时已经退出ssh链接,在本地执行命令)
scp .\realworld-nuxtjs.zip [username]@[ip]:[pwd地址]
# 再次连接服务器
ssh username@ip
# 进入目录
cd realworld-nuxtjs/
# 展示目录
ls
# 解压压缩包(需要服务器已安装unzip)
unzip realworld-nuxtjs.zip
# 查看目录 添加 -a 可以显示隐藏目录 .nuxt
ls -a
# 安装依赖
npm i
# 启动web服务
npm run start

现在就可以使用公网IP+端口号访问(如果访问失败可能是端口未添加对外访问权限)。

使用 PM2 启动 Node 服务

上面在vscode的命令行通过npm run start启动的web服务。

它现在占用着命令行,如果命令行退出,这个服务就关闭了。

pm2 是专门用来管理 Nodejs 进程的应用。

通过它,就可以将 Nodejs 相关的应用,运行在后台,保持运行状态。

当前应用的启动脚本是通过npm启动的,不是执行一个脚本文件,可以 pm2 执行 npm 然后传参:

pm2 start npm -- start
# 此时任务名为npm,自定义名称(--name参数一定要在前面):
# pm2 --name <task_name> start npm -- start

windows 问题

pm2 start npm -- start 在window环境下启动的服务状态是 stopped。

报错日志:

0|RealWorl | :: Created by npm, please don't edit manually.
0|RealWorl | ^
0|RealWorl |
0|RealWorl | SyntaxError: Unexpected token :
0|RealWorl |     at Module._compile (internal/modules/cjs/loader.js:872:18)
0|RealWorl |     at Object.Module._extensions..js (internal/modules/cjs/loader.j
s:947:10)
0|RealWorl |     at Module.load (internal/modules/cjs/loader.js:790:32)
0|RealWorl |     at Function.Module._load (internal/modules/cjs/loader.js:703:12
)
0|RealWorl |     at Object.<anonymous> (D:\software\nvm\v12.10.0\node_modules\pm
2\lib\ProcessContainerFork.js:32:23)
0|RealWorl |     at Module._compile (internal/modules/cjs/loader.js:936:30)
0|RealWorl |     at Object.Module._extensions..js (internal/modules/cjs/loader.j
s:947:10)
0|RealWorl |     at Module.load (internal/modules/cjs/loader.js:790:32)
0|RealWorl |     at Function.Module._load (internal/modules/cjs/loader.js:703:12
)
0|RealWorl |     at Function.Module.runMain (internal/modules/cjs/loader.js:999:
10)

GitHub有人提出了这个问题,里面的变通方案是:https://github.com/Unitech/pm2/issues/2808

也就是使用 node-cmd 运行命令(网上其他的方案也是把npm run start 写在一个脚本文件中,然后用pm2执行):

  1. 安装
npm install node-cmd
  1. 新建脚本 xxx.js
const cmd = require('node-cmd')
cmd.run('npm run start')
  1. pm2 启动脚本
pm2 start xxx.js

执行 pm2 配置文件启动Node服务

项目根目录创建 pm2的配置文件:pm2.config.json

{
  "apps": [
    {
      "name": "RealWorld", // 自定义pm2启动的项目名称
      "script": "npm", // pm2执行的命令
      "args": "start" // 命令参数
    }
  ]
}

执行pm2命令时指定配置文件:

pm2 start pm2.config.json
# 等同于
pm2 start npm -- start

注意:window 环境下同样不生效

PM2 常用命令

命令说明
pm2 list查看应用列表
pm2 start启动应用
pm2 stop停止应用
pm2 reload重载应用(在启动新实例之前,原有实例的进程会一个一个消灭)
pm2 restart重启应用(先消灭原有实例的所有进程,然后启动新实例)
pm2 delete删除应用(从pm2管理中移除掉)
pm2 -h查看所有命令

自动化部署方式

传统部署方式

  • 优点:部署流程比较清晰。
  • 缺点:每次更新都要重复发布流程(本地构建 -> 发布)

现代化的部署方式(CI/CD):

结合 CI/CD 服务工具实现自动部署。

  • CI:持续集成(Continuous integration)
  • CD:持续部署(Continuous deployment)

CI/CD 服务:

  • GitHub Actions
  • Gitee Jenkins
  • GitLab CI
  • Travis CI

在这里插入图片描述

使用GitHub Actions 实现自动化部署

准备工作

  • Linux 服务器 - 发布应用
  • GitHub 仓库 - 托管代码

1. 将项目代码提交到GitHub仓库

2. 在 GitHub 的 Settings 面板创建 token

点击GitHub右上角头像 - Settings - Developer settings - Personal access tokens

生成的个人访问令牌(Token)用于访问GitHub API

在这里插入图片描述

输入密码,创建token,添加对仓库完全访问和操作的权限:

在这里插入图片描述

在这里插入图片描述

生成的token只会出现这一次,如果没有记录,忘记了,只能重新创建一个新的。

3. 在项目根目录创建 GitHub Actions 工作流配置文件

创建目录./github/workflows,在里面创建.yml后缀的文件,文件名随意,将作为工作流的默认名称,GitHub会自动识别到这个文件并执行。

name: Publish And Deploy Demo
on:
  push:
    # 提交tag名以v开头的tag时执行部署任务
    tags:
      - 'v*'

jobs:
  build-and-deploy:
    # 运行环境
    runs-on: ubuntu-latest
    # 执行的步骤
    steps:
      # 下载源码
      - name: Checkout
        uses: actions/checkout@master

      # 打包构建
      - name: Build
        uses: actions/setup-node@master
      - run: npm install
      - run: npm run build
      # 生成压缩包(打包 .nuxt static nuxt.config.js package.json package-lock.json pm2.config.json)
      - run: tar -zcvf release.tgz .nuxt static nuxt.config.js package.json package-lock.json pm2.config.json

      # 发布 Release(创建Release分支)
      - name: Create Release
        id: create_release
        uses: actions/create-release@master
        env:
          GITHUB_TOKEN: ${{ secrets.TOKEN }}
        with:
          # 本次提交的tag的名称
          tag_name: ${{ github.ref }}
          # Release版本的名称
          release_name: Release ${{ github.ref }}
          # 是否是草稿
          draft: false
          # 是否是预发布
          prerelease: false

      # 上传构建结果(release.tgz)到 Release
      - name: Upload Release Asset
        id: upload-release-asset
        uses: actions/upload-release-asset@master
        env:
          GITHUB_TOKEN: ${{ secrets.TOKEN }}
        with:
          # 上传地址(创建的Release分支地址)
          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 }}
          # 远程服务器用户名
          username: ${{ secrets.USERNAME }}
          # 远程服务器密码
          password: ${{ secrets.PASSWORD }}
          # 远程服务器端口号
          port: ${{ secrets.PORT }}
          # 命令超时配置 默认10m
          command_timeout: 20m
          # 运行在远程服务器的命令
          # 1. 进入项目目录
          # 2. 下载发布包
          # 3. 解压缩发布包
          # 4. 安装生产环境依赖
          # 5. pm2运行配置文件
          script: |
            cd /root/realworld-nuxtjs
            wget [Github仓库地址]/releases/latest/download/release.tgz -O release.tgz
            tar zxvf release.tgz
            npm install --production
            pm2 reload pm2.config.json

工作流中使用到了 secrets 信息,即GitHub项目仓库 Settings 中配置的 Secrets。

在这里插入图片描述

需要配置的有(注意名称需要与文件中的保持一致):

  • TOKEN - 之前创建并记录的token
  • HOST - 服务器IP地址
  • USERNAME - 服务器用户名,Linux默认root
  • PASSWORD - 服务器 ssh 连接密码
  • PORT - ssh连接服务器的端口号,默认22

在这里插入图片描述

在这里插入图片描述

4. push代码触发自动部署任务

触发条件:push名称以v开头的 tag。

TortoiseGit方式:

  • 创建标签
  • 推送 - 勾选包括标签

Git 命令方式:

# 创建tag
git tag v0.1.0
# 查看tag
git tag
# 推送tag
push tag origin v0.1.0

然后在GitHub仓库的Actions面板可以查看构建过程。

在这里插入图片描述

构建成功后,使用服务器公网IP+端口号访问。

之后修改内容后,只需重新打 tag 推送到 GitHub 就会自动部署。

遇到的问题

请确认服务器已安装 git、nodejs、pm2 等工具。

本人服务器构建过程中 Deploy 失败,状态码 127。

文件已经解压缩,于是手动连接服务器,执行后面的步骤 npm install --production

最终失败报错:Maximum call stack size exceeded

于是切换npm源为淘宝镜像:npm set registry https://registry.npm.taobao.org/

重新安装,成功。

重新创建tag推送,自动部署又报错:

-bash: npm: command not found
-bash: pm2: command not found

可是手动连接服务器执行都OK(本人是nvm安装的nodejs)。

打印环境变量 echo $PATH 也添加了路径的。

于是在actions任务中执行命令打印 echo $PATH,果然没有 node 路径。

尝试在/root/.bashrc/etc/profile中都添加了 环境变量配置,都没有生效。

又在actions任务中查看文件目录,node、npm、pm2都有。

这个问题的原因是:

手动执行任务时,是在当前 shell 环境下进行的,程序可以找到环境变量。

而系统自动执行任务调度时,是不会加载任何环境变量的,因为它不是通过 shell 环境执行的。

解决办法:

  1. 临时办法:在actions任务中手动添加环境变量:

这个方式就是在每次任务执行时,npm命令执行前手动配置环境变量。

#...
script: |
  export PATH=/root/.nvm/versions/node/v12.17.0/bin:$PATH
  cd /root/realworld-nuxtjs
#...
  1. 长久办法:创建软链接
ln -s [node路径] /usr/local/bin
ln -s [npm路径] /usr/local/bin
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值