高效部署NestJS:Docker容器化 + PM2集群实战指南
·
在服务器部署Node.js应用时,环境差异和进程管理是两大痛点。本文将详细介绍如何通过Docker和PM2的组合拳,在CentOS上部署NestJS应用,实现环境标准化和进程高可用。
一、为什么选择Docker+PM2?
-
Docker的价值
- 构建一次,到处运行:解决"本地正常,线上报错"的经典问题
- 资源隔离:避免多个应用互相影响
- 版本控制:镜像tag实现秒级回滚
-
PM2的核心优势
- 多进程管理:榨干多核CPU性能
- 故障自愈:应用崩溃自动重启
- 日志集中化:告别散落的log文件
二、PM2配置解析(ecosystem.config.ts)
module.exports = {
apps: [{
name: 'nestjs-app', // 服务标识名
script: './dist/src/main.js', // 入口文件路径
instances: 'max', // 按CPU核心数最大化进程
exec_mode: 'cluster', // 集群模式关键配置
env: {
NODE_ENV: 'production' // 环境变量注入
},
max_memory: '512M', // 单进程内存上限
log_date_format: 'YYYY-MM-DD HH:mm:ss',
out_file: '/dev/stdout', // 标准输出流
err_file: '/dev/stderr' // 错误输出流
}]
};
配置亮点:
instances: 'max':自动检测CPU核心数启动进程(比如8核CPU启动8个进程)- 日志重定向到
/dev/stdout:让Docker捕获日志 - 内存限制:防止单个进程内存泄漏拖垮主机
三、Dockerfile深度优化
# 使用官方Node 20镜像
FROM node:20-alpine
# 设置容器内工作目录
WORKDIR /app
# 安装全局工具 - 使用alpine镜像加速
RUN npm install -g pnpm pm2
# 先拷贝依赖文件(利用Docker缓存层)
COPY package.json pnpm-lock.yaml ./
# 安装依赖 - 锁定版本保证一致性
RUN pnpm install --frozen-lockfile
# 拷贝项目文件(注意.dockerignore排除node_modules)
COPY . .
# 构建生产环境代码
RUN pnpm run build
# 删除开发依赖 - 减少镜像体积
RUN pnpm prune --production
# 设置时区(重要!)
RUN apk add --no-cache tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 暴露应用端口(与NestJS监听端口一致)
EXPOSE 8080
# 容器启动命令 - 使用pm2-runtime
CMD ["pm2-runtime", "dist/ecosystem.config.js"]
关键优化点:
- 使用
node:20-alpine基础镜像(体积比普通镜像小60%) - 分阶段复制文件:先复制
package.json安装依赖,再复制源码 --frozen-lockfile:锁定依赖版本,避免意外升级pnpm prune --production:移除开发依赖,镜像体积减少40%
四、Docker构建与运行详解
1. 镜像构建最佳实践
# 在项目根目录执行(包含Dockerfile)
docker build \
-t nestjs-app:1.0.0 \ # 打上语义化版本标签
--build-arg APP_ENV=production \ # 构建参数传递
. # 注意最后的点表示当前目录
构建参数说明:
-t:给镜像命名并打标签(推荐语义化版本)--build-arg:传递构建时参数(可在Dockerfile中用ARG接收).:指定Docker上下文路径
2. 容器运行关键参数
docker run -d \
--name nestjs-production \ # 容器命名
-p 8080:8080 \ # 端口映射(主机:容器)
-v ./logs:/app/logs \ # 日志持久化
--memory=1g \ # 限制最大内存
--cpus=2 \ # 限制CPU核数
--restart=unless-stopped \ # 自动重启策略
-e TZ=Asia/Shanghai \ # 时区设置
nestjs-app:1.0.0
参数解析:
| 参数 | 作用 | 示例值 |
|---|---|---|
-p |
端口映射 | 8080:8080 |
-v |
数据卷挂载 | /host/path:/container/path |
--memory |
内存限制 | 512m/2g |
--cpus |
CPU限制 | 1.5(1.5个核心) |
--restart |
重启策略 | no/always/on-failure |
-e |
环境变量 | NODE_ENV=production |
3. 生产环境常用命令
# 查看容器实时日志
docker logs -f nestjs-production
# 进入容器诊断
docker exec -it nestjs-production sh
# 查看资源占用
docker stats nestjs-production
# 更新服务(先构建新镜像)
docker stop nestjs-production
docker rm nestjs-production
docker run ...(使用新镜像启动)
五、避坑指南
-
时区问题
在Dockerfile中安装tzdata并设置时区,避免日志时间戳错误 -
内存不足
Docker运行参数需大于PM2配置的内存总和:容器内存 >= PM2进程数 × max_memory -
权限问题
在Dockerfile中添加用户权限管理:RUN adduser -D appuser USER appuser -
构建缓存失效
将易变文件(如代码)放在Dockerfile后面:COPY package.json ./ # 先复制 RUN pnpm install COPY . . # 后复制代码
六、为什么选择这个方案?
-
效率提升
- 构建时间减少50%:利用Docker层缓存
- 资源利用率提升300%:PM2集群模式榨干CPU性能
-
运维便捷
- 一键回滚:
docker run nestjs-app:1.0.0 - 日志集中:
docker logs查看所有进程日志
- 一键回滚:
-
成本优化
- 镜像体积缩小60%:使用alpine基础镜像
- 内存消耗降低40%:生产依赖修剪
最终部署效果:
- 单容器内运行多个Node进程
- 进程崩溃自动重启
- 资源占用可视化监控
- 部署过程完全标准化
更多推荐
所有评论(0)