使用 PM2 运行 Strapi

页面摘要: 构建管理面板,在一个 NODE_ENV 设为 production 的 ecosystem.config.js 文件中描述你的应用,然后用 pm2 start 启动它。运行 pm2 startup 和 pm2 save,使应用在重启后自动恢复。

通过 npm run start 启动时,Strapi 在前台运行,并在你关闭终端或进程崩溃时停止。进程管理器则能让它持续运行:在失败时重启应用,在重启后将其拉起,并收集其日志。PM2 是 Node.js 应用的一个常见选择。本指南涵盖安装 PM2、向 PM2 描述一个 Strapi 应用,以及随之而来的运维任务。

WARNING
  • 一个已部署到你的服务器、并安装了依赖的 Strapi 5 应用(参见 部署指南)。
  • 服务器上已提供 Node.js 和包管理器。
  • Shell 访问权限,重启步骤需要 sudo 权限。

安装 PM2

全局安装 PM2,使 pm2 命令对你的 shell 和启动脚本都可用:

Yarn

yarn global add pm2

NPM

npm install -g pm2

确认安装成功:

pm2 --version

构建管理面板

管理面板是一个静态包,必须在服务器于生产环境启动之前构建。使用 NODE_ENV 设为 production 来构建,以便构建使用你的生产配置:

Yarn

NODE_ENV=production yarn build

NPM

NODE_ENV=production npm run build
WARNING

在构建命令本身上设置 NODE_ENV=production,而不是为整个 shell 会话设置。如果在安装依赖之前导出它,包管理器会跳过 devDependencies,而构建正需要它们。

创建 ecosystem 文件

PM2 可以从命令行启动应用,但配置文件能让设置纳入版本控制,并使每次部署都可重复。在 Strapi 项目的根目录创建该文件:

module.exports = {
  apps: [
    {
      name: 'strapi',
      cwd: '/srv/strapi',
      script: 'npm',
      args: 'start',
      env: {
        NODE_ENV: 'production',
        HOST: '0.0.0.0',
        PORT: 1337,
      },
    },
  ],
};

这些选项的作用如下:

选项作用
name你传递给其他 PM2 命令的名称,例如 pm2 restart strapi。
cwd项目的绝对路径。PM2 相对于它解析 script,因此无论你从哪个目录运行 pm2,应用都能正确启动。
script 与 argsPM2 运行的命令。使用包管理器而非文件路径,可以保持与手动启动 Strapi 时完全一致的行为。
env进程的环境变量。NODE_ENV 必须为 production,以便 Strapi 加载生产配置。
将密钥纳入版本控制

如果 ecosystem 文件被提交到版本控制,请勿在其中放入诸如 APP_KEYS、ADMIN_JWT_SECRET 或数据库凭据之类的密钥。请将它们保留在服务器启动时 Strapi 会读取的 .env 文件中,或从你的部署工具中注入(参见环境配置)。

使用 PM2 启动 Strapi

从 ecosystem 文件启动应用:

pm2 start ecosystem.config.js

检查它是否启动成功:

pm2 list

Strapi 条目应显示状态为 online。如果状态为 errored,或者重启计数持续攀升,说明进程正在失败并退出。请阅读日志查找原因:

pm2 logs strapi --lines 100

让 Strapi 在重启后持续运行

PM2 自身无法在重启后存活。它需要一个初始化脚本,以及一份关于要启动哪些应用的已保存快照。

  1. 生成初始化脚本。该命令会打印第二条命令,并已为你的初始化系统和用户预填好:

    pm2 startup
    
  2. 原样运行它打印出的命令。这一步才需要 sudo。

  3. 保存当前的进程列表,以便 PM2 知道要恢复什么:

    pm2 save
    

每当你添加、移除或重命名一个应用时,都要再次运行 pm2 save。否则,PM2 会恢复到上次保存时的列表。

管理日志

PM2 将每个应用的输出写入 ~/.pm2/logs/ 中的文件。这些文件会无限增长,因此请安装日志轮转模块:

pm2 install pm2-logrotate

设置大小上限以及保留多少个轮转后的文件:

pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 7

更新正在运行的部署

只要你的代码或管理面板配置发生变化,就必须重新构建管理面板包,并且重建必须在进程重启之前完成。请按以下顺序部署:

  1. 在服务器上获取新代码。

  2. 安装依赖。

  3. 使用 NODE_ENV=production 构建管理面板。

  4. 重启应用:

    pm2 restart strapi --update-env
    

--update-env 标志会让 PM2 重新读取环境,而不是复用进程首次启动时的取值。如果没有它,你对 .env 文件或 ecosystem 文件所做的更改将被忽略。

NOTE

PM2 仅在 cluster 模式下执行零停机时间的 pm2 reload,即它会在退役旧 worker 之前先启动替代 worker。在上面使用的单进程 fork 模式下,进程会先停止再启动,因此会有一个请求失败的时间窗口。如果你需要控制访客在该窗口期间看到的内容,请在 Strapi 前方放置一个反向代理,如 Nginx、Caddy、HAProxy 和 Traefik 指南所述。

运行多个实例

PM2 可以通过其 cluster 模式运行一个应用的多个副本,共享同一个端口。cluster 模式构建于 Node.js 的 cluster 模块之上,该模块需要一个 JavaScript 入口点。本指南前面使用的 script: 'npm' 值运行的是一个二进制文件,而 PM2 只能在 fork 模式下管理二进制文件。

在项目根目录添加一个直接启动 Strapi 的入口点:

const strapi = require('@strapi/strapi');

strapi.createStrapi(/* {...} */).start();
NOTE

对于 TypeScript 项目,请向 createStrapi 传入 distDir 选项,以便服务器从编译后的输出启动(参见使用 createStrapi 工厂)。

将 ecosystem 文件指向该文件,并选择 cluster 模式:

module.exports = {
  apps: [
    {
      name: 'strapi',
      cwd: '/srv/strapi',
      // highlight-start
      script: './server.js',
      exec_mode: 'cluster',
      instances: 'max',
      // highlight-end
      env: {
        NODE_ENV: 'production',
        HOST: '0.0.0.0',
        PORT: 1337,
      },
    },
  ],
};

Strapi 可以运行在此模式下,但实例之间没有任何协调机制,因此某些行为会发生变化。在启用之前请阅读本节。

并发模式同步

Strapi 在启动时运行其模式同步,每个进程运行一次,实例之间不共享锁。如果重启后内容类型不变则是安全的,因为同步会检测到模式未变而不做任何操作。

同步在两种情况下不安全:发布会更改内容类型的版本,以及带有待处理迁移的版本。此时同时启动的实例会对同一数据库发出并发模式更改和迁移。

对于此类版本,先启动单个实例并让其完成启动,再启动下一个实例。这是在多个进程针对一个数据库运行时的固有属性,因此将实例分布在不同主机上也无法避免。

运行多个实例还有另外 3 个值得了解的后果:

  • CRON 任务在每个 Strapi 进程内调度,因此任务在每个实例上运行一次,而不是整体运行一次。设置为夜间运行的任务会运行与实例数量相同次数。如果项目设置 cron.enabled 为 true,要么将任务移出 Strapi,要么将它们保留在单个实例上。
  • Strapi 在内存中保存的任何内容都只属于一个实例,因为每个实例都是独立进程。Strapi 核心不会在它们之间复制任何状态。
  • 默认的本地上传提供方将文件写入实例自身的磁盘。共享同一台机器和项目目录的实例共享该磁盘,但不同机器或不同容器中的实例则不共享。在这种情况下,请使用基于对象存储的媒体库提供方之一。

鉴于这些限制,请从位于反向代理之后的单个实例开始。只有在实测单个实例确实不够时,再按上述方式增加实例。

验证应用是否正在运行

确认应用正在运行且可达:

  1. 运行 pm2 list,检查 Strapi 条目是否显示为 online 且重启计数没有攀升。

  2. 请求健康检查路由,服务器就绪时会返回 HTTP 204 No Content:

    curl -I http://localhost:1337/_health
    
  3. 重启服务器。

  4. 再次运行 pm2 list。应用应处于 online 状态,而无需你手动启动。

故障排查

以下每个症状都指向一个具体的原因。症状以粗体显示,其后为导致该症状的原因以及需要更改的内容:

  • pm2 list 中显示进程为 errored。 请阅读 pm2 logs strapi --lines 100。常见原因包括:缺少构建产物、数据库不可达,或缺少环境变量。

  • PM2 在循环中重启 Strapi。 应用在启动时立即退出。日志中会指明原因。在修复之前,请使用 pm2 stop strapi 停止该循环,而不是任由其重试。

  • Strapi 在重启后没有恢复。 要么从未运行过 pm2 startup 打印出的命令,要么在添加应用后没有运行 pm2 save。请重新执行这两步。

  • 对环境变量的更改没有生效。 PM2 会复用进程首次启动时的环境。请使用 pm2 restart strapi --update-env 重启。

  • 部署后管理面板显示旧版本。 管理面板包没有被重新构建。请使用 NODE_ENV=production 运行构建,然后重启。

后续步骤

后续步骤

在 Strapi 前方放置反向代理

查看服务器配置选项

阅读部署指南