Files
Mujoco_WASM/docs/website-deployment.md
chenlin 7519309a27
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
fix: release v1.0.3 预设渲染与语言搬运监督修复
2026-09-24 17:02:10 +08:00

8.1 KiB
Raw Permalink Blame History

CADWorld Sim 网站部署与运维

目标:https://cadworld-sim.robotquan.com,主机 root@47.93.31.109。复用 1Panel 的 OpenResty,独立容器仅发布 127.0.0.1:8768。不安装训练/GPU 服务,不改系统 Python,不需要访问者开启终端。

当前在线版本:20260924T081555Z-language-render-fix,上一版本 20260924T065821Z-language-v2。前后端共同发布,修复预设阴影/高 DPI 渲染与 Jev 技能上下文;公网非付费检查 6/6 及硬件双相机验证通过。详见 修复与发布记录,其中包含保留 iframe 热更新的回滚步骤。

iframe 嵌入已通过响应头热更新放行 https://cadworld.robotquan.com,未重启应用;接入示例、验证范围与配置回滚见 嵌入说明。重新发布旧包会覆盖该热更新,应从当前源码重新构建。

产品边界

  • 网站公开、无需注册或前端输入密钥。按用户新要求固定服务器 DeepSeek deepseek-flash 和 OpenRouter Jev typesafe/jev-1.13,费用由站长承担;前端移除模型/密钥/订阅配置。
  • 官方订阅仍在旧本地/非共享服务实现中保留,但当前共享密钥网站关闭其接口(403),没有绕过官方网络限制或登录其他账号。
  • 仅两项授权密钥存于 /opt/cadworld-sim/secrets/model-keys.env(0400、UID 10001,父目录 root/0700),只读挂载;不进入镜像、静态目录、发布包、浏览器或日志。每访客任务状态独立,空闲 30 分钟/最长 8 小时销毁;删除会话不会删除站长的服务器配置。
  • ZIP/URDF/地图/物理仿真仍在浏览器。网站隐藏训练、调参和外控,浏览器 Python/ONNX 保留;本地训练/外控功能保留,语言面板与网站统一精简并使用同源模型后端。
  • 容量:128 会话、每会话 1 推理/120 次每小时,生产全站并行上限 2。共享 SQLite 限额为每小时 60、滚动 24h 600 次上游调用;/command 保守预留 2 次,失败不退款,不自动重试。预算在 /opt/cadworld-sim/budget,不得在重启/发布时删除。匿名访问仍可能耗尽公共额度;建议供应商侧另设金额上限,当前不是货币金额硬预算。
  • 备案已由站长确认;正式备案/公安备案展示号码由站长提供,不能编造。TLS 证书首次无邮箱注册,自动续期由 systemd timer 负责,建议管理员另行设置证书到期监控。

本地开发与测试

source .venv/bin/activate
python -m decision_server --website-origin http://127.0.0.1:5173 --website-dev
# 开发者另一个终端(仅开发时):
npm run dev:website -- --host 127.0.0.1
npm run build:website       # 输出 website-dist/,不含 tuning.html
npm run test:e2e:website    # 真实后端 + 假 HTTP 上游,无 API 额度消耗

上述不带密钥启动方式只调试界面,执行会提示服务未就绪;真实开发需另显式提供 --website-key-file 和 --website-budget-file,不自动读取仓库 .env。生产必须 HTTPS,不能携带 --website-dev。前后端 Origin 要一致;本机 Bearer 模式仍使用 npm run decision-server,两种模式不自动回退。契约见 website-api.md。

构建、传输与首次发布

  1. 保留工作树变更基线,运行 TS/Vitest/Python/Playwright 门禁。build/website-deployment/baseline/ 保存部署前工作树摘要,不包含 .env。
  2. 使用 官方 crane v0.20.6,校验 release checksums。将 deploy/cadworld/images.lock.json 中的 linux/amd64 digest 拉为 docker archive(crane pull --platform linux/amd64 REF FILE);不需要本机 Docker daemon,也不让服务器访问不明镜像源。
  3. 为 Python 3.12 下载 requirements.lock.txt 指定 wheels,验证 hash;从官方 npm @openai/codex@0.147.0-linux-x64 包验证 registry 的 integrity 后提取二进制。文件放在 build/website-deployment/vendor/{wheels/,codex,codex-origin.json}。不复制任何用户的 Codex HOME/auth.json。
  4. npm run build:website 后运行 python3 deploy/cadworld/prepare_bundle.py RELEASE。脚本只打包显式白名单(含 v1 schema、v2 task schema、v2 scene 三个运行契约)、生成每文件 SHA-256,并输出归档 SHA-256;不打包 .env/.git/.venv/build/、测试代码或未批准的个人模型。明确内置的 web_platform/assets/robots/lekiwi-v1.zip 随 Vite 生成带哈希的静态资产,必须连同整个 website-dist/ 发布;/?robot=lekiwi-v1 即可自动导入,详见 内置机器人。
  5. SSH 传送归档、两份镜像 tar 和 SHA-256 到 /opt/cadworld-sim/uploads/。核验 SHA-256 后解压到 /opt/cadworld-sim/releases/RELEASE/,运行该版本的 deploy/import-images.sh IMAGE_DIRECTORY。先确认 172.30.88.0/24 不与现有 Docker 网络冲突。
  6. 首次运行 bash /opt/cadworld-sim/releases/RELEASE/deploy/bootstrap-tls.sh:备份原 OpenResty conf,创建独立 HTTP challenge vhost,签发域名证书,安装 HTTPS vhost 与续期 timer。不修改默认站点/1Panel账号;已存在同域名配置则拒绝覆盖。
  7. 站长明确授权后,在本机执行 source .venv/bin/activate && python deploy/cadworld/install-model-keys.py --confirm-server-keys,只选取项目 .env 的两项固定变量,经 SSH 标准输入传输;同时扫描静态资源避免密钥泄漏。不会把整个 .env 复制过去;若既有值不同则拒绝覆盖,轮换须单独授权。该步骤在共享模式首次发布前完成。
  8. bash /opt/cadworld-sim/releases/RELEASE/deploy/publish.sh RELEASE:逐文件验 hash、离线构建、无网络/无密钥挂载的运行时导入与 v2 契约预检、启动最小权限容器、健康检查、原子切换静态目录、nginx -t、reload。失败恢复上一版本,首次失败撤下新 vhost 恢复默认站点。成功生成 current.txt/previous.txt/image-id.txt。

只有 80/443 提供网站流量;8768 绑定回环。不挂载 Docker socket、SSH key、宿主 HOME;应用非 root、只读根、tmpfs、2 GiB/2 CPU/128 PID 限制。证书在已有 OpenResty www 挂载下独立 ssl/,不在站点 document root 内。

日常操作(目标主机)

cd /opt/cadworld-sim
docker compose --env-file release.env -f compose.yaml ps
docker compose --env-file release.env -f compose.yaml logs --tail 100 decision
curl -H 'Host: cadworld-sim.robotquan.com' http://127.0.0.1:8768/healthz
systemctl status cadworld-certificate.timer
bash /opt/cadworld-sim/renew-certificate.sh --dry-run
# 后台更新/重启会销毁访客会话;固定密钥和共享限额保留,用户再次执行建立新会话:
docker compose --env-file release.env -f compose.yaml restart decision
# 回滚:取 previous.txt 中的具体版本,调用那个版本的发布脚本,前后端一起恢复。
bash /opt/cadworld-sim/releases/PREVIOUS/deploy/publish.sh PREVIOUS

不要在 1Panel 重复创建同域名覆盖手工 vhost,不要将开发服务器或后台端口直接暴露公网。不要打印完整 Cookie、请求体、API_KEY、设备码或 OAuth 链接来排障。应用和 API 访问日志不记录请求正文;会话异常仅返回稳定错误码。

验证边界

普通测试使用假上游,不证明云端模型可用;mock 抓放使用真实 WASM 物理,不证明真实 LLM/Jev 被调用。真实 API 测试必须经站长授权并限定调用数:CADWORLD_LIVE_API=1 npx playwright test -c web_platform/playwright.website-live.config.ts --output build/website-deployment/本次目录。当前 v2 用例最多 4 次 DeepSeek/16 次 Jev,不读取浏览器凭据、不自动重试,任何安全停止如实记录。HEAD 的 200/401/403/404 只作为连通性证据,不是 POST 推理成功。生产证书、重启/回滚及浏览器验证结果另见实际发布记录。当前发布、调用费用和未完成的抓放复验见 服务器内置与语言控制记录。回滚到此前 BYOK 版本会恢复旧界面;受保护密钥文件和预算目录保留但旧服务不使用它们。