本文档面向当前仓库内的 Docker 构建与单机 Compose 部署路径,覆盖:
- 三个镜像如何构建
- 默认 Compose 路径的实际行为
- 首次启动时数据库、卷和环境变量的实际行为
- 常用运维命令与排障入口
当前部署骨架位于:
infra/docker/sandbox-runtime.Dockerfileinfra/docker/web.Dockerfileinfra/docker/supervisor.Dockerfileinfra/compose/docker-compose.ymlinfra/compose/docker-compose.prod.ymlinfra/compose/.env.example
| 镜像 | Dockerfile | 作用 | 关键特征 |
|---|---|---|---|
sandbox-runtime |
infra/docker/sandbox-runtime.Dockerfile |
FastAgent remote sandbox 服务 | 从 @fastagent/sandbox-runtime npm 包安装,并通过 repo-local wrapper 对齐真实 bot workspace;额外预装 agent-browser、lark-cli、bun、pnpm、uv、gh、ffmpeg、jq、压缩包工具以及 PDF / .docx 文本提取 CLI;默认浏览器路径通过 Browserless sidecar 执行 |
browserless |
Compose image ghcr.io/browserless/chromium |
远程浏览器 sidecar | 为 sandbox-runtime 内的 agent-browser -p browserless 提供受支持的浏览器会话后端 |
supervisor |
infra/docker/supervisor.Dockerfile |
管理 bot 生命周期、收敛状态、自动迁移 DB | 构建阶段 bundle 出 dist/index.js,运行层复用 repo-local @fastagent/cli@0.8.4,并预装 curl、gh、ffmpeg、procps |
web |
infra/docker/web.Dockerfile |
Next.js UI/API | 使用 Next standalone 运行层,并额外保留 pnpm-workspace.yaml、apps/supervisor/package.json、resources/skills/managed 与 procps,保证页头 FastAgent CLI 版本 badge 和 owner-scoped Sync Skills 接口都能在生产镜像中正常工作 |
- 三个镜像的 build context 都是仓库根目录
.。 .dockerignore已排除node_modules、.next、docs、测试产物和运行态数据,避免把无关内容打进镜像上下文。web镜像是多阶段构建。supervisor镜像是多阶段构建:build 阶段用esbuild产出apps/supervisor/dist/index.js,并复制dist/migrations;运行层通过node apps/supervisor/dist/index.js启动。
公开仓的生产镜像目标地址为:
ghcr.io/yokingma/weclaws/web:latestghcr.io/yokingma/weclaws/supervisor:latestghcr.io/yokingma/weclaws/sandbox-runtime:latest
发布新版本时,推送 v* tag 会触发 .github/workflows/docker-images.yml,自动构建并推送三张镜像。每张镜像都会写入当前 tag(例如 v0.1.0)和 latest 两个标签,供生产 Compose override 拉取。
infra/compose/docker-compose.yml作为本地联调基线。infra/compose/docker-compose.prod.yml会用build: !reset null清掉基础文件里的本地构建定义,默认改成拉取ghcr.io/yokingma/weclaws/*:latest,并通过WECLAWS_DATA_ROOT把 SQLite、instances、sandbox user workspaces 和 sandbox-runtime private config/status 绑定到宿主机目录。- 生产 override 还会拉起
ghcr.io/browserless/chromium:latest,保持和本地基线一致的远程浏览器拓扑。 - 生产部署时应叠加两个 Compose 文件,保持同一份服务拓扑、卷、健康检查和环境变量 contract。
在执行 Compose 前先确认:
- Docker Engine 可用。
docker compose可用。- 已复制
infra/compose/.env.example为infra/compose/.env。 - 如果使用生产 override,宿主机上的
${WECLAWS_DATA_ROOT}已提前创建并允许 Docker 读写。 BETTER_AUTH_SECRET已按实际环境填写。- Bot runtime 需要绑定至少一个用户 LLM profile。
APP_BASE_URL已和最终对外访问地址对齐;如果修改了WEB_PORT,也要同步调整它。- 如果需要首个管理员自举注册,
WEB_ADMIN_EMAILS已填写管理员邮箱白名单;不需要时可以留空。 - 如果走默认本仓库 sandbox 打包路径,允许构建
infra/docker/sandbox-runtime.Dockerfile。 - 如果要启用默认远程浏览器路径,
BROWSERLESS_TOKEN应替换成真实 token;不需要宿主机侧直连时,不必覆盖BROWSERLESS_API_URL - 默认 Compose 不会把
browserless暴露到宿主机端口;只有在本地调试或外部客户端接入时,才应通过额外 override 单独加ports - 已确认根
.env.example和infra/compose/.env.example的默认 provider/model 并不相同。
- 宿主机本地开发的
pnpm dev:web/pnpm dev:supervisor主要读取仓库根.env。 - Docker Compose 默认读取的是
infra/compose/.env。 - 不要把两者混为一谈。
Compose 解析变量时,当前 shell 已导出的同名环境变量优先级高于 --env-file / infra/compose/.env。
排查配置漂移时,先看最终渲染结果:
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml config如果输出值和 infra/compose/.env 不一致,优先检查当前 shell 是否已经导出了 APP_*、FASTAGENT_*、SANDBOX_*、SRT_*。
这些变量主要影响 Compose 渲染和宿主机端口映射,不直接进入业务容器的应用配置:
COMPOSE_PROJECT_NAMEWECLAWS_DATA_ROOTWEB_PORT
说明:
COMPOSE_PROJECT_NAME会影响容器、网络和卷名称前缀。WECLAWS_DATA_ROOT只用于docker-compose.prod.yml,控制宿主机 bind mount 根目录。WEB_PORT控制宿主机暴露出来的 web 端口;APP_BASE_URL应与它对应的真实访问 URL 保持一致。
生产环境推荐直接固定为下面这组值:
WECLAWS_DATA_ROOT=/srv/weclaws/data
APP_BASE_URL=https://weclaws.example.com
WEB_PORT=3000web 容器运行时至少依赖这些变量:
DATABASE_URL=file:/app/storage/sqlite/db.sqliteAPP_BASE_URLBETTER_AUTH_SECRETWEB_ADMIN_EMAILS(可选)WEB_USER_BOT_LIMIT(可选)SRT_POOL_STATUS_FILESRT_DEFAULT_*/SRT_PORT_BASE/SRT_PROXY_PORT_BASE/SRT_WORKSPACE_BASE_ROOT
说明:
web镜像是 Nextstandalone运行层,不能假设容器内还能读取宿主机根.env。web运行镜像还必须保留/app/apps/supervisor/package.json。web运行镜像除了 Next 产物外,还必须保留/app/resources与procps。WEB_ADMIN_EMAILS允许为空;非空时决定首个管理员白名单自举注册和管理员入口权限。- 当前 web runtime 不再用
FASTAGENT_DEFAULT_*或网关 env 去补齐 bot 运行配置;create bot 只读取 owner 的 LLM profiles。 web共享claws_instances卷的主要原因是 create bot 时要先创建实例目录;它本身不负责拉起 FastAgent 进程。web在用户注册时用SRT_DEFAULT_*创建默认 SRT pool;管理员 sandbox-runtime 页面通过SRT_POOL_STATUS_FILE读取 manager 状态。
supervisor 容器依赖:
DATABASE_URL=file:/app/storage/sqlite/db.sqliteFASTAGENT_SANDBOX_MODEINSTANCES_ROOT=/app/storage/instancesRECONCILE_INTERVAL_MSSRT_SERVICE_HOSTSRT_POOL_CONFIG_FILESRT_POOL_STATUS_FILESRT_WORKSPACE_MAP_DIRSRT_DEFAULT_*/SRT_PORT_BASE/SRT_PROXY_PORT_BASE/SRT_WORKSPACE_BASE_ROOT
说明:
- Compose 默认复用
apps/supervisor/node_modules/.bin/fastagent。 - 运行镜像会预装
curl、gh、ffmpeg、procps,其中procps用于单实例锁和 child process identity 读取容器内ps信息,避免启动阶段直接报Unable to determine process start time for pid 1。 FASTAGENT_BINARY_PATH只在显式 override 时才需要。- 当前 Compose 里的 child
SANDBOX_URL不是在.env里单独填写,而是由SRT_SERVICE_HOST和 bot owner pool 端口推导。 SANDBOX_URL/SANDBOX_API_KEY不再是 supervisor 启动配置;remote mode 会在 spawn 前从 owner-specific SRT pool 注入给 FastAgent child。- bot runtime 不再从任何 repo-wide
FASTAGENT_*env 补齐配置;这些变量如果保留,只服务于 contract smoke 或手工 CLI tooling,不属于默认 Compose 栈的运行面。 - 即使把
FASTAGENT_SANDBOX_MODE设为disabled,当前默认 Compose 仍会启动sandbox-runtimemanager;它不需要全局SANDBOX_API_KEY。 supervisor启动时会自动执行数据库迁移。- 镜像不会内置用户 API key、OAuth token、设备配对态等个性化 secrets;这类配置仍应在部署时通过环境变量或外部状态注入。
当前 Compose 路径会传入:
SRT_POOL_CONFIG_FILESRT_POOL_STATUS_FILESRT_MANAGER_PORTSANDBOX_COMMAND_EXTRA_PATHSLOG_LEVEL
说明:
- 默认路径会从
infra/docker/sandbox-runtime.versions.env里声明的@fastagent/sandbox-runtime版本构建镜像。 - 默认路径还会通过
AGENT_BROWSER_NPM_VERSION固定安装agent-browser,并通过LARK_CLI_NPM_VERSION固定安装官方lark-cli;当前公开 Compose 基线只保留 Browserless 远程浏览器路径,不再在sandbox-runtime镜像内预装本地 Chromium 或执行agent-browser install --with-deps。 - 默认路径还会通过
BUN_VERSION、PNPM_VERSION、UV_VERSION固定安装bun、pnpm和uv;当前基线分别是1.3.13、9.15.4、0.11.7。 - 由于上游
sandbox-runtime现在只给 session command 注入系统目录 PATH 基线,WeClaws 的sandbox-runtime镜像自身会默认设置SANDBOX_COMMAND_EXTRA_PATHS=/usr/local/bin,Compose 还会显式透传同一个值,把镜像里安装到/usr/local/bin的node、lark-cli、bun、pnpm、uv等 CLI 重新暴露给 remote sandbox 命令执行。 LOG_LEVEL会先驱动 manager 自身日志级别,并继续透传到 per-user SRT child;如果需要排查某个 child runtime,不能只看 manager 是否切到了debug。- 运行入口是仓库内的 manager;manager 读取
srt-pools.json,为每个 enabled user pool 启动srt-child-entry.mjs。 srt-child-entry.mjs会让 FastAgent host/tool 层继续看到真实 bot workspace root;/workspace只作为 sandbox 内命令别名和cwd翻译入口存在。- Compose 不再给 manager 传全局
API_KEY;per-user SRT child 的 API key 由 DB pool config 生成后写入srt-pools.json。 - 当前仓库接受上游 sandbox-runtime 的网络公开 contract:默认允许外网访问,只通过
SRT_DEFAULT_DENIED_DOMAINS写入新用户 pool 做 denylist 收口。 DATABASE_URL和INSTANCES_ROOT在当前 Compose 文件里固定写成容器内路径,不从infra/compose/.env.example读取。- Compose 还会给 supervisor 注入
SRT_WORKSPACE_MAP_DIR=/app/storage/sandbox-runtime-private/workspace-map;workspace map 只允许 supervisor 与 sandbox-runtime 通过私有共享卷读写,不再混在/app/storage/instances根目录里。 - 当前 Compose 基线会把新用户 pool 默认设为
SRT_DEFAULT_POOL_SIZE=3、SRT_DEFAULT_MIN_READY_PROCESSES=1、SRT_DEFAULT_SESSION_TIMEOUT_MS=600000。 - sandbox 镜像里额外包含的常用 CLI 基线:
- 浏览器自动化:
agent-browser - Feishu/Lark 官方 CLI:
lark-cli - JS 运行 / 包管理:
bun - Node 包管理:
pnpm - Python 项目 / 包管理:
uv - Python 解释器:
python3 - GitHub CLI:
gh - 媒体处理:
ffmpeg - 数据/文件:
jq、zip、unzip、file - 文本提取:
pdftotext/pdfinfo(来自poppler-utils)、pandoc
- 浏览器自动化:
- 这批工具属于 remote sandbox 执行面。
- 默认 Compose 还会额外提供
browserlesssidecar;受支持路径是sandbox-runtime内的agent-browser -p browserless
docker build -f infra/docker/sandbox-runtime.Dockerfile \
--build-arg AGENT_BROWSER_NPM_VERSION=0.27.0 \
--build-arg BUN_VERSION=1.3.13 \
--build-arg LARK_CLI_NPM_VERSION=1.0.32 \
--build-arg PNPM_VERSION=9.15.4 \
--build-arg UV_VERSION=0.11.7 \
-t weclaws/sandbox-runtime:local .
docker build -f infra/docker/supervisor.Dockerfile \
-t weclaws/supervisor:local .
docker build -f infra/docker/web.Dockerfile \
-t weclaws/web:local .适用场景:
- 只验证某一个 Dockerfile
- 需要本地提前缓存镜像
- 想把单个镜像推送到独立 registry
默认路径:
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml build生产环境如果直接使用已发布的 GHCR 镜像,不需要再本地 build;改用:
docker compose \
--env-file infra/compose/.env \
-f infra/compose/docker-compose.yml \
-f infra/compose/docker-compose.prod.yml \
pull
docker compose \
--env-file infra/compose/.env \
-f infra/compose/docker-compose.yml \
-f infra/compose/docker-compose.prod.yml \
up -d如果宿主机目录还不存在,先创建:
mkdir -p /srv/weclaws/data/sqlite /srv/weclaws/data/instances /srv/weclaws/data/sandbox-user-workspaces /srv/weclaws/data/sandbox-runtime-private一个可直接照抄的生产 override 片段:
cat >> infra/compose/.env <<'EOF'
WECLAWS_DATA_ROOT=/srv/weclaws/data
APP_BASE_URL=https://weclaws.example.com
WEB_PORT=3000
EOF如果只验证 sandbox 扩容后的 CLI 基线,优先跑:
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml build sandbox-runtime
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'agent-browser --help'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'lark-cli --version'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'bun --version'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'pnpm --version'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'uv --version'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'gh --version'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'ffmpeg -version'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'pdftotext -v'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'pandoc --version'
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh -lc 'jq --version && file --version'当前 Compose 栈包含四个服务:
browserlesssandbox-runtimesupervisorweb
卷映射:
claws_sqlite->web:/app/storage/sqliteclaws_sqlite->supervisor:/app/storage/sqliteclaws_instances->web:/app/storage/instancesclaws_instances->supervisor:/app/storage/instancesclaws_instances->sandbox-runtime:/app/storage/instancessandbox_user_workspaces->sandbox-runtime:/app/apps/sandbox-runtime/user-workspacessandbox_runtime_private->supervisor:/app/storage/sandbox-runtime-privatesandbox_runtime_private->web:/app/storage/sandbox-runtime-privatesandbox_runtime_private->sandbox-runtime:/app/storage/sandbox-runtime-private
说明:
web和supervisor必须共享同一份claws_instances,因为 bot 创建目录和 runtime 启动都依赖同一根实例目录。sandbox-runtime现在也必须挂载同一份claws_instances到相同绝对路径;否则 workspace map 就算命中,runtime 也无法访问 FastAgent child 实际传入的真实cwd。srt-pools.json、srt-pool-status.json和 workspace map 现在必须单独放在私有sandbox_runtime_private卷里,只给web、supervisor和sandbox-runtime共享;不要再把它写进instances根目录。sandbox-runtime仍然是独立 HTTP / Socket.IO 服务边界。browserless提供远程浏览器会话后端;默认由sandbox-runtime内的agent-browser -p browserless通过 Compose 内部服务名访问。- base Compose 不会给
browserless配置宿主机ports;默认只允许内部 Compose 网络访问。 - 当前 Compose 已为
sandbox-runtime固定配置:cap_drop: [ALL]cap_add: [SYS_ADMIN, NET_ADMIN]cgroup: privatesecurity_opt: [seccomp=unconfined, apparmor=unconfined]
sandbox-runtime镜像构建会删除/etc/passwd-、/etc/shadow-、/etc/group-和/etc/gshadow-,运行期 wrapper 也会 deny 这些备份路径与敏感/proc入口;Linux 下不再直接 deny/etc/mtab,因为它是/proc/mounts的符号链接,硬绑/dev/null会让 bubblewrap 启动失败。- Ubuntu 24 上如果
docker inspect仍显示AppArmor=docker-default,bubblewrap 可能在 mount namespace 阶段直接报Failed to make / slave: Permission denied;更新 Compose 后记得up -d --force-recreate sandbox-runtime - 生产 override 改用
${WECLAWS_DATA_ROOT}bind mount 后,SQLite、instances、sandbox user workspaces、sandbox-runtime 私有 config/status 目录都会直接出现在宿主机目录中,便于备份、迁移和排障;如果必须使用 bind mount,建议固定为/srv/weclaws/data这类不含个人用户名或项目临时路径的标准路径。最终避免 sandbox 内看到宿主源路径仍依赖运行期 deny/proc/*/mountinfo//proc/mounts。
cp infra/compose/.env.example infra/compose/.env说明:
infra/compose/.env.example现在只把硬必填项保持为未注释。- 其他参数都会以注释形式保留在文件里;需要覆盖默认行为时再取消注释,不要因为它们被注释就误判成“不支持”。
最少需要修改:
APP_BASE_URLBETTER_AUTH_SECRET
按场景补充:
WECLAWS_DATA_ROOT- 只有在叠加
docker-compose.prod.yml做生产部署时才需要取消注释并设置;本地默认 Compose 不使用它 - 推荐固定成
/srv/weclaws/data这类标准路径,避免 sandbox 内可见的 mount 元信息暴露个人用户名或临时目录
- 只有在叠加
WEB_ADMIN_EMAILS- 需要首个管理员白名单自举注册或管理员入口时填写;否则可留空
WEB_USER_BOT_LIMIT- 需要限制每个用户可创建 bot 数量时再取消注释
补充说明:
- 默认 Compose 栈不再接受 repo-wide LLM fallback env;部署后的 bot 必须在 web 里先创建并绑定用户级 LLM profile
- 如果只是要跑
pnpm test:fastagent-contract之类的 smoke,请在临时 shell 里单独导出FASTAGENT_API_KEY与FASTAGENT_MODEL/FASTAGENT_PROVIDER(或对应FASTAGENT_DEFAULT_*等价变量),不要把它们混回长期部署 env
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml up --build -dsupervisor启动时会自动运行migrateDatabase()。web容器不会执行pnpm db:migrate,也不应该被当成 migration 容器使用。- 首次启动时,SQLite 文件会在共享卷中自动创建。
如果需要手工重跑 migration,请在 supervisor 容器里执行:
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml \
exec supervisor pnpm --filter @weclaws/db db:migratedocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml ps正常情况下:
sandbox-runtime应显示为healthyweb应显示为healthysupervisor应显示为Up
curl -i http://localhost:3000/login
curl -i http://localhost:8788/health正常情况下:
/login返回200/health返回200
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml logs -f web
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml logs -f supervisor
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml logs -f sandbox-runtime
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml logs -f browserless仅看 /health 和 docker compose ps 还不够。
真实 runtime 验证至少要满足其中之一:
- 完成一次 bot 登录并收到二维码
- 完成一次真实 turn,确认 sandbox session 能创建并执行命令
- 至少成功跑通一次
POST /sessions+POST /commands
如果要做真实 turn 验证,至少确认当前 Compose 基线仍保持 SRT_DEFAULT_POOL_SIZE=3、SRT_DEFAULT_SESSION_TIMEOUT_MS=600000;若被本机 shell 覆盖回较小值,session timeout + reconnect 更容易把 pool 顶满。
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml build web
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml build supervisor
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml build sandbox-runtime
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml build browserlessdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml restart web
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml restart supervisor
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml restart sandbox-runtime
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml restart browserlessdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml configdocker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec supervisor sh
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec sandbox-runtime sh
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml exec browserless shweb 容器是精简运行层,不建议把它当调试入口或工具容器使用。
保留卷:
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml down删除卷:
docker compose --env-file infra/compose/.env -f infra/compose/docker-compose.yml down -v警告:
down -v会删除 SQLite 和实例目录卷。- 这会清空当前 Compose 路径下的持久化数据。
优先检查当前 shell 是否已经导出了:
APP_BASE_URLBETTER_AUTH_SECRETWEB_ADMIN_EMAILSWEB_USER_BOT_LIMITSRT_DEFAULT_*SRT_PORT_BASESRT_PROXY_PORT_BASE
这是最常见的“明明改了 infra/compose/.env 但容器里还是旧值”的原因。
优先检查:
APP_BASE_URLBETTER_AUTH_SECRETDATABASE_URLWEB_ADMIN_EMAILS
如果 create bot 页面无法提交,优先确认当前账号是否已经在 /settings 创建至少一个可用的 LLM profile,并且该 bot 绑定了正确的 profile。
这通常不是异常现象。
原因:
- remote sandbox session 是懒建立的
- owner-specific
SANDBOX_URL/SANDBOX_API_KEY不会在 child process 启动瞬间就被验证
因此:
process_startedqr_coderunning(restored)
都不能证明 sandbox 已经成功连通。
重点检查:
- 当前 runtime 是否真的支持 sandbox worker 所需的 Linux 隔离原语
cap_drop/cap_add/cgroup/security_opt是否被宿主机平台吞掉- 用
docker inspect <sandbox-container> --format 'AppArmor={{.AppArmorProfile}} CapDrop={{json .HostConfig.CapDrop}} CapAdd={{json .HostConfig.CapAdd}} Cgroupns={{.HostConfig.CgroupnsMode}} SecurityOpt={{json .HostConfig.SecurityOpt}} Privileged={{.HostConfig.Privileged}}'确认当前容器不是AppArmor=docker-default,并且保留CapDrop=["ALL"]、CapAdd=["SYS_ADMIN","NET_ADMIN"]与Cgroupns=private;Ubuntu 24 上 AppArmor 未放开是 bubblewrap 命令执行失败的高频根因 - 当前
sandbox-runtime容器日志里是否已经打印安装了 workspace override 的信息
记住:
/health正常不代表 worker 一定可执行命令journalctl -k没抓到apparmor/DENIED日志,也不能单独证明 AppArmor 没介入;以容器实际AppArmorProfile为准- 常见现场症状是
/health正常、bot 能启动,但ls这类命令返回bwrap: Failed to make / slave: Permission denied - 如果刚更新过 Compose 安全参数,务必执行
docker compose ... up -d --force-recreate sandbox-runtime,不要只restart - 至少要补一轮实际命令执行验证
这是当前真实 turn smoke 的常见瓶颈。
处理方式:
- 不要在真实 turn 验证环境把
SRT_DEFAULT_POOL_SIZE固定为1 - 当前 Compose 基线建议值是
SRT_DEFAULT_POOL_SIZE=3 - 同时建议保持
SRT_DEFAULT_SESSION_TIMEOUT_MS=600000,避免短 session timeout 放大 reconnect 抖动 - 需要定位单个用户 pool 时,优先看管理员
/admin/sandbox-runtime页面里的 pool 状态、端口和资源采样
最关键的是两份持久化数据:
- SQLite 数据卷
claws_instances卷
只保留其一会导致状态不一致或恢复不完整。
- 停止
web - 停止
supervisor - 按需决定是否保留
sandbox-runtime - 备份 SQLite 与实例目录卷
- 更新镜像或代码
- 先起
sandbox-runtime - 再起
supervisor - 最后起
web
- 默认 Compose 路径已经是自包含的 repo-local 构建,不依赖 FastAgent 上游仓库的 Dockerfile。
web的运行时环境现在必须由 Compose 显式注入,不能再把宿主机根.env当成容器内隐式依赖。supervisor是当前默认的 migration owner。- 判断 Docker 路径“真的可用”的最低标准,不只是三服务起来,而是至少完成一次真实 sandbox 命令执行或真实 turn。