云效平台:Nestjs+ts+pm2项目部署到docker

1,674 阅读3分钟

背景介绍

首先,因为团队创立不久,所以目前项目管理、开发都是依托于云效平台,下面简称平台。所以我们的自动化部署便配置在 云效->流水线 上。

流程配置

部署流程配置如下:

tu1.png

简单来讲,三个步骤:

  1. 拉取代码:平台从代码仓库拉取选中的分支代码;
  2. 阿里云镜像构建:读取根目录的Dockerfile,根据file内容在平台构建docker镜像;
  3. Docker部署:目标服务器拉取镜像,执行一段脚本部署到本地。目标服务器需安装python(用于授权平台做免密登录)与docker(用于部署)

源配置

这个没啥好讲的,选择代码仓库和默认分支就行。不做赘述。

构建镜像配置

平台配置

image.png

关于${DATETIME}变量,可以在环境变量查看。

需要注意的是构建参数配置,最常用的是我们自动构建时需要区分环境。在平台配置,并在Dockerfile中使用。

Dockerfile

FROM node:14.15.0

# 获取构建参数env
ARG env

MAINTAINER JHH
# 创建工作目录
RUN mkdir -p /var/publish/nest

# 指定工作目录
WORKDIR /var/publish/nest

# 复制当前代码到/app工作目录
COPY . /var/publish/nest

# 配置系统变量,指定端口
ENV HOST 0.0.0.0
ENV PORT 8000
ENV ENV_NAME pm2:${env}

EXPOSE 8000

# npm 源,选用国内镜像源以提高下载速度
# RUN npm config set registry https://registry.npm.taobao.org/

RUN echo $ENV_NAME

# npm 安装依赖
RUN npm i pnpm -g

RUN pnpm i --cache .npm --quiet
# 注意,因为ts无法直接被识别,所以需要执行build命令
RUN npm run build

# 启动服务
CMD npm run ${ENV_NAME}

RUN和CMD的区别属于Docker语法问题,这里就不做赘述啦。可以看到以env=prod为例,最终执行的是npm run pm2:prod指令。 结合script脚本命令就比较清楚了:

"pm2:test": "TZ=Asia/Shanghai pm2-runtime tz-nest/ecosystem.config.js --env test",
"pm2:prod": "TZ=Asia/Shanghai pm2-runtime tz-nest/ecosystem.config.js --env prod",

运行脚本详解

TZ=Asia/Shanghai pm2-runtime tz-nest/ecosystem.config.js --env prod

  • TZ=Asia/Shanghai配置时区,解决构建完之后日志时间不对的问题。
  • pm2-runtime tz-nest/ecosystem.config.js读取配置文件,并前台运行项目。或者后台运行的话,可以用 pm2 start tz-nest/ecosystem.config.js命令。
  • --env prod设置环境变量。

ecosystem.config.ts

export default {
  apps: [
    {
      name: 'tz-nest',
      // tz-nest是我build之后的文件夹,一般默认是dist。
      script: './tz-nest/src/main.js',
      instances: 2,
      env_test: {
        NODE_ENV: 'development'
      },
      // script中设置的--env prod,会自动读取env_prod属性。
      env_prod: {
        NODE_ENV: 'production'
      },
      exec_mode: 'cluster',
      combine_logs: true
    }
  ]
}

运行之后会起两个实例。

为什么用 pm2

一开始我并没有用pm2,会发现隔两天容器就会挂掉。虽然可以在启动docker容器的时候加上--restart=always,但是相关日志就没了。排查BUG的时候有些抓马~~

在上了pm2保驾护航之后,就再没挂掉过。

部署配置

添加主机

配置需要部署到主机,需要先添加主机组。关于添加主机,也不做赘述,按提示操作即可。不过需要主机安装python2.7。

如果不是2.7版本的可以重新安装2.7版本python,或者 改为访问本地shell,取消python版本校验

部署脚本

export TAG_NAME=$(echo $CI_COMMIT_REF_NAME)
export BUILD_NUMBER=$(echo $BUILD_NUMBER)

echo "IMAGE $image"

# IID为镜像ID
IID=$(docker images | grep "$image_base" | awk '{print $3}')
echo  "IID $IID"
# 判断是否存在这个仓库的镜像并删除
if [ -n "$IID" ]
then
    echo "delete $image_base image"
    docker rmi -f $IID
else
    echo "no exist $image_base image, build docker"
fi
# 拉取镜像到本机
docker pull $image

# tz-nest是我为容器起的别名,拿到容器ID
CID=$(docker ps | grep "tz-nest" | awk '{print $1}')

echo "CID $CID"
# 如果容器ID存在,移除容器
if [ -n "$CID" ]
then
    docker stop $CID
    docker rm $CID
else
    echo "no exist $IMAGE container"
fi
    # 为新镜像创建一个容器,别名为tz-nest
    docker run -d -p 8000:8000 --name tz-nest $image

上面用到了两个变量,$image$image_base,也是在平台配置的。

image.png

这里的$image代表上游产生的镜像TAG,$image_base代表镜像仓库地址。

结尾

配置完成后,一键运行流水线,程序就能自动部署到服务器上啦。

最后感谢大家的阅读~有不正确的地方还望指正。[捂脸]