传统部署方式
传统部署流程
-
配置 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 相关的应用,运行在后台,保持运行状态。
- Github 仓库地址:https://github.com/Unitech/pm2
- 官方文档:https://pm2.io/
- 全局安装:
npm i -g pm2
- 启动:
pm2 start 脚本路径
- 停止:
pm2 stop <app_name|namespace|id|'all'|json_conf>
当前应用的启动脚本是通过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执行):
- 安装
npm install node-cmd
- 新建脚本 xxx.js
const cmd = require('node-cmd')
cmd.run('npm run start')
- 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 id|name|file | 启动应用 |
pm2 stop id|name|all | 停止应用 |
pm2 reload id|name|all | 重载应用(在启动新实例之前,原有实例的进程会一个一个消灭) |
pm2 restart id|name|all | 重启应用(先消灭原有实例的所有进程,然后启动新实例) |
pm2 delete id|name|all | 删除应用(从pm2管理中移除掉) |
pm2 kill | 杀死所有进程 |
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:
# 运行环境
# 启动一个 Docker 的容器,容器中执行的镜像是 ubuntu-latest,所有任务执行完成后,会销毁这个 Docker
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 }}
# 远程服务器密码
# 也可以使用密钥,具体查看官方文档 https://github.com/appleboy/ssh-action
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 环境执行的。
解决办法:
- 临时办法:在actions任务中手动添加环境变量:
这个方式就是在每次任务执行时,npm命令执行前手动配置环境变量。
#...
script: |
export PATH=/root/.nvm/versions/node/v12.17.0/bin:$PATH
cd /root/realworld-nuxtjs
#...
- 长久办法:创建软链接
ln -s [node路径] /usr/local/bin
ln -s [npm路径] /usr/local/bin