PM2 单机部署
PM2 是 Node 进程管理器,单机部署的事实标准。轻量、零配置、自带负载均衡。但仅适合单机——多机用 K8s。
一、避坑指南
PM2 是单机工具,不要上 K8s 还在用:
- PM2 管进程不管容器
- K8s 环境下用 cluster mode 是反模式(让 K8s 做调度)
必须用 ecosystem 配置文件,不要纯 CLI:
# ❌ 命令行:散乱、不可版本化
pm2 start app.js -i 4 --name web
# ✅ 配置文件:commit 到 git
pm2 start ecosystem.config.js --env productioncluster模式必须开(多核利用):// ecosystem.config.js
module.exports = {
apps: [{
name: "web",
script: "./dist/server.js",
instances: "max", // ← 关键:用满所有 CPU 核
exec_mode: "cluster",
}],
};零停机重载用
reload不是restart:# ❌ restart 会停掉再起,中间有秒级 downtime
pm2 restart web
# ✅ reload 逐个重启(graceful reload)
pm2 reload web日志要分割,否则磁盘会爆:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 30开机自启:
pm2 startup # 生成开机启动命令
pm2 save # 保存当前进程列表
二、什么时候用 PM2?
| 场景 | 用 PM2? | 推荐方案 |
|---|---|---|
| 内部小服务 / 工具 | ✅ 首推 | PM2 |
| 中小团队 SSR 服务(单台服务器) | ✅ 首推 | PM2 + Nginx |
| 内部 Node 后端(1~3 台机器) | ✅ 推荐 | PM2 + Nginx |
| 多机 / 弹性扩缩容 | ❌ 改用 K8s | K8s / Docker Swarm |
| 纯静态 | ❌ | CDN |
| K8s 集群内部 | ❌ | 用 K8s 自带机制 |
决策原则:单机 + Node 服务 = PM2。多机或容器化用 K8s。
三、PM2 vs Docker vs K8s
| 维度 | PM2 | Docker | K8s |
|---|---|---|---|
| 部署粒度 | 进程 | 容器 | Pod |
| 资源隔离 | ❌(共享 OS) | ✅ 强 | ✅ 强 |
| 负载均衡 | ✅ cluster 内置 | 需外部(Nginx) | ✅ Service / Ingress |
| 自动恢复 | ✅ 内置 | restart policy | ✅ 内置 |
| 多机 | ❌ 需手动 | ✅ docker swarm | ✅ 原生 |
| 启动速度 | < 1s | 几秒 | 几十秒 |
| 学习成本 | 低 | 中 | 高 |
| 日志 | 内置 | 需配置 | 需配置(EFK/Loki) |
| 监控 | pm2 monit / pm2 plus | 外部 | 外部 |
典型组合:PM2(Node 进程管理) + Nginx(反向代理/SSL)。Docker 也常包一层:Docker 打包 + PM2 进程管理 + Nginx 反代。
四、快速上手
# 全局安装
npm i -g pm2
# 启动应用
pm2 start app.js # 普通启动
pm2 start npm --name "web" -- run start # 启动 npm script
# 查看
pm2 list # 进程列表
pm2 monit # 实时监控(CPU/内存)
pm2 logs # 实时日志
pm2 logs web --lines 100 # 最近 100 行
# 控制
pm2 stop web # 停止
pm2 restart web # 重启(有 downtime)
pm2 reload web # 零停机重载
pm2 delete web # 删除
pm2 delete all # 全部删除
# 信息
pm2 info web # 详细信息
pm2 show web # 同 info
五、ecosystem.config.js 完整配置
// ecosystem.config.js
module.exports = {
apps: [
{
name: "web",
script: "./dist/server.js",
cwd: "/var/www/app",
// 集群模式:用满所有 CPU 核
instances: "max",
exec_mode: "cluster",
// 环境变量
env: {
NODE_ENV: "development",
PORT: 3000,
},
env_production: {
NODE_ENV: "production",
PORT: 3000,
DATABASE_URL: "postgresql://...",
},
// 资源限制
max_memory_restart: "500M", // 内存超 500M 自动重启
// 日志
log_file: "/var/log/pm2/web.log",
error_file: "/var/log/pm2/web-err.log",
out_file: "/var/log/pm2/web-out.log",
merge_logs: true,
log_date_format: "YYYY-MM-DD HH:mm:ss Z",
// 监听文件变化(开发用)
watch: false,
ignore_watch: ["node_modules", ".git", "logs"],
// 优雅关闭
kill_timeout: 5000, // 5s 内 kill 不掉强制 kill
wait_ready: false,
listen_timeout: 8000,
// 自动重启
max_restarts: 10,
min_uptime: "10s", // 运行 10s 内挂掉不计入重启
restart_delay: 1000, // 重启延迟 1s
},
],
};
# 启动(指定环境)
pm2 start ecosystem.config.js --env production
# 重载(用新环境变量)
pm2 reload ecosystem.config.js --env production
六、Cluster 模式(负载均衡)
PM2 cluster 模式 = 内置 Node.js cluster 模块,master 进程把请求分发给 worker。
// ecosystem.config.js
{
instances: 4, // 4 个 worker(或 "max")
exec_mode: "cluster",
}
pm2 start ecosystem.config.js --env production
pm2 list
# ┌────┬──────┬─────────┬──────┬────────┬──────────┐
# │ id │ name │ mode │ ↺ │ status │ cpu │
# ├────┼──────┼─────────┼──────┼────────┼──────────┤
# │ 0 │ web │ cluster │ 0 │ online │ 0% │
# │ 1 │ web │ cluster │ 0 │ online │ 0% │
# │ 2 │ web │ cluster │ 0 │ online │ 0% │
# │ 3 │ web │ cluster │ 0 │ online │ 0% │
# └────┴──────┴─────────┴──────┴────────┴──────────┘
面试题:cluster 模式怎么做到「零停机」? 答:reload 时 master 逐个重启 worker(先起新的 → 老的才会停),保证任何时刻都有 worker 在线。
七、Nginx 反向代理
PM2 监听 127.0.0.1:3000,Nginx 监听 :80/:443:
# /etc/nginx/sites-available/myapp
upstream myapp {
server 127.0.0.1:3000;
keepalive 64;
}
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
# 反代
location / {
proxy_pass http://myapp;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
八、PM2 部署工作流
# 1. 本地构建
pnpm build
# 2. 同步到服务器
rsync -avz --exclude=node_modules ./dist user@server:/var/www/app/
# 3. 远程 reload
ssh user@server "cd /var/www/app && pm2 reload ecosystem.config.js --env production"
或用 PM2 的 deploy 功能(适合简单项目):
// ecosystem.config.js
module.exports = {
apps: [{ name: "web", script: "./dist/server.js" }],
deploy: {
production: {
user: "deploy",
host: ["1.2.3.4"],
ref: "origin/main",
repo: "git@github.com:myorg/myapp.git",
path: "/var/www/app",
"pre-deploy-local": "",
"post-deploy": "pnpm install --frozen-lockfile && pnpm build && pm2 reload ecosystem.config.js --env production",
"env": { NODE_ENV: "production" },
},
},
};
# 一键部署
pm2 deploy production setup # 初始化
pm2 deploy production # 部署
pm2 deploy production revert 1 # 回滚到上一版
建议:复杂项目用 GitHub Actions / GitLab CI,PM2 deploy 适合内部小项目。
九、监控与日志
# 实时监控
pm2 monit
# 内存/重启统计
pm2 list
# 看 ↺ 列(重启次数)、memory 列
# 日志
pm2 logs web # 实时
pm2 logs web --lines 200 # 最近 200 行
pm2 flush # 清空日志
# 性能分析(CPU profile)
pm2 profile web # 录制 30s CPU profile
生产监控推荐:
pm2 plus(官方 SaaS,付费)- Keymetrics / PM2 Plus
- 接入 Prometheus + Grafana
十、面试高频
Q1:PM2 cluster 模式和 fork 模式区别?
A:
- fork:单进程(不利用多核)
- cluster:master + N worker,利用多核 + 内置负载均衡
- 生产环境必须 cluster
Q2:pm2 restart 和 pm2 reload 区别?
A:
restart:先停再起,有秒级 downtimereload:逐个重启(graceful reload),零停机
生产环境永远用
reload。
Q3:怎么保证 PM2 应用崩溃后自动恢复?
A:PM2 内置:
max_restarts:最大重启次数min_uptime:运行 N 秒内挂掉才计入重启max_memory_restart:内存超限自动重启- 进程崩溃时自动重启
但业务死锁(如 DB 连接池耗尽但没崩)PM2 不会发现,需配合健康检查 + 监控告警。
Q4:PM2 适合多机部署吗?
A:不适合。PM2 是单机进程管理器。多机用 K8s 或自己写 deploy 脚本(rsync + ssh)。
Q5:为什么不用 nohup / & 启动 Node?
A:nohup / &:
- ❌ 进程崩溃不自动恢复
- ❌ 不支持 cluster
- ❌ 不支持日志管理
- ❌ 不支持监控
- ❌ 不支持零停机重载
PM2 把这些都包了。生产环境必须用进程管理器。