一、架构总览
下面是简化后的 Agent 与沙箱架构图。
整体流程是这样的:
- Agent(也就是我)在云端的 Anthropic 服务器上思考,决定要执行某个操作,比如跑一段代码或创建文件。
- 这个请求作为"命令"发到沙箱,由 PID 1 的
process_api接收。 process_api拉起短暂的命令进程(sh、python、node等),这些进程读写沙箱里的工作区和输出目录。- 命令的输出再作为"结果"返回给我,我据此决定下一步。
- 需要交给你的文件放在输出目录,由
rclone同步到外部文件存储,你在聊天里点文件卡片下载的就是它。
和前面查到的信息对应起来:沙箱是 Firecracker 微虚拟机,规格是 1 核、4 GB,网络关闭,所以沙箱不能主动联网;telemetry是遥测收集进程,和命令流程相互独立。
这张图是根据沙箱内能观察到的进程和挂载推断出来的简化版。云端和沙箱之间具体用什么协议通信、请求怎么路由,从沙箱内部看不到,所以图里只画了"命令"和"结果"两个方向,没有展开细节。
本执行环境为三层结构,自外向内依次为宿主机内核、容器实例、会话工作区:
┌──────────────────────────────────────────────────┐ │ 第一层:宿主机内核(多任务共享) │ │ Linux 5.15.0-151-generic x86_64 │ │ 已持续运行 41.6 天 │ └──────────────────────┬───────────────────────────┘ │ 命名空间隔离 + cgroup 配额 ┌──────────────────────▼───────────────────────────┐ │ 第二层:容器实例(本会话) │ │ Ubuntu 24.04.5 LTS (Noble) │ │ 运行时长约 40 分钟 —— 按需创建、用完即弃 │ │ ┌────────────────────────────────────────────┐ │ │ │ 进程拓扑:5 个常驻进程 │ │ │ │ 初始化 → 服务组 → 保活链 │ │ │ └────────────────────────────────────────────┘ │ └──────────────────────┬───────────────────────────┘ │ 独立挂载 ┌──────────────────────▼───────────────────────────┐ │ 第三层:会话工作区(独立网络存储) │ │ /app/workspace/<会话ID> │ │ 用户产物落盘位置,与容器根分区物理分离 │ └──────────────────────────────────────────────────┘分层意义:
- 第一层与第二层解耦——容器可随时重建,不影响宿主机;
- 第二层与第三层解耦——容器销毁后工作区数据仍可保留,这是产物不随环境消失的原因;
- 共享与隔离并存——内核与部分资源(CPU、内存、磁盘)为多任务共享,但进程视图、网络栈、文件系统视图各自隔离。
二、进程拓扑
稳定态共5 个常驻进程,构成清晰的树形结构:
PID 1 sandboxTemplate 容器初始化进程(Ss,1 线程) ├── PID 8 caddy Web 服务进程(Sl,9 线程,43 MB) ├── PID 9 agent 任务代理进程(Sl,5 线程,14 MB) │ └── PID N bash 任务执行 Shell —— 按需派生,结束即回收 └── PID 10 tini 轻量 init(S,1 线程) └── PID 12 sleep infinity 保活进程(S,1 线程)| PID | 进程 | 角色 | 状态 | 线程 | 内存 |
|---|---|---|---|---|---|
| 1 | sandboxTemplate | 容器初始化,拉起整个环境 | Ss 睡眠 | 1 | 2.6 MB |
| 8 | caddy | 提供本地 HTTP 服务能力 | Sl 睡眠 | 9 | 43.2 MB |
| 9 | agent | 任务派发入口 | Sl 睡眠 | 5 | 13.9 MB |
| 10 | tini | 孤儿进程回收,防僵尸堆积 | S 睡眠 | 1 | 0.66 MB |
| 12 | sleep infinity | 维持容器存活 | S 睡眠 | 1 | 0.60 MB |
结构特征:
- 三层职责分离——初始化进程只管拉起;服务进程组提供能力;任务子进程按需派生、用完即回收;
- 无长期驻留的任务进程——所有任务执行都通过
agent派生的临时子进程完成,任务结束即消失,因此进程列表始终保持精简; - 独立兜底分支——
tini单独挂载,负责回收孤儿进程,这是环境零僵尸进程的机制保障。
资源占用:常驻进程内存合计60.9 MB,占容器内存上限约 1.5%;CPU 累计消耗约 1 秒。
三、资源配额(cgroup 限制)
容器的真实资源边界由 cgroup 定义,而非free/loadavg的输出:
| 资源 | cgroup 配额 | 实测占用 | 占用率 |
|---|---|---|---|
| CPU | 2 vCPU(cpu.max = 200000/100000) | 采样约 31%(节点视角) | 宽松 |
| 内存 | 4 GiB(memory.max = 4294967296) | 60.9 MB(进程 RSS) | 约 1.5% |
| 交换分区 | 未配置(0 MB) | — | — |
重要辨析:进程 RSS 与实际内存占用之间存在明显落差,差额主要是文件页缓存:
| 口径 | 数值 | 含义 |
|---|---|---|
| 常驻进程 RSS 合计 | 60.9 MB | 5 个进程实际占用的物理内存 |
cgroupmemory.current | 1.03 GiB | 容器内存实际用量(含页缓存) |
系统视图freeused | ~1.3 GB | 含可回收的缓存部分 |
页缓存属于可回收内存,内存紧张时会被内核自动释放,不构成真实压力。判断容器内存水位应以 cgroup 配额(4 GiB)为准。同理,loadavg与 CPU 压力指标反映的是共享节点的整体负载——容器内仅有 5 个空闲进程,无法产生该量级的负载。
无 Swap 的含义:内存充裕时无影响;内存突增时缺少缓冲,进程可能被直接终止。这是处理超大文件时建议分块读取的原因。
四、存储布局
| 挂载点 | 文件系统类型 | 容量 | 使用率 | 用途 |
|---|---|---|---|---|
/ | overlay | 99 GB | 76%(71 GB 已用) | 系统层:OS、运行时、依赖库 |
/app/workspace/<会话ID> | 网络存储(nfs4) | 容量充裕 | 1% | 会话工作区:用户产物落盘 |
/tmp | overlay | 同根分区 | — | 临时文件 |
关键特征:
- 系统层与数据层物理分离——用户产物存放在独立的网络存储上,不占用根分区;容器重建后工作区数据仍在;
- 根分区 76% 的成因——该数字来自底层共享磁盘的整体水位,包含其他任务环境与共享镜像层的数据。容器内可见文件仅约 10.6 GiB,且全部为预装运行时(LaTeX 3.2 GB、Python 库 2.5 GB、系统库 1.4 GB、Chromium 658 MB、.NET 624 MB 等),与用户使用量无关;
- inode 使用率 19%——远未耗尽,无小文件堆积风险;
- 写权限正常——根分区与工作区写入测试均通过。
目录约定:
<工作区>/ ├── outputs/ 最终产物(交付文件) ├── scripts/ 脚本文件 └── runs/ 运行中间数据五、网络边界
| 项目 | 实测结果 |
|---|---|
| 出站连通性 | ✅ 正常(HTTP 200,响应 47–85 ms,存在正常波动) |
| DNS 解析 | ✅ 正常 |
| 入站监听端口 | 0 个(/proc/net/tcp无监听条目) |
| TCP 连接状态 | inuse 4,TIME_WAIT 69,orphan 0 |
| UDP | inuse 0 |
边界特征:
- 出站开放、入站封闭——环境可主动访问外网(检索、下载、调用接口),但没有对外暴露任何监听端口,不存在入站攻击面;
- TIME_WAIT 69 个属正常连接回收状态,不是异常堆积。
六、安全机制
本环境采用四层防护:
| 层级 | 机制 | 实测状态 |
|---|---|---|
| 1. 系统调用层 | Seccomp 过滤 | 模式 2(白名单过滤),5/5 进程全部启用 |
| 2. 进程隔离层 | 独立权限域 | 跨域/proc读取被内核拒绝(含exe/cwd/maps/environ) |
| 3. 命名空间层 | 进程 / 网络 / 文件系统视图隔离 | 独立网络栈,无入站监听 |
| 4. 资源层 | cgroup 配额 + OOM 评分 | CPU 2 vCPU / 内存 4 GiB;oom_score_adj统一 78 |
逐项说明:
- Seccomp 模式 2表示系统调用被白名单机制限制,进程只能使用被显式允许的调用——这是最内层的内核级防护;
- 进程隔离的实际体现:即使容器内 uid 为 0,读取其他进程的
/proc/<pid>/exe、maps、environ仍返回Permission denied。权限是分域的,uid 0 不等于全局特权; oom_score_adj = 78为平台统一配置(取值 -1000~1000,越高越优先被内存回收),属于资源调度策略,含义是本环境在节点内存紧张时会被优先回收,不构成运行风险。
七、权限模型
| 维度 | 实测值 |
|---|---|
| 容器内身份 | uid=0(root) gid=0(root) |
| 权限范围 | 仅限本容器命名空间 |
| 跨域访问 | ❌ 被内核拒绝 |
| 文件描述符上限 | 1,048,576(占用率 0.004%) |
| 进程句柄总数 | 39 |
核心结论:容器内拥有root 身份,但该 root 被三重边界约束——
- 命名空间边界:看不到也碰不到其他容器;
- Seccomp 边界:系统调用受限;
- cgroup 边界:资源用量受限。
即:容器内是 root,出了容器什么都不是。这是沙箱环境的常规设计。
八、生命周期
按需创建 ──▶ 初始化(拉起 5 个常驻进程)──▶ 执行任务(派生临时子进程) │ │ └──────────── 会话结束 ──▶ 容器回收 ◀────────────────┘ │ └── 工作区数据保留(独立存储)| 阶段 | 特征 |
|---|---|
| 创建 | 按需创建,非长期驻留;当前实例运行约 40 分钟 |
| 初始化 | sandboxTemplate拉起服务进程组与保活链 |
| 执行 | 任务通过agent派生子进程完成,结束即回收,不累积 |
| 回收 | 会话结束后容器销毁;工作区产物因独立存储而保留 |
与宿主机的时长差异:容器 PID 1 运行约 40 分钟,而宿主内核已运行 41.6 天——每次任务会话获得一个干净的新环境,这是沙箱设计的核心特征,也是产物必须落在工作区(而非容器内)的原因。
九、可复现的检查命令
本文档全部数据可由以下命令复现:
# 容器与进程ps-eopid,ppid,stat,%cpu,%mem,rss,etime,comm--sort=pidps-e-opid,ppid,comm--forest# 资源配额cat/sys/fs/cgroup/cpu.max# CPU 配额cat/sys/fs/cgroup/memory.max# 内存上限free-m# 节点级内存视图# 存储df-hT# 各挂载点使用率df-i# inode 使用率du-x-h-d1/# 容器内可见文件总量# 网络cat/proc/net/tcp# TCP 连接与监听cat/proc/net/sockstat# socket 统计# 安全与权限id# 当前身份grep-E"^(Name|Threads|VmRSS|Seccomp)"/proc/<pid>/statuscat/proc/<pid>/oom_score_adj# 生命周期ps-oetime=-p1# 容器运行时长cat/proc/uptime# 宿主内核 uptime十、架构要点小结
| 维度 | 核心特征 |
|---|---|
| 层级 | 三层解耦:宿主机内核 / 容器实例 / 独立工作区 |
| 进程 | 5 个常驻进程,三层职责分离,任务进程按需派生即回收 |
| 资源 | 2 vCPU / 4 GiB,实际占用约 1.5%,余量充足 |
| 存储 | 系统层与数据层物理分离,产物存独立网络存储 |
| 网络 | 出站开放、入站封闭,无暴露面 |
| 安全 | 四层防护:Seccomp + 进程隔离 + 命名空间 + cgroup |
| 权限 | 容器内 root,受三重边界约束 |
| 生命周期 | 按需创建、用完即弃;数据独立保留 |
十一、数据核验记录
核验时间:2026-10-15 08:15 (CST)
核验方式:重新实测 + 多路径交叉验证(同一事实用两种独立方法测量)
| 核验项 | 方法一 | 方法二 | 结论 |
|---|---|---|---|
| 进程数量 | ps -e计数 | /proc目录扫描 | ✅ 一致 |
| 进程内存 | ps的 RSS 列 | 直读/proc/<pid>/status的 VmRSS | ✅ 一致 |
| 容器内存 | cgroupmemory.current | 进程 RSS 求和 | ✅ 差额为页缓存,合理 |
| 磁盘用量 | df | du -x逐目录汇总 | ✅ 一致 |
| 安全机制 | /proc/<pid>/status的 Seccomp | oom_score_adj直读 | ✅ 一致 |
| 网络监听 | /proc/net/tcp状态位 | socket 统计 | ✅ 一致 |
本次修订明细
| 项目 | 原值 | 修正值 | 原因 |
|---|---|---|---|
| caddy 内存 | 44.2 MB | 43.2 MB | 单位换算错误 |
| agent 内存 | 14.4 MB | 13.9 MB | 单位换算错误 |
| sandboxTemplate 内存 | 2.7 MB | 2.6 MB | 单位换算错误 |
| tini 内存 | 0.68 MB | 0.66 MB | 单位换算错误 |
| sleep 内存 | 0.61 MB | 0.60 MB | 单位换算错误 |
| 进程内存合计 | 62 MB | 60.9 MB | 单位换算错误 |
| 内存口径说明 | 节点级 / 容器级二分 | 补充页缓存口径 | 表述更严谨 |
| 网络响应时间 | 47 ms | 47–85 ms | 实测存在波动 |
单位换算说明:ps输出的 RSS 单位为KiB,换算为 MB 应除以1024(而非 1000)。原文档按 ÷1000 换算,导致全部内存数值系统性偏大。