Skip to content

仲灏小栈

仲灏约 1 分钟

前言

按照目前的进度,相信很多同学已经完成基础篇的内容,也有部分同学完成了用户或者物料系统的开发,所以应广大同学的要求,将应用部署这章提前写出来,方便大家完成项目开发流程中关键的最后一步。

与开发环境不同,在生产环境中服务端的项目都需要后台启动,如果是前端启动的话,当你关闭 ssh 连接或者控制台的时候,程序也就自动退出了,这显然不是我们希望的结果。

本章将介绍 NestJS 两种方式的发布类型: PM2Docker Compose 部署。

PM2

PM2 是一款使用于生产环境的 NodeJS 的进程管理工具,操作非常简便,内置了进程管理、监控、日志以及负载均衡的能力。

首先需要安装 PM2 的依赖,一般会安装在全局依赖:

shell
$ yarn global add pm2

普通的前端项目启动的话,直接使用以下命令就行了:

shell
pm2 start app.js

但毕竟是这一个实战的项目而且也有不同的环境变量存在,直接这么启动并不合适,可以借助 Ecosystem File 来完成我们的需求。

  1. 项目根目录新建 ecosystem.config.js
js
module.exports = {
  apps: [
    {
      name: "gateway",
      script: "dist/src/main.js",
      env_production: {
        RUNNING_ENV: "prod"
      },
      env_development: {
        RUNNING_ENV: "dev"
      }
    }
  ]
}
  1. 添加 package.json 中的 scripts 构建命令:
diff
+ "build": "nest build",
+ "build:webpack": "nest build --webpack",

image.png

对比一下两种构建命令的不同点:

  • nest build:将 NestJS 项目的源码从 TS 编译成 JS 之后再使用 node main.js 来运行项目,这样有个好处是还能看到大概的工程路径,也可以使用 TypeOrm 动态注册实体类的功能。
  • nest build --webpack 会将 NestJS 项目打包成一个独立的 main.js,从文件类型的角度来说,做了一次混淆跟合并,原理跟之前提到过的热更新启动是一样的,按照这种模式的话来使用的话,就不能使用动态注册实体类的功能,只能手动引入实体类

两种构建产物的方式都可以完成要求,按照自己的喜好选择就行,但无论是 webpack 打包成单文件的模式还是使用 TSC 模式生成 JS 项目代码,都需要在发布工程里面添加 node_modules,否则是没办法正常启动。

因为这两种模式并没有将依赖直接打包进产物内,虽然可以曲线修改 webpack.config 可以使得在 webpack 模式下,能将所有的依赖都打入单文件,但是由于环境依赖的问题,这种模式的产物大概率只能在相同的环境运行依赖,例如 windows 下打包的产物是无法部署在 linux 环境下。

  1. package.jsonscripts 中添加启动脚本:
diff
+ "start:prod": "nest build && pm2 start ecosystem.config.js --env production"

添加完毕之后,执行 yarn start:prod 出现如下界面既完成了项目生产环境的部署,如果不能正常访问接口的话,可以使用 pm2 log gateway 查看启动日志,如果按照我给的方案走一般不会出现问题,有问题的话,大概率是配置文件找不到,调整配置文件即可。

image.png

切记,如果使用 webpack 模式部署生产环境,一定要手动注册实体类!!!!不然会报错的!!!!

更多的 PM2API 使用与黑科技,用兴趣的同学可以自己进行摸索,这里就不过多介绍了。

Docker Compose

Docker Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排日常开发工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。

比如我们的网关服务体系就由 3 个不同的服务组成,其中还不包括 RedisMysql 这种中间件的服务,所以每个服务都使用直接 Docker 来部署的话,效率低下而且维护麻烦,而借助 Docker Compose 可以将我们的服务统一一次性部署完成。

第一步:要把项目工程打包成 image,根路径创建文件 Dockerfile:

FROM node:16-alpine3.15

RUN mkdir -p /home/app/

WORKDIR /home/app/

COPY package*.json ./

RUN npm install

COPY . .

EXPOSE 3000

ENTRYPOINT ["npm", "run"]

CMD ["start"]

第二步:根目录运行以下脚本来就行构建:

shell
$ docker build -f ./Dockerfile -t gateway:0.0.1 .

image.png

第三步:运行以下命令既可以启动容器运行:

shell
docker run -d -e RUNNING_ENV=prod -p 3000:3000 gateway:0.0.1

image.png

使用 docker logs [容器id] 既可以看到我们的项目已经正常启动了:

image.png

以上是直接使用 Docker 来部署项目,换成 Docker Compose 的话,则需要额外新建文件 docker-compose.gateway-service-dev.yml

version: "3"
services:
  gateway-service-dev:
    container_name: gateway-service-dev
    build:
      context: ./
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      RUNNING_ENV: 'dev'
    networks:
      - servicebus
networks:
  servicebus:
    name: servicebus

启动命令为:

shell
docker-compose -f docker-compose.gateway-service-dev.yml up -d  --build

其中 build 参数代表构建过程,所以我们在使用 docker-compose 构建的时候可以省去第二步构建镜像的步骤,配合 docker file 中的前置安装依赖步骤,可以在每次更新代码后需要重新构建时,项目依赖不更新的情况下,使用缓存构建,大幅度减少构建时间。

写在最后

部署篇的章节为了方便大家快速使用,目前较为简单,等待所有的项目都完成之后,会在 docker compose 部分扩充内容,给大家展示容器编排的优势。

另外如果有机会或者想尝试 K8S 部署的话,可以参考 Devops 的小册,里面有 Rancher 章节是关于集群部署的

如果你有什么疑问,欢迎在评论区提出或者加群沟通。 👏

上次更新: