Skip to content

08 · 部署与运维 ​

文档定位:给出从零到可运行环境的完整搭建步骤,以及进程编排、环境变量隔离、健康检查、备份与故障排查的运维约定。

关联文档:docs/adr/0007-node-toolchain-nvm-pnpm-pm2.md、docs/01-系统总体方案.md、docs/04-MCP安全网关设计.md、docs/09-原型验证方案.md


1. 工具链:NVM → PNPM → PM2 ​

NVM  ──►  PNPM  ──►  PM2
管理 Node 版本    安装依赖     守护 Node 进程

三层各自有唯一权威配置,环境因此可复现:

层权威文件作用
NVM.nvmrc固定 Node 版本
PNPMpnpm-workspace.yaml + pnpm-lock.yamlworkspace 定义与依赖锁定
PM2deploy/ecosystem.config.cjs进程拓扑、重启策略、环境变量、日志路径

1.1 Node 版本选择(关键) ​

OpenClaw 官方要求:Node 24.15+(推荐),或 Node 22 LTS ≥ 22.22.3,或 Node 25.9+。

本机现状核对:

本机 Node版本是否满足
托管版本22.22.2❌ 低于 22.22.3 下限
系统版本22.23.1✅

决策:统一使用 Node 24.x(≥24.15),理由见 ADR-0007。

bash
# .nvmrc 内容
24.15.0
bash
# 安装并切换
nvm install 24.15.0
nvm use                 # 自动读 .nvmrc
node -v                 # 应输出 v24.15.0

⚠ 坑位记录:nvm use 只影响当前 shell。PM2 守护的进程继承的是 PM2 守护进程启动时的 Node 版本。切换 Node 版本后必须 pm2 kill 再重新 pm2 start,否则守护进程仍用旧版本 Node 运行——而旧版本可能不满足 OpenClaw 下限,表现为启动即报错。

1.2 PNPM ​

bash
corepack enable
corepack prepare pnpm@latest --activate
pnpm -v

仓库为 monorepo:

yaml
# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
bash
pnpm install --frozen-lockfile     # CI / 部署环境用
pnpm -r build                      # 递归构建

约定:只用 pnpm-lock.yaml,不引入 npm/yarn 的 lockfile。

1.3 PM2 ​

bash
pnpm add -g pm2
pm2 -v

2. 进程拓扑与编排 ​

2.1 进程清单 ​

PM2 进程名脚本作用启动顺序
mcp-gatewaypackages/mcp-gateway/dist/index.jsMCP 安全网关(安全边界)1
business-apipackages/business-api/dist/index.js业务接口服务2
openclawopenclaw gatewayAgent 运行时 + 安全管控插件层3
web(可选)Nginx 或静态服务Web 控制台任意

顺序理由:插件层的 plugin:init 会做网关健康检查;网关不可达则插件拒绝启用(fail-closed)。因此网关必须先起。

2.2 deploy/ecosystem.config.cjs ​

js
// deploy/ecosystem.config.cjs
// 注意:本文件入库,但 env_file 指向的文件不入库(见 .gitignore)
const path = require('path');
const ROOT = path.resolve(__dirname, '..');

module.exports = {
  apps: [
    {
      name: 'mcp-gateway',
      cwd: ROOT,
      script: 'packages/mcp-gateway/dist/index.js',
      instances: 1,
      exec_mode: 'fork',
      env_file: 'deploy/env/mcp-gateway.env',
      env: { NODE_ENV: 'production' },
      max_memory_restart: '512M',
      autorestart: true,
      max_restarts: 10,
      restart_delay: 3000,
      kill_timeout: 10000,
      error_file: 'logs/mcp-gateway-error.log',
      out_file: 'logs/mcp-gateway-out.log',
      merge_logs: true,
      time: true,
    },
    {
      name: 'business-api',
      cwd: ROOT,
      script: 'packages/business-api/dist/index.js',
      instances: 1,
      exec_mode: 'fork',
      env_file: 'deploy/env/business-api.env',
      env: { NODE_ENV: 'production' },
      max_memory_restart: '512M',
      error_file: 'logs/business-api-error.log',
      out_file: 'logs/business-api-out.log',
      merge_logs: true,
      time: true,
    },
    {
      name: 'openclaw',
      cwd: ROOT,
      script: 'openclaw',
      args: 'gateway',
      instances: 1,
      exec_mode: 'fork',
      env_file: 'deploy/env/openclaw.env',
      env: { NODE_ENV: 'production' },
      max_memory_restart: '1G',
      autorestart: true,
      error_file: 'logs/openclaw-error.log',
      out_file: 'logs/openclaw-out.log',
      merge_logs: true,
      time: true,
    },
  ],
};

注意:PM2 的 env_file 会加载文件中的变量。若某进程需要"显式不继承某变量",可在该 app 的 env 中把它设为空串——但更可靠的做法是从不在任何 env 文件中写这些变量。见 §3。

2.3 常用命令 ​

bash
pm2 start deploy/ecosystem.config.cjs          # 启动全部
pm2 start deploy/ecosystem.config.cjs --only mcp-gateway
pm2 restart openclaw                            # 重启单个(插件改动后必须)
pm2 list                                        # 查看全部进程状态
pm2 logs mcp-gateway --lines 200                # 查看日志
pm2 monit                                       # 实时监控
pm2 save                                        # 保存当前进程列表
pm2 startup                                     # 生成开机自启脚本(Linux)

Windows 开机自启:pm2 startup 在 Windows 不适用,需用 pm2-windows-startup 或任务计划程序配置开机运行 pm2 resurrect。


3. 环境变量隔离(安全核心) ​

这是本系统最重要的运维约定。 凭证按进程最小化分配,deploy/env/ 下每个文件只包含该进程需要的变量。

3.1 凭证分配矩阵 ​

变量mcp-gatewaybusiness-apiopenclaw(含插件层)
BUSINESS_DB_URL✅✅❌ 禁止
AI_DB_URL✅❌❌ 禁止
MQTT_URL / MQTT_USER / MQTT_PASS✅❌❌ 禁止
AGENT_TOKEN_SECRET(签发用)✅❌❌ 禁止
JWT_PUBLIC_KEY✅❌❌
JWT_PRIVATE_KEY❌✅❌
GATEWAY_MCP_ENDPOINT❌✅✅
AGENT_TOKEN(运行时令牌)❌❌✅
AGENT_ID❌❌✅
SECURITY_POLICY_PATH❌❌✅
OPENCLAW_GATEWAY_TOKEN❌❌✅

这张表是 docs/09-原型验证方案.md 中"凭证隔离验证"用例的判定依据。

3.2 文件示例 ​

ini
# deploy/env/mcp-gateway.env
NODE_ENV=production
PORT=7801
BUSINESS_DB_URL=file:./data/business.sqlite
AI_DB_URL=http://127.0.0.1:8000
MQTT_URL=mqtt://127.0.0.1:1883
MQTT_USER=gw-svc
MQTT_PASS=<从密钥管理注入>
AGENT_TOKEN_SECRET=<从密钥管理注入>
JWT_PUBLIC_KEY_PATH=./keys/jwt.pub.pem
LOG_LEVEL=info
ini
# deploy/env/business-api.env
NODE_ENV=production
PORT=7802
BUSINESS_DB_URL=file:./data/business.sqlite
JWT_PRIVATE_KEY_PATH=./keys/jwt.pem
JWT_PUBLIC_KEY_PATH=./keys/jwt.pub.pem
ini
# deploy/env/openclaw.env
NODE_ENV=production
GATEWAY_MCP_ENDPOINT=http://127.0.0.1:7801
AGENT_ID=ops-analyst
AGENT_TOKEN=<由网关签发,或由启动脚本拉取>
SECURITY_POLICY_PATH=./packages/security-plugin/policy.json
OPENCLAW_GATEWAY_TOKEN=<从密钥管理注入>
# ── 以下变量在此文件中永远不得出现 ──
# BUSINESS_DB_URL / AI_DB_URL / MQTT_* / AGENT_TOKEN_SECRET

3.3 校验脚本 ​

提供 deploy/scripts/check-env-isolation.sh,在部署后自动核对:

bash
#!/usr/bin/env bash
# 校验 openclaw 进程环境中不含业务凭证
set -euo pipefail
FORBIDDEN='BUSINESS_DB_URL|AI_DB_URL|MQTT_URL|MQTT_USER|MQTT_PASS|AGENT_TOKEN_SECRET'
if grep -Eq "$FORBIDDEN" deploy/env/openclaw.env 2>/dev/null; then
  echo "❌ openclaw.env 含禁止的凭证变量:"
  grep -En "$FORBIDDEN" deploy/env/openclaw.env
  exit 1
fi
echo "✅ 凭证隔离校验通过"

同时提供运行期核对(用 PM2 的进程环境做实测,比查文件更有说服力):

bash
# 查看 PM2 中 openclaw 进程的实际环境变量(用于答辩截图)
pm2 env <pm2-id-of-openclaw>

4. 从零搭建步骤 ​

4.1 前置组件 ​

组件版本安装方式
NVM—见官方安装说明
Node24.15+nvm install 24.15.0
PNPMlatestcorepack enable
PM2latestpnpm add -g pm2
Mosquitto2.x系统包管理器 / 官方安装包
OpenClaw锁定版本pnpm add -g openclaw@<锁定版本>(不用 @latest)
Chroma 或 Qdrant—原型期用 Chroma 本地持久化
STM32 工具链—见 docs/07-STM32边缘终端设计.md

4.2 步骤清单 ​

bash
# ① 环境
nvm install 24.15.0 && nvm use
node -v                                  # 期望 v24.15.x
corepack enable && pnpm -v

# ② 依赖
pnpm install --frozen-lockfile
pnpm -r build

# ③ 数据库初始化(双库,两套独立文件)
pnpm --filter mcp-gateway run db:migrate:business   # → data/business.sqlite
pnpm --filter mcp-gateway run db:migrate:ai         # → data/ai.sqlite / chroma/
pnpm --filter mcp-gateway run db:seed               # 内置管理员、示例设备

# ④ 知识库入库
pnpm --filter mcp-gateway run kb:ingest -- ./fixtures/manuals

# ⑤ 密钥与令牌
openssl genrsa -out keys/jwt.pem 2048
openssl rsa -in keys/jwt.pem -pubout -out keys/jwt.pub.pem
# 写入 deploy/env/*.env(这些文件不入库)

# ⑥ Broker
mosquitto -c deploy/mosquitto/mosquitto.conf -d
mosquitto_passwd -c deploy/mosquitto/passwd gw-svc
mosquitto_passwd    deploy/mosquitto/passwd stm32-node-001

# ⑦ 启动服务(注意顺序)
pm2 start deploy/ecosystem.config.cjs --only mcp-gateway
curl -s http://127.0.0.1:7801/health | jq     # 期望 ok:true, auditWritable:true
pm2 start deploy/ecosystem.config.cjs --only business-api
pm2 start deploy/ecosystem.config.cjs --only openclaw

# ⑧ 安装并启用安全管控插件层
openclaw plugins install --link ./packages/security-plugin
openclaw plugins enable security-plugin
openclaw gateway restart
openclaw plugins inspect security-plugin --runtime --json   # 关键验证

# ⑨ 安全基线自检
openclaw security audit
openclaw security audit --deep

# ⑩ 持久化
pm2 save

4.3 部署后必做的三项验证 ​

bash
# 1) 凭证隔离
bash deploy/scripts/check-env-isolation.sh
pm2 env <openclaw-pm2-id> | grep -E 'BUSINESS_DB|AI_DB|MQTT' || echo "✅ 未发现业务凭证"

# 2) 插件与钩子已注册
openclaw plugins inspect security-plugin --runtime --json

# 3) 审计可写
curl -s http://127.0.0.1:7801/health | jq '.checks.auditWritable'

5. 健康检查与告警 ​

对象检查方式判定
网关GET /healthok:true 且 checks.auditWritable:true
OpenClaw Gatewayopenclaw gateway status --deep --require-rpc返回 RPC 正常
业务接口服务GET /healthok:true
Brokermosquitto_sub -t '$SYS/broker/uptime' -C 1有输出
进程存活pm2 list无 errored / 重启次数异常增长

关键告警项:auditWritable: false。此时网关应主动进入拒绝模式,运维需立即处理(通常是 business-db 文件权限或磁盘满)。


6. 备份与数据管理 ​

对象备份方式频率说明
business-dbsqlite3 data/business.sqlite ".backup data/backup/business-$(date +%F).sqlite"每日用 .backup 命令而非直接复制文件(WAL 模式下复制可能不一致)
ai-db 向量数据复制 Chroma 持久化目录每周可从原始手册重建,优先级低
审计日志随 business-db 一起每日不得删除,是答辩证据
配置与 env手工归档到密钥管理变更时deploy/env/* 不入库,需单独备份
日志logs/ 保留 30 天—由 PM2 的 pm2-logrotate 模块轮转
bash
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 30

7. 故障排查 ​

现象可能原因排查步骤
OpenClaw 启动即报 Node 版本错误PM2 守护进程用了旧 Nodepm2 kill → nvm use → pm2 start
插件加载失败openclaw.compat.pluginApi / minHostVersion 与实际版本不符查实际版本,改正清单字段;openclaw plugins inspect <id>
--runtime --json 看不到钩子钩子事件名与版本不符,或插件未重启openclaw gateway restart;核对事件名
所有工具调用返回 AUDIT_UNAVAILABLEbusiness-db 不可写(权限/磁盘满/文件锁)curl /health 看 auditWritable;检查 data/ 权限与磁盘
Agent 调不到 MCP 工具工具名带前缀,tools.allow 写错查运行时工具清单;tools.deny:["*"] + 精确 allow
遥测不落库Broker 认证失败 / 主题不匹配 / deviceId 未登记mosquitto_sub -t 'iot/+/telemetry' -v 观察;查网关日志
网关端口被占用7801 冲突netstat -ano | findstr 7801
pnpm install 报 engine 不兼容Node 版本不符核对 .nvmrc
Agent 上下文膨胀、推理变慢遥测返回行数过多检查 limit 与插件层 R12 体积控制是否生效

8. 落地期演进方向 ​

原型期刻意保持简单,落地期需要补齐的部分记录在此,作为答辩"后续工作"章节的素材:

项原型期落地期
进程编排PM2(单机)Docker Compose / K8s
数据库SQLite 双文件(逻辑隔离)PostgreSQL + Qdrant 两套独立实例(物理隔离)
网关实例数1(fork)多实例 + 负载均衡(注意审计写入的并发)
审计存储同库同表独立实例 + 按月分区
令牌静态短时效令牌网关按会话动态签发 + 刷新
密钥管理.env 文件Vault / KMS
终端安全用户名密码 + 可选 TLS双向 TLS + 一机一密 + 固件签名与安全启动
可观测性PM2 日志 + 轻量指标OpenTelemetry + 集中式日志
多租户不支持(框架限制,见 ADR-0003)按信任边界拆分独立 Gateway