本文通过“多个沙箱共用基础环境和工具包”的例子,浅谈 DSec 的 Composable Environment Layers(可组合环境层)。

为便于理解,下面以容器沙箱为例,主要讨论环境文件的存储、准备和更新,不展开镜像分发与运行内存优化。

What

先把最容易混淆的一点说清楚:

1
2
3
每个沙箱看到一套完整的环境
≠
每个沙箱都要完整复制一套环境文件

DSec 将环境拆成三个可以独立维护版本的部分:

1
2
3
4
5
Base Image(基础镜像):操作系统和基础运行依赖

Workspace(工作区):任务代码仓库和专用依赖

Toolkit(工具包):任务使用的工具,例如 DeepSeek Harness

创建沙箱时,再选择需要的层,将它们组合起来,并加入沙箱自己的可写上层。

可以简单理解为:

公共内容可以复用,各自的运行时改动单独保存。

Why

这套设计不只是为了方便升级,还希望减少重复存储和重复准备。

1. 节省存储空间

多个沙箱需要同一份基础环境或工具包时,可以引用同一个只读层,而不是分别保存完整副本。OverlayFS 允许多个挂载共享下层目录,为这种复用提供了基础。

此外,EROFS 支持压缩,可以进一步减少只读文件的存储占用。

两者解决的是不同的问题:

1
2
3
共享层:相同内容,不必保存多份

压缩:需要保存的内容,可以放得更紧凑

2. 减少启动时的重复解包

论文对比的一种做法是:把工作区和工具包打成压缩包,在每个沙箱中分别解压。

DSec 则将它们作为 EROFS 层直接挂载使用,避免每个沙箱都先解出一整套文件,减少重复解压和写盘的工作。

1
2
3
4
5
逐个解包:
同一个工具包 → 在每个沙箱里分别展开一份

共享挂载:
同一个只读工具层 → 多个沙箱直接使用

3. 只更新发生变化的部分

工具包从 Tool-v1 升级到 Tool-v2 时,单独发布新的工具层即可。

之后创建沙箱时选择新版本,不需要为了更新工具包,把没有变化的基础镜像和工作区也重新构建一遍。

基础 Example

假设两个沙箱使用不同的工作区,但共享同一份基础环境和工具包。

下面的大小仅用于说明复用原理,不是论文测试数据;暂不计算压缩、元数据和运行时改动。

1
2
3
4
Base:          4 GiB
Tool: 1 GiB
Workspace-A: 1 GiB
Workspace-B: 1 GiB

每套环境都完整保存

假设没有共享或去重,而是分别保存两套完整文件:

1
2
3
4
5
环境 A:Base + Workspace-A + Tool = 6 GiB

环境 B:Base + Workspace-B + Tool = 6 GiB

合计:12 GiB

这里,Base 和 Tool 都保存了两份。

复用相同的只读层

只保存一份 Base 和一份 Tool,两个工作区仍然各自保存:

1
2
3
4
5
6
7
实际保存:
Base 4 GiB
Tool 1 GiB
Workspace-A 1 GiB
Workspace-B 1 GiB

合计:7 GiB

两个沙箱分别引用自己需要的组合:

1
2
3
4
沙箱 A:Base + Workspace-A + Tool
沙箱 B:Base + Workspace-B + Tool
↑ ↑
引用同一份 引用同一份

这样,示例中的存储占用从 12 GiB 变成了 7 GiB。

省掉的是第二份基础环境和工具包,不是把两个不同的工作区变成了同一份。

这里对比的是“每套都完整保存”的做法。原系统如果已经共享相同层,就不能再按这个例子重复计算收益。

How

结合前面介绍的 EROFS 和 OverlayFS,只看三个动作。

1. 用 EROFS 保存可直接使用的只读层

DSec 将发布后不再修改的环境层保存在 EROFS 中。[1]

EROFS 不只是把文件压小,还允许挂载后按需读取。启用压缩时,读取相关数据块并解压即可,不必先把整个镜像全部展开到另一个目录。

1
2
3
4
5
压缩包部署:
压缩包 → 完整解包到目录 → 应用使用

EROFS:
只读镜像 → 挂载 → 应用按需读取

因此,共享的是可以直接使用的只读层,而不只是一个仍需逐个解包的压缩包。

2. 用 OverlayFS 组合文件视图

DSec 在创建容器沙箱时,动态组装 OverlayFS 的层次:

1
2
3
4
5
6
7
上层
沙箱自己的可写层
------------------
Toolkit 只读
Workspace 只读
Base Image 只读
下层

应用看到一棵合并后的目录树,但文件仍然可以来自不同的层。

组合的是访问视图,不是把所有文件重新复制一遍,生成一个完整的新镜像。

3. 运行时的修改,保存到自己的上层

例如,沙箱 A 要修改下层工作区中的 main.py。

按照 OverlayFS 的 copy-up 机制,需要修改的下层文件会先复制到 A 的可写上层,再对这个副本进行修改。共享的只读层保持不变。

1
2
3
4
5
6
7
8
共享只读层中的 main.py
│
│ copy-up
▼
沙箱 A 的可写层中的 main.py
│
▼
保存 A 修改后的版本

所以,共享基础内容不妨碍沙箱修改文件。

但可写上层仍然占空间:它保存新增文件和修改后的文件副本,不是只保存被改动的几个字节。

记忆图

1
2
3
4
5
6
7
8
9
10
11
12
13
准备环境:
Base、Workspace、Toolkit 分别发布

创建沙箱:
选择需要的只读层
↓
OverlayFS 组合 + 加入自己的可写层
↓
应用看到完整环境

运行过程中:
未修改的文件继续使用下层
各自的修改保存在各自的上层

这对应着三个收益:

1
2
3
4
5
省空间:公共内容复用,EROFS 可压缩,不逐个完整解包

省准备:直接挂载使用,减少重复解压和写盘

省维护:哪一层变化,就单独更新哪一层

一句话概括:

不为每个沙箱重新保存、解包和构建一整套环境,而是复用只读内容,按需组合,把各自的改动留在自己的上层。


参考资料:

  1. DeepSeek Elastic Compute (DSec): A Sandbox Infrastructure for Effective Agentic Training at Scale — §4.2、§5.1、§8.3
  2. EROFS: A Compression-friendly Readonly File System for Resource-scarce Devices — USENIX ATC 2019
  3. Linux Kernel Documentation: Overlay Filesystem
  4. Linux Kernel Documentation: EROFS