使用 PM2 部署 Node.js 应用
原文来自 aaronnotes 博客
PM2 是一个用于管理和保持 Node.js 应用状态的进程管理器。它可以用于部署和监控你的 Node.js 应用程序。本文将介绍如何使用 PM2 部署 Node.js 应用。
为什么要使用 PM2
使用 PM2 部署 Node.js 应用程序有几个好处:
-
进程管理。PM2 可以启动、停止、重启和守护你的 Node.js 应用程序,它将应用程序作为进程守护在后台运行。
-
持久化。PM2 可以在服务器重启后自动重启你的 Node.js 应用,这意味着你的应用将始终处于运行状态
-
负载均衡。PM2 可以轻松制作一个本地的负载均衡器来平衡你的 Node.js 应用的多个实例之间的传入请求。
-
监控。PM2 提供一个简单的仪表板来监控你所有的 Node.js 应用程序(CPU、内存、进程数等)。
-
日志管理。PM2 聚合了所有应用程序的日志,可以轻松管理和查询日志。
使用 PM2 部署 Node.js 应用
安装 PM2:
npm install pm2@latest -g
进入你的应用程序目录:
cd your-app/
启动应用程序:
pm2 start npm --name "your-app-name" -- run start
查看应用程序状态:
pm2 list
# 或 pm2 ls
# 或 pm2 status
你将看到你的应用程序名称以及相关信息(进程 ID、内存使用情况、重启次数等):
┌────┬────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │
├────┼────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0 │ app1 │ default │ 2.16.3 │ cluster │ 18259 │ 37s │ 0 │ online │ 0% │ 93.9mb │ root │ disabled │
│ 1 │ app2 │ default │ 2.16.3 │ cluster │ 18289 │ 11s │ 0 │ online │ 0% │ 114.5mb │ root │ disabled │
└────┴────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
重启应用程序:
pm2 restart your-app-name
停止应用程序:
pm2 stop your-app-name
PM2 也有一个简单的仪表板可以监控你的应用程序:
pm2 monit
最后,你可以通过运行以下命令,在服务器重启后使 PM2 自动启动:
pm2 startup
pm2 startup
是 PM2 的一个命令,它的主要作用是创建一个系统服务,以便在系统重启时自动启动 PM2 进程管理器和已经被管理的应用程序。
具体来说,pm2 startup
执行以下操作:
-
检测当前系统使用哪种初始化系统(例如,
systemd
、upstart
、SysV
等),并生成相应的启动脚本。 -
将这个启动脚本复制到系统服务目录中(例如,
/etc/systemd/system
目录),并设置服务启动时的用户、环境变量以及其他相关信息。 -
最后,它会生成一条命令,要求用户以管理员权限运行该命令,并将其复制到终端中执行。这个命令将启用刚刚创建的系统服务,并在系统重启时自动启动 PM2 进程管理器和已经被管理的应用程序。这样,用户就不必手动启动这些进程,从而提高了系统的可靠性和稳定性。
如果停用自动启动,运行命令:pm2 unstartup
。
以下是执行完命令 pm2 startup
的输出信息:
[PM2] Init System found: systemd
Platform systemd
Template
[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target
[Service]
Type=forking
User=root
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/root/.nvm/versions/node/v18.15.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/root/.pm2
PIDFile=/root/.pm2/pm2.pid
Restart=on-failure
ExecStart=/root/.nvm/versions/node/v18.15.0/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/root/.nvm/versions/node/v18.15.0/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/root/.nvm/versions/node/v18.15.0/lib/node_modules/pm2/bin/pm2 kill
[Install]
WantedBy=multi-user.target
Target path
/etc/systemd/system/pm2-root.service
Command list
[ 'systemctl enable pm2-root' ]
[PM2] Writing init configuration in /etc/systemd/system/pm2-root.service
[PM2] Making script booting at startup...
[PM2] [-] Executing: systemctl enable pm2-root...
Created symlink /etc/systemd/system/multi-user.target.wants/pm2-root.service → /etc/systemd/system/pm2-root.service.
[PM2] [v] Command successfully executed.
+---------------------------------------+
[PM2] Freeze a process list on reboot via:
$ pm2 save
[PM2] Remove init script via:
$ pm2 unstartup systemd
systemd
是一个 Linux 系统初始化系统和服务管理器,是目前主流 Linux 发行版(如 Ubuntu、Debian、CentOS、Red Hat 等)的默认初始化系统。它负责启动系统服务、管理进程、处理日志、控制系统休眠和唤醒等任务。
systemd
的主要目标是提高系统启动速度和效率,统一系统管理,简化配置文件格式,提高可靠性和可维护性。 它采用一种事件驱动的方式管理系统,所有的系统服务都以单独的进程运行,并由systemd
统一管理。
使用 ecosystem.config.js
管理应用程序
PM2 可以使用 ecosystem.config.js
文件来管理多个应用程序,这比手动启动每个应用程序更加结构化和可维护。ecosystem.config.js
是一个模块,它导出用于定义应用程序环境的配置。
下面这个简单示例用来启动 Nuxt
应用程序的两个进程:app1
和 app2
,分别使用端口 3000
和 3001
。同时在 Nginx
中配置了 upstream server
指向这两个端口做负载均衡,以方便应用升级的时候可以不影响后台服务。
module.exports = {
apps: [
{
name: "app1",
exec_mode: "cluster",
port: 3000,
instances: "4", // Or a number of instances
script: "./node_modules/nuxt/bin/nuxt.js",
args: "start",
},
{
name: "app2",
exec_mode: "cluster",
port: 3001,
instances: "4", // Or a number of instances
script: "./node_modules/nuxt/bin/nuxt.js",
args: "start",
},
],
};
要启动此配置,运行:
pm2 start ecosystem.config.js
或者可以单独启动某一个应用进程:
pm2 start app1
如果我们需要升级更新该 Nuxt 应用,我们只需将代码更新到服务器中,依次运行下面的命令,即可做到在升级的时候后台服务不需间断。
npm run build
pm2 stop app1
pm2 start app1
pm2 stop app2
pm2 start app2
PM2 的进程执行模式
在上面的示例中,我们看到一个配置 exec_mode: 'cluster'
,这表示 PM2 的进程执行模式选择 cluster
模式。
PM2 有两种进程执行模式:
fork
模式是默认的执行模式,它使用单个主进程来管理所有的子进程。在这种模式下,每个应用程序都会被复制多次,以创建多个独立的子进程。每个子进程都可以独立地处理请求,但它们之间不会共享状态或内存。
cluster
模式是一种高级模式,它使用多个主进程来管理所有的子进程。在这种模式下,每个应用程序只会被复制一次,并由多个子进程共享。这些子进程可以共享状态和内存,并且可以使用 IPC 通信来协调工作。
这两种模式的主要区别在于 PM2 使用 Node.js 的 child_process.fork api
或 cluster api
:
在 fork 模式下,PM2 为你的应用程序的每个实例创建一个单独的 Node.js
进程。每个进程独立运行,不与其他进程共享任何资源。这意味着,如果一个进程崩溃,它不会影响其他进程。在这个模式下,允许改变 exec_interpreter
(用来启动子进程的 “命令”),所以你可以用 PM2 运行一个 PHP 或 Python 服务器 。默认情况下,PM2 会使用 node,所以 pm2 start server.js
类似于:
require('child_process').spwn('node', ['server.js'])
这种模式非常有用,因为它可以实现很多可能性。例如,你可以在预先确定的端口上启动多个服务器,然后由 HAProxy 或 Nginx 进行负载均衡。
cluster 只在 node 作为执行解释器的情况下工作,cluster
模式使用内置的 Node.js cluster
模块来创建一个进程集群,这些进程都共享同一个服务器端口。这使 Node.js
能够利用多个 CPU 核心,并使需要处理大量并发请求的应用程序具有更好的性能和可扩展性。在 cluster
模式下,PM2 创建一个主进程和几个工作进程。主进程管理工作进程,并将传入的请求分配给它们。
一般来说,fork
模式适用于中低流量的简单应用,而 cluster
模式更适合于需要更好性能和可扩展性的高流量应用。然而,需要注意的是,cluster
模式比 fork
模式需要更多的内存和 CPU 资源,所以它可能不适合所有的应用。
要切换模式,在部署应用程序时使用 --exec-mode
参数:
pm2 start app.js --exec-mode=cluster
或在 ecosystem.config.js
文件中设置:
module.exports = {
apps: [
{
exec_mode: "cluster",
},
],
};
例子
Nuxt
module.exports = {
apps: [
{
name: "nuxt-app",
exec_mode: "cluster",
port: 3000,
script: "./node_modules/nuxt/bin/nuxt.js",
args: "start",
},
],
};
Next
module.exports = {
apps: [
{
name: "next-app",
exec_mode: "cluster",
port: 3000,
script: "./node_modules/next/dist/bin/next",
args: "start",
},
],
};