
1. 项目概述为什么需要一个“能一直在线”的 Agent 运行环境WeKnora 是一个面向知识协作与智能代理Agent编排的开源平台它的核心价值不在于单次调用某个模型而在于让多个具备不同技能的 Agent 能够长期、稳定、可追溯地协同工作——比如自动归档会议纪要、持续监控项目文档变更、按规则触发知识图谱更新、或在团队协作空间中扮演“智能协作者”角色。但现实很骨感绝大多数本地部署的 Agent 框架包括 WeKnora 的早期实践跑在普通进程里一旦终端关闭、SSH 断连、服务器重启所有正在运行的 Agent 就瞬间消失状态全丢任务中断日志清空。这不是“功能没做完”而是根本没进入生产可用阶段。我去年在给一家科研团队搭建 WeKnora 环境时就踩过这个坑。他们需要一个 Agent 每天凌晨自动抓取三个学术论坛的新帖提取关键信息后写入本地知识库并生成摘要推送到 Slack。我们用 Python 脚本Dify 的 API 调用方式实现了逻辑但上线三天后发现有两次凌晨任务根本没执行——查日志才发现是运维例行维护重启了服务器而我们的 Agent 进程没做任何守护机制直接被 kill -9 带走了。更麻烦的是它连“上次执行到哪一步”都没记录重跑就得全量拉取既浪费带宽又可能重复入库。这暴露了一个本质问题Agent 不是脚本它是服务服务必须有生命周期管理而生命周期管理的核心就是持久化运行环境。CubeSandbox 正是为此而生。它不是传统意义上的容器或虚拟机而是一个专为 AI Agent 设计的轻量级沙箱运行时——它把 Agent 的代码、依赖、配置、状态存储、日志输出、甚至网络策略全部封装在一个受控、隔离、可复现的边界内并通过一套标准化接口如 REST WebSocket对外提供服务。它解决的不是“能不能跑”而是“能不能可靠地、长时间地、安全地、可观测地跑”。关键词里的“沙箱”二字绝非噱头它意味着每个 Agent 实例都有独立的文件系统视图、受限的系统调用白名单、内存与 CPU 使用上限、以及明确的网络出口策略比如只允许访问指定域名或 IP 段。这直接回应了热词中反复出现的“agent安全”“agent anywhere”“agent架构”等深层诉求——没有沙箱谈何安全没有持久化谈何 anywhere没有统一运行时谈何架构演进所以“WeKnora 基于 CubeSandbox 的 Agent 持久化运行环境建设”本质上是一次基础设施级别的升级它把 WeKnora 从一个“演示型工具”推向“生产级平台”。它面向的不是只想跑个 demo 的新手而是真正要把 Agent 当作业务组件嵌入工作流的工程师、知识管理员和自动化负责人。如果你正被“Agent 总是断线”“状态总丢失”“多人共用环境互相污染”“无法审计谁在什么时候调用了哪个 Agent”这些问题困扰那么这篇内容就是为你写的。接下来我会完全基于一线实操经验拆解这套环境是怎么一步步搭起来的每一个选择背后是什么权衡哪些参数必须改哪些坑我替你踩过了。2. 整体设计思路为什么选 CubeSandbox 而不是 Docker 或 systemd在决定用 CubeSandbox 之前我们其实对比了至少四种主流方案纯 Python 进程 systemd 服务、Docker Compose 编排、Kubernetes Operator、以及 CubeSandbox 本身。最终选择 CubeSandbox不是因为它“新”而是因为它精准切中了 WeKnora 场景下的三个刚性痛点而其他方案要么过度复杂要么能力缺失。2.1 痛点一Agent 状态必须跨重启存活且需细粒度隔离WeKnora 的典型 Agent 往往需要维护自己的状态比如一个“会议纪要整理 Agent”会缓存最近 5 次会议的原始录音 URL 和已处理的段落哈希值一个“知识图谱同步 Agent”会记录上一次成功同步的时间戳和最后处理的实体 ID。这些状态不能存在内存里重启即失也不能简单扔进全局 Redis多 Agent 共享同一实例易冲突、难审计。我们需要的是每个 Agent 实例独享一份状态存储且这份存储在 Agent 进程终止后依然存在下次启动时能自动加载。systemd 方案可以用Restartalways保证进程常驻但状态存储得自己实现。常见做法是让 Agent 把状态写到/var/lib/weknora/agent-name/下再配好目录权限。问题在于如果两个 Agent 都想写同一个文件比如都叫state.json或者一个 Agent 的 bug 导致它疯狂写磁盘整个宿主机的/var/lib就可能被撑爆。systemd 本身不提供文件系统隔离。Docker 方案天然有 volume 映射可以给每个 Agent 容器挂载独立的 volume状态隔离没问题。但问题出在“启动开销”和“调试成本”上。一个简单的 WeKnora Agent镜像动辄 800MB含 Python、PyTorch、transformers每次启动要解压、加载、初始化模型冷启动时间超过 40 秒。而 WeKnora 的很多 Agent 是事件驱动的比如监听 Git 仓库 push要求秒级响应。更麻烦的是Docker 日志分散在docker logs和容器内/var/log两处调试时得来回切换。CubeSandbox 方案它内置了“沙箱内持久化存储”机制。当你定义一个 Agent 时只需在sandbox.yaml里声明storage: type: filesystem path: /data mount: /mnt/sandbox-dataCubeSandbox 启动时会为该 Agent 创建一个专属的、位于宿主机安全路径如/opt/cubesandbox/data/agent-uuid/下的目录并将其挂载为沙箱内的/data。Agent 代码里所有对/data的读写都会被透明映射到这个持久化位置。重启 Agent只要不删掉这个目录状态就在。而且这个目录的权限、配额可通过quota工具限制、甚至加密可选 LUKS 加密卷都能单独配置。这才是真正的“按 Agent 隔离”。2.2 痛点二Agent 依赖必须严格锁定避免“在我机器上能跑在你机器上报错”WeKnora Agent 的开发语言主要是 Python但实际依赖五花八门有的用llama-cpp-python调用本地 GGUF 模型有的用pymupdf解析 PDF有的用playwright控制浏览器。这些包的 C 扩展、系统库依赖如libglib-2.0.so、libfontconfig.so极易因宿主机环境差异而失败。我们曾遇到一个 Agent在开发机上pip install一切顺利部署到 CentOS 7 服务器却卡在pycairo编译因为缺pkg-config和cairo-devel。Docker 方案看似完美Dockerfile可以精确控制基础镜像和安装步骤。但问题在于“镜像爆炸”。一个 WeKnora 部署可能包含 10 个不同功能的 Agent如果每个都打一个独立镜像光镜像体积就超 10GB推送、拉取、存储都成负担。更糟的是镜像更新后旧版本 Agent 的状态如何迁移Docker 没有原生的状态迁移机制。CubeSandbox 方案它采用“沙箱模板 运行时注入”模式。你只需要维护一个通用的 Python 沙箱模板比如cubesandbox/python311:latest里面预装好gcc、make、pkg-config等构建工具以及numpy、requests等高频基础包。每个 Agent 的具体依赖则通过requirements.txt在沙箱启动时动态安装。CubeSandbox 内置了一个优化的 pip 安装器它会先检查宿主机缓存目录/opt/cubesandbox/cache/pip/是否有对应 wheel若无则从 PyPI 下载源码但在沙箱内编译利用沙箱的完整 build 工具链编译成功后将 wheel 缓存到宿主机供后续 Agent 复用。 这样10 个 Agent 共享同一个基础模板但各自拥有独立的、精确匹配的依赖树。pip list在每个沙箱里看到的包版本都是确定的不会互相污染。我们实测10 个不同依赖的 Agent 启动总时间比单个 Docker 容器还快 30%因为大部分 wheel 直接从缓存加载。2.3 痛点三Agent 必须可审计、可限流、可熔断且不侵入业务代码WeKnora 作为协作平台其 Agent 很可能被多个用户、多个工作区调用。我们必须能回答这些问题今天哪个 Agent 被调用最多有没有某个 Agent 因为外部 API 限流导致大量超时某个用户是否在滥用“网页转 Markdown”技能每秒发起 50 次请求这些监控和治理能力不能靠在每个 Agent 代码里硬编码埋点来实现那太脆弱也太重复。Kubernetes 方案Prometheus Grafana Istio 确实能提供强大的可观测性和流量治理。但代价是你需要维护一个完整的 K8s 集群学习曲线陡峭资源开销巨大etcd、kube-apiserver、controller-manager 等组件本身就要吃掉 2 核 4G。对于一个中小团队的 WeKnora 部署这属于典型的“杀鸡用牛刀”。CubeSandbox 方案它在沙箱网关层Gateway就集成了这些能力。当你通过 WeKnora 的 API 调用一个 Agent 时请求实际先到达 CubeSandbox Gateway由它完成身份鉴权校验 WeKnora 发来的 JWT Token提取user_id和workspace_id速率限制基于user_id或agent_id维度应用令牌桶算法Token Bucket默认配额是 10 QPS可动态调整熔断保护如果某 Agent 连续 5 次返回 HTTP 5xx 或超时30sGateway 会自动将其标记为“熔断”10 分钟内拒绝所有新请求并返回503 Service Unavailable全链路日志自动生成结构化日志包含request_id、agent_id、user_id、duration_ms、status_code、error_message如有并输出到统一日志文件/var/log/cubesandbox/gateway.log可直接对接 ELK 或 Loki。最关键的是这一切对 Agent 开发者完全透明。你的 Agent 代码还是写def execute(input: dict) - dict:完全不用关心限流、熔断、日志格式。Gateway 的配置是 YAML 文件驱动的修改后systemctl reload cubesandbox-gateway即可生效零代码重启。这种“基础设施即代码”的治理方式才是可持续的。综上CubeSandbox 的选择逻辑非常清晰它不是一个通用容器引擎而是一个为 AI Agent 生命周期管理量身定制的运行时。它用恰到好处的抽象解决了 WeKnora 在落地过程中最痛的三个问题——状态持久、依赖隔离、运行治理。它不追求“大而全”但求“准而稳”。接下来我们就进入实操环节看看这套环境到底怎么搭。3. 核心细节解析CubeSandbox 沙箱的构成与 WeKnora 的集成点要真正理解“基于 CubeSandbox 的 Agent 持久化运行环境”必须拆开 CubeSandbox 的内部结构看清它和 WeKnora 是如何咬合在一起的。这不像安装一个软件包那么简单而是一套精密的协议对接和配置协同。我把它拆解为四个核心模块沙箱运行时Runtime、沙箱网关Gateway、WeKnora 插件Plugin、以及持久化存储后端Storage Backend。每一个模块都有其不可替代的作用任何一个配置错误都会导致 Agent “看起来在跑实际上没干活”。3.1 沙箱运行时RuntimeAgent 的“操作系统”CubeSandbox Runtime 是整个环境的地基它负责创建、启动、监控、销毁每一个 Agent 沙箱实例。它的核心是一个用 Rust 编写的守护进程cubesandboxd之所以用 Rust是因为它需要极高的内存安全性和并发性能——毕竟一个生产环境可能同时运行上百个沙箱每个沙箱都是一个独立的 Linux namespace 进程组。cubesandboxd的配置文件/etc/cubesandbox/config.yaml是关键。其中最易被忽略、却最影响稳定性的参数是resource_limitsresource_limits: # 每个沙箱最大内存单位 MB memory_mb: 2048 # 每个沙箱最大 CPU 时间片权重CFS cpu_shares: 1024 # 沙箱内进程最大数量防止 fork bomb pids_limit: 256 # 沙箱内打开文件描述符最大数 nofile_limit: 1024为什么这些值如此重要举个真实例子我们最初把memory_mb设为4096认为“大点保险”。结果上线一周后发现服务器内存使用率持续 95% 以上dmesg里全是Out of memory: Kill process xxx (python)。排查发现某个用于 PDF 解析的 Agent 在处理一个 500 页的扫描件时pymupdf库会申请大量临时内存虽然最终释放但峰值远超预期。cubesandboxd的内存限制是硬限制cgroup v2 memory.max一旦超限内核会直接 OOM kill 沙箱主进程。我们将memory_mb改为2048后该 Agent 在超限时会收到SIGKILLWeKnora 侧能捕获到500 Internal Server Error并重试而不是拖垮整台服务器。记住沙箱的资源限制不是“保底”而是“安全阀”。设得太松害己设得太紧误伤。最佳实践是先用stress-ng模拟负载测出 Agent 的真实峰值再加 30% 余量。另一个关键细节是sandbox_template。CubeSandbox 不是为每个 Agent 从零构建环境而是基于模板克隆。模板本身就是一个标准的 OCI 镜像但它的构建方式很特别# FROM cubesandbox/base:ubuntu22.04 # RUN apt-get update apt-get install -y \ # build-essential python3.11 python3.11-venv python3.11-dev \ # libglib2.0-dev libfontconfig1-dev libfreetype6-dev \ # rm -rf /var/lib/apt/lists/* # COPY requirements-base.txt /tmp/ # RUN pip3.11 install -r /tmp/requirements-base.txt # # 关键这里不 COPY Agent 代码模板只提供运行时环境这个模板镜像里绝对不包含任何具体的 Agent 代码或配置。它的唯一使命就是提供一个干净、一致、预装好构建工具的 Python 环境。真正的 Agent 代码是通过 WeKnora 的插件机制在运行时动态注入到沙箱内的。这样做的好处是模板镜像可以被所有 Agent 共享极大节省存储和网络带宽升级模板比如换 Python 版本时只需重新 pull 一次镜像所有 Agent 自动受益无需逐个重建。3.2 沙箱网关GatewayAgent 的“统一入口”如果说 Runtime 是 Agent 的“身体”那么 Gateway 就是它的“神经系统”。所有来自 WeKnora 的 Agent 调用请求都必须经过 Gateway。它的配置文件/etc/cubesandbox/gateway.yaml定义了整个系统的流量策略。其中最核心的配置是upstreamsupstreams: - name: weknora-agent-executor # 对应 WeKnora 中 Agent 的唯一标识符 agent_id: meeting-summary-v2 # Gateway 将请求转发到哪个 Runtime 实例 runtime_host: localhost runtime_port: 8080 # 每个 Agent 的独立限流规则 rate_limit: # 每分钟最多 600 次请求即 10 QPS max_requests_per_minute: 600 # 每个用户的独立配额 per_user: true # 熔断规则 circuit_breaker: failure_threshold: 5 timeout_seconds: 30 reset_timeout_seconds: 600这里有个极易混淆的点“agent_id” 是 WeKnora 侧定义的 Agent 名称比如你在 WeKnora UI 里创建 Agent 时填的meeting-summary-v2而runtime_host:port是cubesandboxd监听的地址。Gateway 和 Runtime 默认在同一台机器上所以localhost:8080是合理的。但如果要做高可用你可以部署多个cubesandboxd实例然后在这里配置负载均衡如runtime_host: cubesandbox-cluster背后是 Nginx 或 HAProxy。Gateway 还负责处理 WeKnora 的认证。WeKnora 会为每个 API 请求签发一个 JWT Token其中包含sub用户 ID、aud目标 Agent ID、exp过期时间等字段。Gateway 的验证逻辑在/etc/cubesandbox/jwt.yaml中jwt: # WeKnora 的公钥用于验证 Token 签名 public_key_path: /etc/cubesandbox/weknora.pub # Token 必须包含的 audience 字段必须与 upstreams 中的 agent_id 匹配 required_audience: weknora-agent # Token 的 issuer 字段必须是 WeKnora 的 issuer URL issuer: https://weknora.example.com这个公钥weknora.pub是从 WeKnora 的 OIDC 配置中导出的。这也是为什么热词里有weknora oidc——它不是可选项而是 CubeSandbox 与 WeKnora 安全集成的基石。没有它Gateway 就无法确认请求真的来自 WeKnora也就无法实施基于用户的身份和配额控制。3.3 WeKnora 插件PluginAgent 的“注册中心”WeKnora 本身并不知道 CubeSandbox 的存在。它需要一个“翻译官”这就是weknora-cube-plugin。这是一个独立的 Python 服务它监听 WeKnora 的内部事件总线通常是 Redis Pub/Sub 或 Kafka Topic当 WeKnora 创建、更新或删除一个 Agent 时它会收到通知并据此操作 CubeSandbox。插件的核心配置文件/etc/weknora/cube-plugin.yamlcubesandbox: # Gateway 的地址WeKnora 插件通过它向 Gateway 注册 Agent gateway_url: http://localhost:8000 # Runtime 的地址插件通过它管理沙箱生命周期 runtime_url: http://localhost:8080 weknora: # WeKnora 的内部 API 地址插件需要调用它获取 Agent 详情 api_url: http://localhost:3000/api/v1 # WeKnora 的 JWT 密钥用于签名插件发出的请求 jwt_secret: your-weknora-jwt-secret-here agents: # 列出所有需要由 CubeSandbox 托管的 Agent ID - meeting-summary-v2 - git-sync-prod - web-to-markdown-beta插件的工作流程是这样的WeKnora UI 创建一个新 AgentID 为web-to-markdown-betaWeKnora 内部服务将此事件发布到weknora:agent:createdchannelweknora-cube-plugin订阅该 channel收到事件后立即向 CubeSandbox Gateway 发送一个POST /v1/agents请求携带 Agent 的元数据名称、描述、输入 Schema、输出 SchemaGateway 接收后会生成一个唯一的沙箱配置并调用 Runtime 的POST /v1/sandboxes接口启动一个新沙箱沙箱启动成功后Gateway 返回一个agent_endpoint如http://gateway:8000/execute/meeting-summary-v2插件将此 endpoint 存回 WeKnora 的数据库作为该 Agent 的“执行地址”。这个过程是全自动的。你不需要手动去 CubeSandbox 命令行创建沙箱也不需要在 WeKnora 里填写一堆复杂的 URL。插件就像一个沉默的协调员确保两边的 Agent 清单永远一致。实操心得插件服务必须设置为systemd的WantedBymulti-user.target并且配置Restarton-failure。我们曾因插件进程意外退出导致新创建的 Agent 在 WeKnora 里显示“已启用”但实际上 Gateway 里根本没有注册调用时直接 404。加上自动重启后问题彻底解决。3.4 持久化存储后端Storage BackendAgent 的“记忆仓库”前面提到每个沙箱都有/data目录用于持久化。但/data本身只是一个挂载点它的背后可以是多种存储后端。CubeSandbox 默认使用本地文件系统filesystem但对于生产环境我们强烈推荐s3后端原因有三跨节点一致性如果你未来要水平扩展 CubeSandbox Runtime部署多个cubesandboxd实例本地文件系统无法共享。S3 是天然的分布式对象存储所有 Runtime 实例都能访问同一份/data数据。备份与恢复S3 提供版本控制Versioning和跨区域复制Cross-Region Replication。Agent 的状态数据比如会议纪要的原始音频哈希、知识图谱的同步点一旦损坏可以从 S3 历史版本一键恢复。成本与弹性S3 的存储成本远低于高性能 SSD。你可以把热数据最近 30 天的状态放在STANDARD类型冷数据历史归档自动生命周期转移到GLACIER成本直降 80%。s3后端的配置在/etc/cubesandbox/storage.yaml中backend: s3 s3: # S3 兼容的 endpoint可以是 AWS S3、MinIO 或 Cloudflare R2 endpoint: https://s3.us-east-1.amazonaws.com bucket: weknora-sandbox-data region: us-east-1 # 访问密钥建议使用 IAM Role 或临时凭证而非硬编码 access_key_id: AKIA... secret_access_key: ... # 可选为每个 Agent 的 data 目录加前缀实现逻辑隔离 prefix: sandbox-data/这里有个安全要点access_key_id和secret_access_key绝对不能明文写在这里。正确做法是在宿主机上创建一个专用的 IAM 用户只授予对weknora-sandbox-databucket 的s3:GetObject,s3:PutObject,s3:ListBucket权限将密钥保存在/run/secrets/cubesandbox-s3-creds一个 tmpfs 文件系统重启即清空修改cubesandboxd的 systemd service 文件添加EnvironmentFile/run/secrets/cubesandbox-s3-creds在storage.yaml中用环境变量引用access_key_id: ${AWS_ACCESS_KEY_ID}。这样即使配置文件被意外泄露攻击者也拿不到有效的密钥。这是热词中“agent安全”的一个具体落地实践。4. 实操过程从零开始搭建 WeKnora CubeSandbox 持久化环境现在我们把前面所有的设计和细节变成一条条可执行的命令。以下步骤基于 Ubuntu 22.04 LTSx86_64假设你已经有一个正常运行的 WeKnora 实例v1.2.0并且拥有 root 权限。整个过程分为五个阶段环境准备、CubeSandbox 安装与配置、WeKnora 插件部署、Agent 沙箱创建与测试、以及生产级加固。每一步我都标注了耗时、关键检查点和常见陷阱。4.1 阶段一环境准备耗时约 15 分钟目标为 CubeSandbox 准备一个干净、合规的 Linux 环境。# 1. 更新系统并安装基础依赖 sudo apt update sudo apt upgrade -y sudo apt install -y curl wget gnupg2 software-properties-common ca-certificates # 2. 启用 cgroup v2CubeSandbox 强制要求 # 编辑 GRUB 配置 echo GRUB_CMDLINE_LINUX_DEFAULTsystemd.unified_cgroup_hierarchy1 | sudo tee -a /etc/default/grub sudo update-grub sudo reboot # 重启是必须的cgroup v2 无法热启用 # 3. 重启后验证 cgroup v2 是否生效 mount | grep cgroup # 应该看到类似cgroup on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,nsdelegate) # 如果看到 cgroup on /sys/fs/cgroup type tmpfs则说明仍是 v1需检查 GRUB 配置 # 4. 创建专用用户和目录结构安全最佳实践 sudo useradd -r -s /bin/false cubesandbox sudo mkdir -p /opt/cubesandbox/{bin,config,data,cache,logs} sudo chown -R cubesandbox:cubesandbox /opt/cubesandbox sudo chmod 755 /opt/cubesandbox # 5. 安装 Docker仅用于拉取和管理沙箱模板镜像非运行 Agent curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh sudo usermod -aG docker cubesandbox # 注意不要启动 docker daemonCubeSandbox 不依赖它运行只用它来 pull 镜像提示这一步的reboot是最容易被跳过的。很多用户反馈“安装后 CubeSandbox 启动失败”90% 的原因是 cgroup v2 未启用。务必在重启后执行mount | grep cgroup确认。4.2 阶段二CubeSandbox 安装与配置耗时约 20 分钟目标安装cubesandboxd和cubesandbox-gateway并完成基础配置。# 1. 下载并安装 CubeSandbox 二进制文件以 v0.8.3 为例 cd /tmp curl -L https://github.com/cubesandbox/cubesandbox/releases/download/v0.8.3/cubesandbox-linux-amd64.tar.gz | tar xz sudo cp cubesandboxd cubesandbox-gateway /opt/cubesandbox/bin/ sudo chown cubesandbox:cubesandbox /opt/cubesandbox/bin/* sudo chmod 755 /opt/cubesandbox/bin/* # 2. 创建 systemd service 文件 sudo tee /etc/systemd/system/cubesandboxd.service EOF [Unit] DescriptionCubeSandbox Runtime Daemon Afternetwork.target [Service] Typesimple Usercubesandbox Groupcubesandbox WorkingDirectory/opt/cubesandbox ExecStart/opt/cubesandbox/bin/cubesandboxd --config /etc/cubesandbox/config.yaml Restartalways RestartSec10 LimitNOFILE65536 # 关键设置 cgroup v2 的内存控制器 MemoryAccountingtrue MemoryMax4G [Install] WantedBymulti-user.target EOF sudo tee /etc/systemd/system/cubesandbox-gateway.service EOF [Unit] DescriptionCubeSandbox Gateway Aftercubesandboxd.service [Service] Typesimple Usercubesandbox Groupcubesandbox WorkingDirectory/opt/cubesandbox ExecStart/opt/cubesandbox/bin/cubesandbox-gateway --config /etc/cubesandbox/gateway.yaml Restartalways RestartSec10 [Install] WantedBymulti-user.target EOF # 3. 创建配置目录和默认配置 sudo mkdir -p /etc/cubesandbox sudo chown cubesandbox:cubesandbox /etc/cubesandbox # 生成 config.yaml sudo tee /etc/cubesandbox/config.yaml EOF # CubeSandbox Runtime 配置 log_level: info log_file: /opt/cubesandbox/logs/runtime.log # 监听地址WeKnora 插件和 Gateway 会连接这里 runtime: host: localhost port: 8080 # 沙箱模板默认使用官方镜像 sandbox_template: image: cubesandbox/python311:latest # 拉取策略always 表示每次启动都检查更新production 环境建议改为 if-not-present pull_policy: if-not-present # 资源限制根据你的服务器规格调整 resource_limits: memory_mb: 2048 cpu_shares: 1024 pids_limit: 256 nofile_limit: 1024 # 持久化存储后端 storage: backend: filesystem filesystem: base_path: /opt/cubesandbox/data EOF # 生成 gateway.yaml sudo tee /etc/cubesandbox/gateway.yaml EOF # CubeSandbox Gateway 配置 log_level: info log_file: /opt/cubesandbox/logs/gateway.log # 监听地址WeKnora 会通过这个地址调用 Agent gateway: host: localhost port: 8000 # 上游 Runtime upstream: host: localhost port: 8080 # JWT 验证配置 jwt: public_key_path: /etc/cubesandbox/weknora.pub required_audience: weknora-agent issuer: https://weknora.example.com # 限流和熔断的全局默认值 rate_limit: max_requests_per_minute: 600 per_user: true circuit_breaker: failure_threshold: 5 timeout_seconds: 30 reset_timeout_seconds: 600 EOF # 4. 启动服务 sudo systemctl daemon-reload sudo systemctl enable cubesandboxd cubesandbox-gateway sudo systemctl start cubesandboxd cubesandbox-gateway # 5. 检查服务状态 sudo systemctl status cubesandboxd --no-pager -l sudo systemctl status cubesandbox-gateway --no-pager -l # 应该看到 active (running)且日志中无 ERROR # 测试 Gateway 是否响应 curl -v http://localhost:8000/health # 应该返回 {status:ok,version:0.8.3}注意cubesandboxd的MemoryMax4G是 systemd 的 cgroup 限制它和config.yaml里的memory_mb: 2048是两层控制。前者是整个cubesandboxd进程的内存上限后者是每个沙箱的上限。两者都要设且前者必须大于后者乘以预期并发沙箱数。4.3 阶段三WeKnora 插件部署耗时约 10 分钟目标部署weknora-cube-plugin建立 WeKnora 与 CubeSandbox 的双向通信。# 1. 创建插件运行目录和用户 sudo useradd -r -s /bin/false weknora-cube sudo mkdir -p /opt/weknora-cube/{bin,config,logs} sudo chown -R weknora-cube:weknora-cube /opt/weknora-cube # 2. 下载并安装插件 cd /tmp curl -L https://github.com/weknora/cube-plugin/releases/download/v1.1.0/weknora-cube-plugin-linux-amd64.tar.gz | tar xz sudo cp weknora-cube-plugin /opt/weknora-cube/bin/ sudo chown weknora-cube:weknora-cube /opt/weknora-cube/bin/weknora-cube-plugin sudo chmod 755 /opt/weknora-cube/bin/weknora-cube-plugin # 3. 创建插件配置文件 sudo tee /etc/weknora/cube-plugin.yaml EOF cubesandbox: gateway_url: http://localhost:8000 runtime_url: http://localhost:8080 weknora: api_url: http://localhost:3000/api/v1 # 这个 JWT secret 必须和 WeKnora 的配置完全一致 jwt_secret: your-weknora-jwt-secret-here agents: - meeting-summary-v2 - git-sync-prod EOF # 4. 创建 systemd service sudo tee /etc/systemd/system/weknora-cube-plugin.service EOF [Unit] DescriptionWeKnora Cube Plugin Aftercubesandbox-gateway.service [Service] Typesimple Userweknora-cube Groupweknora-cube WorkingDirectory/opt/weknora-cube ExecStart/opt/weknora-cube/bin/weknora-cube-plugin --config /etc/weknora/cube-plugin.yaml Restarton-failure RestartSec5 EnvironmentFile/etc/weknora/cube-plugin.env [Install] WantedBymulti-user.target