PM2 很多人以为只能管 Node.js,其实它本质上是一个进程管理器。只要是能在命令行启动的长期运行程序,PM2 都可以托管,比如 Node.js、Rust 编译出来的二进制、Go 服务、Python 脚本、Shell 脚本等。
例如一个 Rust 后端服务,可以这样启动:
pm2 start ./target/release/gateway \
--name bazar-api \
--cwd /var/www/bazar_api \
--update-env
这篇整理一下 PM2 的常用命令、参数含义和部署时经常会用到的操作。
安装
PM2 通常通过 npm 安装:
npm install -g pm2
查看版本:
pm2 -v
如果服务器上没有 Node.js 环境,需要先安装 Node.js。即使你的服务不是 Node 写的,PM2 自己仍然依赖 Node 运行。
启动服务
最基本的启动方式:
pm2 start app.js
指定进程名:
pm2 start app.js --name my-api
启动二进制文件:
pm2 start ./target/release/gateway --name bazar-api
启动时传递参数给应用:
pm2 start ./server --name my-server -- --port 8080 --host 0.0.0.0
注意 -- 后面的内容会传给你的应用,而不是传给 PM2。
例如:
pm2 start ./target/release/gateway \
--name bazar-api \
--cwd /var/www/bazar_api \
--update-env
这条命令的含义是:
pm2 start ./target/release/gateway:启动当前项目里的gateway二进制。--name bazar-api:PM2 中显示的进程名叫bazar-api,后续可以用这个名字重启、停止、看日志。--cwd /var/www/bazar_api:把工作目录切到/var/www/bazar_api后再启动程序。--update-env:使用当前 shell 中最新的环境变量更新 PM2 进程环境。
--cwd 对后端服务很重要。很多程序会读取相对路径文件,例如 .env、config.toml、data/app.db、static/、uploads/。如果工作目录不对,程序可能能启动,但会读错配置或找不到文件。
查看进程
查看所有 PM2 进程:
pm2 list
或者:
pm2 status
常见字段:
name:进程名。id:PM2 内部进程 ID。mode:fork 或 cluster。pid:系统进程 ID。status:online、stopped、errored 等。restart:重启次数。cpu/mem:CPU 和内存占用。
查看某个进程详情:
pm2 show bazar-api
或者:
pm2 describe bazar-api
这里可以看到启动命令、工作目录、日志路径、环境变量、重启次数等信息。排查“为什么服务启动后行为不对”时很有用。
日志
查看所有进程日志:
pm2 logs
查看指定进程日志:
pm2 logs bazar-api
只看最近 100 行:
pm2 logs bazar-api --lines 100
清空 PM2 日志:
pm2 flush
查看日志文件路径:
pm2 show bazar-api
PM2 默认把日志放在:
~/.pm2/logs/
常见会有两个文件:
bazar-api-out.log:标准输出。bazar-api-error.log:标准错误。
如果服务启动失败,第一步通常就是:
pm2 logs bazar-api --lines 200
重启、停止、删除
重启指定服务:
pm2 restart bazar-api
停止指定服务:
pm2 stop bazar-api
重新启动已经停止的服务:
pm2 start bazar-api
删除指定服务:
pm2 delete bazar-api
重启所有服务:
pm2 restart all
停止所有服务:
pm2 stop all
删除所有服务:
pm2 delete all
stop 和 delete 的区别:
stop:只是停止,进程还在 PM2 列表里。delete:从 PM2 列表中移除这个进程。
更新环境变量
PM2 启动进程后,会保存当时的环境变量。之后你修改了 .env 或 shell 里的环境变量,直接 pm2 restart 不一定会生效。
更新环境变量时用:
pm2 restart bazar-api --update-env
或者启动时:
pm2 start ./target/release/gateway \
--name bazar-api \
--cwd /var/www/bazar_api \
--update-env
如果你的服务依赖这些变量,建议重启时固定加上:
pm2 restart bazar-api --update-env
不过要注意:--update-env 更新的是 PM2 进程环境,不等于自动读取 .env 文件。是否读取 .env,取决于你的程序自己有没有加载 .env。例如 Rust 后端常见做法是用 dotenvy 或配置模块在启动时读取。
指定环境变量启动
可以在命令前直接写环境变量:
APP_ENV=production PORT=8080 pm2 start ./target/release/gateway --name bazar-api
也可以配合 --update-env:
APP_ENV=production PORT=8080 pm2 start ./target/release/gateway \
--name bazar-api \
--cwd /var/www/bazar_api \
--update-env
如果环境变量很多,建议用 ecosystem 配置文件,不要在命令行里堆太长。
开机自启
PM2 管理的服务,如果服务器重启后也要自动恢复,需要配置 startup。
生成开机自启命令:
pm2 startup
PM2 会输出一条带 sudo 的命令,复制执行。
然后保存当前进程列表:
pm2 save
以后服务器重启时,PM2 会恢复这次保存的进程列表。
常见流程:
pm2 start ./target/release/gateway --name bazar-api --cwd /var/www/bazar_api
pm2 save
pm2 startup
如果你新增、删除、改名了 PM2 进程,记得重新:
pm2 save
否则服务器重启后恢复的还是旧列表。
查看已保存的 dump:
pm2 resurrect
pm2 resurrect 会按保存的进程列表恢复服务。正常情况下 systemd 会自动调用它。
使用 ecosystem 配置文件
命令行适合简单服务,但生产环境更推荐写 ecosystem.config.js。
示例:
module.exports = {
apps: [
{
name: "bazar-api",
script: "./target/release/gateway",
cwd: "/var/www/bazar_api",
exec_mode: "fork",
instances: 1,
autorestart: true,
max_memory_restart: "500M",
env: {
APP_ENV: "production",
PORT: "8080",
},
},
],
};
启动:
pm2 start ecosystem.config.js
重启并更新环境:
pm2 restart ecosystem.config.js --update-env
只启动配置里的某一个应用:
pm2 start ecosystem.config.js --only bazar-api
配置文件的好处:
- 启动参数可版本管理。
- 不容易忘记
cwd、环境变量、内存限制。 - 多个服务可以统一管理。
- 部署脚本更短、更稳定。
Node.js 的 cluster 模式
PM2 对 Node.js 有 cluster 模式,可以启动多个实例利用多核 CPU:
pm2 start app.js -i max
指定 4 个实例:
pm2 start app.js -i 4
ecosystem 写法:
module.exports = {
apps: [
{
name: "node-api",
script: "app.js",
exec_mode: "cluster",
instances: "max",
},
],
};
注意:cluster 模式主要适合 Node.js HTTP 服务。Rust、Go 这类二进制服务通常用 fork 模式即可。如果想多实例部署 Rust/Go 服务,一般会在应用端、端口分配、Nginx upstream、systemd 或容器编排层面处理。
监听文件变化自动重启
开发环境可以使用 watch:
pm2 start app.js --watch
指定忽略目录:
pm2 start app.js --watch --ignore-watch="node_modules logs"
生产环境一般不建议随便开 --watch。如果日志、上传文件、缓存目录频繁变化,可能导致服务反复重启。
内存超限自动重启
限制内存,超过后自动重启:
pm2 start app.js --max-memory-restart 500M
ecosystem:
module.exports = {
apps: [
{
name: "api",
script: "app.js",
max_memory_restart: "500M",
},
],
};
这适合防止服务内存泄漏把机器拖垮,但它不是根治方案。如果服务频繁因为内存限制重启,还是要看日志和监控找原因。
监控
终端监控界面:
pm2 monit
查看进程资源占用:
pm2 list
查看详细信息:
pm2 show bazar-api
PM2 也有付费的 PM2 Plus / PM2 Enterprise,但一般小型项目只用本地命令就够了。
常见部署流程
以 Rust 服务为例,常见部署流程是:
cd /var/www/bazar_api
git pull
cargo build --release
pm2 restart bazar-api --update-env
如果是第一次部署:
cd /var/www/bazar_api
cargo build --release
pm2 start ./target/release/gateway \
--name bazar-api \
--cwd /var/www/bazar_api \
--update-env
pm2 save
如果使用 ecosystem:
cd /var/www/bazar_api
cargo build --release
pm2 start ecosystem.config.js
pm2 save
以后更新:
cd /var/www/bazar_api
git pull
cargo build --release
pm2 restart ecosystem.config.js --update-env
pm2 save
常见问题
服务启动后找不到配置文件
先看工作目录:
pm2 show bazar-api
重点看 exec cwd。如果不对,重新指定:
pm2 delete bazar-api
pm2 start ./target/release/gateway \
--name bazar-api \
--cwd /var/www/bazar_api \
--update-env
修改环境变量后不生效
使用:
pm2 restart bazar-api --update-env
如果还是不生效,确认程序是否真的读取了 .env,以及 .env 是否在正确的 cwd 下。
服务一直重启
查看日志:
pm2 logs bazar-api --lines 200
查看重启次数:
pm2 list
常见原因:
- 程序启动即崩溃。
- 端口被占用。
- 数据库连不上。
- 配置文件路径不对。
- 权限不足,无法读取文件或写入目录。
- 环境变量缺失。
服务器重启后服务没起来
确认是否保存了进程列表:
pm2 save
确认是否配置了开机自启:
pm2 startup
确认当前用户是否正确。PM2 的进程列表是按用户隔离的。你用 root 启动的 PM2,和用 www-data 或普通用户启动的 PM2,不是同一套列表。
端口被占用
查看日志通常能看到 address already in use。
可以用:
lsof -i :8080
找到占用端口的进程后再决定是否停止它。
常用命令速查
| 命令 | 作用 |
|---|---|
pm2 start app.js --name api | 启动并命名进程 |
pm2 start ./server --name api --cwd /path/app | 指定工作目录启动 |
pm2 list | 查看进程列表 |
pm2 status | 查看进程状态 |
pm2 show api | 查看进程详情 |
pm2 logs api | 查看指定进程日志 |
pm2 logs api --lines 100 | 查看最近 100 行日志 |
pm2 restart api | 重启进程 |
pm2 restart api --update-env | 重启并更新环境变量 |
pm2 stop api | 停止进程 |
pm2 delete api | 删除进程 |
pm2 restart all | 重启全部进程 |
pm2 flush | 清空日志 |
pm2 monit | 打开监控界面 |
pm2 startup | 生成开机自启配置命令 |
pm2 save | 保存当前进程列表 |
pm2 resurrect | 恢复保存的进程列表 |
总结
PM2 最常用的能力其实就几件事:启动、命名、指定工作目录、看日志、重启、保存开机自启。
生产环境里,建议至少做到这几点:
- 每个服务都用
--name命名。 - 后端服务尽量显式指定
--cwd。 - 修改环境变量后使用
--update-env。 - 第一次部署成功后执行
pm2 save。 - 复杂项目使用
ecosystem.config.js管理启动参数。 - 出问题先看
pm2 logs <name> --lines 200和pm2 show <name>。
对非 Node.js 服务来说,PM2 不是唯一选择,systemd、Docker、supervisord 都能做类似的事。但如果你想要一个简单、命令友好、日志查看方便的进程管理工具,PM2 依然很实用。