feat(workspace): resolve_workspace 加 ZCBOT_WORKSPACE_DIR env 覆盖(per-host 落盘)
prod 要把重写入的 workspace/users/ 落到独立数据盘(xfs prjquota),但 config/agent.yaml 的 workspace_dir 是 dev/prod 共用提交的,改绝对路径会带歪 dev。 resolve_workspace 优先级改为 env ZCBOT_WORKSPACE_DIR > yaml workspace_dir > 默 "workspace" (对齐 sandbox.* 的 yaml+env 模式);env/cfg 值都按 ROOT/<值> 解析,绝对路径直接生效。 dev 不设 env 维持 ROOT/workspace,prod systemd 设数据盘绝对路径,两边不抢同一份 yaml。 PG 暂不迁(元数据库小,留默认 /var/lib/postgresql 少坑)。 RUN.md:env 段加 ZCBOT_WORKSPACE_DIR + 新增「workspace 落独立数据盘」段 (mkfs.xfs + fstab prjquota + rsync 迁移 + systemd env)+ 故障表一行。 PROGRESS.md:2026-06-02 加一条。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
198e95cd84
commit
382a85e88e
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
### 2026-06-02
|
||||
|
||||
- **`resolve_workspace` 加 env 覆盖 `ZCBOT_WORKSPACE_DIR`(per-host 部署,不碰共用 yaml)**:prod 想把重写入的 `workspace/users/` 落到独立数据盘(1T xfs prjquota,空间 + OS 层配额一步到位),但 `config/agent.yaml` 的 `workspace_dir` 是 dev/prod 共用提交的,改成绝对路径会带歪 dev。改法:`core/agent_builder.py:resolve_workspace` 优先级改为 **显式 arg > env `ZCBOT_WORKSPACE_DIR` > cfg `workspace_dir` > 默 `workspace`**,env/cfg 值都 `ROOT / ws`(POSIX 上绝对右操作数覆盖左 → 绝对路径直接生效,相对挂 repo 根)。prod systemd 设 `Environment=ZCBOT_WORKSPACE_DIR=/data/zcbot-workspace`,dev 不设照旧。PG 暂不迁(元数据库小,留默认 `/var/lib/postgresql` 少坑,等真涨到 30–40G 再说)。**对外行为(env 变量)变化 → 更 RUN.md**:env 段加 `ZCBOT_WORKSPACE_DIR`、新增「workspace 落独立数据盘」段(整盘 mkfs.xfs + fstab prjquota + rsync 迁移 + systemd env)、故障表加一行。DESIGN 不动(无架构/schema 变化)。
|
||||
|
||||
- **修 embed 模式"登录页一闪而过"(绘制时机,非鉴权)**:`web/static/dev.html` 的 `#login` 默认 `display:flex` 且带 `login-in .35s` 动画,而加 `body.embed-mode`(→ CSS 隐藏 `#login`)的 `embedInit()` 在 body 末尾才跑;单文件 3800+ 行,浏览器常在解析到底部脚本前就先把登录卡画出来 → 闪一下。改法:在 `<body>` 第一行加一段同步内联脚本,`?embed=1` 时立即 `document.body.classList.add("embed-mode")`,赶在 `#login` 解析/绘制之前隐藏它 → 根本不绘制。只是"绘制闸门",底部 `embedInit()`(postMessage 握手 / `embed-waiting` 覆盖层 / token 分支)完全不动,`embed-mode` 幂等。未提前加 `embed-waiting`(有 stored token 时 `embedInit` 走 `enterApp` 不移除等待层会卡死,故等待层决定仍留底部按 token 判)。**bug 修复,DESIGN 不动;URL 参数/命令/env 无变化,RUN 不动**。
|
||||
|
||||
### 2026-06-01
|
||||
|
|
|
|||
48
RUN.md
48
RUN.md
|
|
@ -372,6 +372,14 @@ sudo -u zcbot docker network create --internal zcbot-sandbox-net
|
|||
# PG 实际 IP,逗号分隔。defense-in-depth ── 即便落内网三段(§7.5 #1),
|
||||
# init.sh 再加一遍 DROP 规则。生产部署必填。
|
||||
ZCBOT_PG_IPS=10.1.2.3,10.1.2.4
|
||||
|
||||
# workspace 根目录(per-host 覆盖)。来源只有两个:这条 env,或 yaml `workspace_dir`
|
||||
# (默值 = `workspace`);env 设了就用 env,没设就用 yaml 那条。两者都按 `ROOT/<值>` 解析
|
||||
# (绝对路径直接生效,相对路径挂 repo 根下)。所以**不设这条 env → 走 yaml 的
|
||||
# workspace_dir=workspace → ROOT/workspace(即 zcbot 下的 workspace)**,dev 维持原样。
|
||||
# prod 设成数据盘绝对路径,把重写入的 user 子树落过去(下方「workspace 落独立数据盘」段),
|
||||
# 不碰提交进仓库的 agent.yaml,两边不抢同一份配置。
|
||||
# ZCBOT_WORKSPACE_DIR=/data/zcbot-workspace
|
||||
```
|
||||
|
||||
### 验证
|
||||
|
|
@ -544,6 +552,45 @@ uid 与 host uid 对齐(错配 → exec 写 `/workspace` 全 EACCES)⑤ `workspa
|
|||
lifespan 启动时同样会打第 ⑤ 项的 WARN 到 stdout(`[startup] [warn] fs quota ...`),
|
||||
应用层周期扫描仍生效;**仅外部用户开放前必须把 ⑤ 升级到 OS 层 quota**。
|
||||
|
||||
### workspace 落独立数据盘(prod,大空间 + quota fs)
|
||||
|
||||
prod 的 `workspace/users/<uuid>/` 是重写入区(报告 / 图 / pptx 等大件落这,DB 只存元数据)。
|
||||
推荐挂一块独立数据盘(xfs prjquota),空间和 OS 层配额一步到位。**dev 不动** —— 走提交进
|
||||
仓库的相对 `workspace_dir`(= `ROOT/workspace`);prod 在 systemd unit 里设 env
|
||||
`ZCBOT_WORKSPACE_DIR` 指到数据盘,两边不抢同一份 `agent.yaml`。
|
||||
|
||||
PG 不必跟着搬:它是元数据库,长期个位数~几十 G,根盘够用;留默认 `/var/lib/postgresql/<ver>/main`
|
||||
更省坑(`pg_ctlcluster` / AppArmor 按标准路径来)。等 `pg_database_size` 真奔 30–40G、根盘紧了
|
||||
再迁,那时 `/data` 下加个 `postgresql/` 子目录布局照样兼容。
|
||||
|
||||
```bash
|
||||
# 假设新盘是整块裸盘 /dev/vdb(lsblk 看,无分区表直接整盘格,数据盘惯例)
|
||||
# 0) 停服务(迁移时别再写 workspace)
|
||||
sudo systemctl stop zcbot
|
||||
|
||||
# 1) 整盘格 xfs
|
||||
sudo mkfs.xfs /dev/vdb
|
||||
|
||||
# 2) 写 fstab(UUID + prjquota),挂 /data
|
||||
sudo mkdir -p /data
|
||||
UUID=$(sudo blkid -s UUID -o value /dev/vdb)
|
||||
echo "UUID=$UUID /data xfs defaults,prjquota 0 0" | sudo tee -a /etc/fstab
|
||||
sudo mount -a
|
||||
findmnt -no FSTYPE,OPTIONS /data # 期望:xfs ... prjquota
|
||||
|
||||
# 3) 迁现有 workspace 数据(prod 若 workspace 还空则跳过 rsync),owner 对齐跑服务的账号
|
||||
sudo rsync -aXS /home/ubuntu/zcbot/workspace/ /data/zcbot-workspace/
|
||||
sudo chown -R ubuntu:ubuntu /data/zcbot-workspace # uid 必须 == 容器内 zcbot(HOST_UID)
|
||||
|
||||
# 4) systemd unit 加 env 指过去(Environment= 或 EnvironmentFile 的 .env),重启
|
||||
# Environment=ZCBOT_WORKSPACE_DIR=/data/zcbot-workspace
|
||||
sudo systemctl daemon-reload && sudo systemctl start zcbot
|
||||
python3 main.py sandbox check # fs quota 那项应变 [ok]
|
||||
```
|
||||
|
||||
确认 `sandbox check` 通过、新 task 文件确实落 `/data/zcbot-workspace/users/...` 后,再删旧
|
||||
`/home/ubuntu/zcbot/workspace`。
|
||||
|
||||
### 配额硬化(§7.5 #4,外部开放前必做)
|
||||
|
||||
应用层磁盘配额能挡常规超额,**但扫描间隙打满共享 fs 拖死同节点**这条硬要 OS 层
|
||||
|
|
@ -598,6 +645,7 @@ sudo xfs_quota -x -c "limit -p bhard=10g zcbot_<user_uuid>" /opt
|
|||
| Sandbox 容器 build 完起不来,`docker logs` 显示 iptables 报错 | 缺 NET_ADMIN cap(`--cap-add=NET_ADMIN` 漏了)或 kernel 不支持(WSL2 / OpenVZ 环境不能跑)。Ubuntu 物理 / KVM 正常。验:`docker exec ... iptables -V` |
|
||||
| 启动报 `ZCBOT_SANDBOX_BACKEND=docker but sandbox init failed: ...` | docker daemon 没起 / 用户不在 docker group / network create 失败。先跑 `main.py sandbox check` 看哪一项 err |
|
||||
| `[startup] [warn] fs quota: <fstype> on ...` | workspace 所在 fs 没启 OS 层 quota。dogfood 阶段忽略;外部用户开放前必须升级 xfs prjquota / ext4 project / zfs(详 RUN.md「配额硬化」段) |
|
||||
| prod 想把 workspace 落独立数据盘,但 `agent.yaml` 是 dev/prod 共用提交的 | 别改 `workspace_dir`(会带歪 dev)。prod systemd 设 env `ZCBOT_WORKSPACE_DIR=/data/zcbot-workspace`(优先级 env > yaml > 默)。详「workspace 落独立数据盘」段 |
|
||||
| `docker run zcbot-sandbox:latest` 报 `Unable to find image` | 镜像没 build。`sudo -u zcbot docker build -f deploy/sandbox/Dockerfile --build-arg HOST_UID=$(id -u zcbot) --build-arg HOST_GID=$(id -g zcbot) -t zcbot-sandbox:latest .` |
|
||||
| 镜像 build pip 报 `ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', ...)` | 境内访问 PyPI 抖动。加 `--build-arg PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple/`(腾讯云内网)或阿里云 / 清华源,详 RUN.md「镜像构建」段。Dockerfile 已把 pip timeout 拉到 60s,主因仍是源不通而非超时 |
|
||||
| pip 报 `Could not find a version that satisfies the requirement litellm>=1.83.0`(伴随一串 `Ignored ... yanked versions: 0.1.xxxx`) | 用的镜像源同步滞后,没有该新版本。**阿里 PyPI 一度只到 litellm 1.82.6** —— update.sh 默认已改腾讯源(到 1.88)。若手动 build 撞到:换 `PIP_INDEX_URL=https://mirrors.cloud.tencent.com/pypi/simple/` 或清华源。那串 `0.1.xxxx` 是 litellm 远古版本,纯干扰信息 |
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ state.json 已删除(元数据全在 PG)。
|
|||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Callable, Optional, Tuple
|
||||
|
|
@ -94,8 +95,19 @@ def _resolve_executor(
|
|||
|
||||
|
||||
def resolve_workspace(workspace: Optional[str], cfg: Optional[dict] = None) -> Path:
|
||||
"""workspace 根解析,优先级:显式 arg > env `ZCBOT_WORKSPACE_DIR` > cfg `workspace_dir` > "workspace"。
|
||||
|
||||
env 覆盖给 per-host 部署用 —— prod 在 systemd 里设 `ZCBOT_WORKSPACE_DIR=/data/zcbot-workspace`
|
||||
把重写入的 user 子树落到独立数据盘(xfs prjquota),dev 不设就吃提交进仓库的相对
|
||||
`workspace_dir`(= ROOT/workspace),两边不抢同一份 yaml。env / cfg 值绝对相对都行:
|
||||
`ROOT / "/abs"` 在 POSIX 上即 "/abs"(绝对右操作数覆盖左),相对则挂在 repo 根下。
|
||||
"""
|
||||
cfg = cfg or load_config()
|
||||
p = Path(workspace) if workspace else ROOT / cfg.get("workspace_dir", "workspace")
|
||||
if workspace:
|
||||
p = Path(workspace)
|
||||
else:
|
||||
ws = os.getenv("ZCBOT_WORKSPACE_DIR") or cfg.get("workspace_dir", "workspace")
|
||||
p = ROOT / ws
|
||||
p.mkdir(parents=True, exist_ok=True)
|
||||
return p
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue