Docker 沙盒与容器:关键区别
容器共享宿主内核。Docker Sandbox 是自带独立内核的 microVM,为需要一整台机器、又不能放任它碰你机器的编程 agent 而设计。
中文
复制

用了几年 Docker 的人看到“Docker Sandboxes”,大概会理解成“里面跑着 AI agent 的容器”。十多年来,容器几乎就是 Docker 一切产品的交付单位,sandbox 听起来无非是打包工作负载的又一种方式。
实际上这是两种不同的技术。容器是一个隔离的进程,与机器上其他所有东西共用宿主内核。Docker Sandboxes 则是自带 Linux 内核的专用 microVM,拥有独立的文件系统、网络和 Docker Engine,专为需要一整台开发机来干活的自主编程 agent 打造。sandbox 里可以运行容器,这也是两者容易被混为一谈的原因之一。
在 WeAreDevelopers 的主题演讲中,Docker 总裁 Mark Cavage 说,容器做的正是它们当初被设计来做的事,只是我们现在要求它们去做另一件事。
容器生来是为了隔离应用,这一点它们至今做得很好。但编程 agent 是一个行动者。它自己做决定,像开发者用笔记本电脑那样操作你的系统。它克隆仓库、安装软件包、启动数据库、构建镜像,一干就是几个小时,失败了再重试。它还可能按照没人审阅过的文件、网页和工具输出里的指令行事。
这件不同的事需要一条不同的边界,而边界划在哪里,决定了 agent 的一次失误能波及多远。本文讲 Docker Sandboxes 和容器各自如何隔离工作负载、内核之外还有哪些不同、用 sandbox 在搭建上要付出什么代价,以及该怎么选。
要点
- 容器是共享宿主内核的隔离进程。Docker Sandboxes 是自带内核、文件系统、网络和 Docker Engine 的 microVM。
- 打包好的应用、CI 任务和短时执行,仍然应该用容器。
- Docker Sandboxes 适合需要 sudo、独立 Docker Engine、长期保留的状态,以及由宿主机强制实施的网络与凭据管控的自主 agent。
- 容器可以是约束 agent 的一环,sandbox 里也可以运行容器。把 agent 放进 sandbox,把它所操作的应用装进容器。
什么是容器?
容器是运行在宿主机上的一个进程或一组进程,拥有自己独立的文件系统、进程树和网络视图。Linux namespace 提供这套视图,cgroup 则负责计量 CPU、内存和 I/O。机器上的每个容器还共用宿主机内核,这正是容器启动快、部署密度高、开销极低的原因。

这套设计背后有十多年的工具生态支撑。Compose、Kubernetes、OCI registry、镜像扫描器以及几乎所有 CI 系统都把容器当作通用的基础单元。无论是运行服务、执行一段代码、处理单个请求,还是跑一次评测后即销毁,容器通常都是显而易见的选择,而且这一局面不会改变。
ⓘ 容器共用一个内核,即使在虚拟机里也是如此。在 macOS 和 Windows 上,Docker Desktop 把你的 Linux 容器运行在一个虚拟机内,从而让它们与宿主机操作系统隔开。但该虚拟机里的每个容器仍然共用这一个内核,因此容器之间的隔离程度并没有变化。
什么是 Docker Sandboxes?
Docker Sandboxes 把 AI 编程 agent 运行在一个拥有独立 Linux 内核的 microVM 中,该 microVM 有自己的文件系统和网络栈,以及一个私有的 Docker Engine。agent 在这个隔离环境内拥有 sudo 权限,可以安装软件包、运行服务、构建镜像、拉起一整套 Compose 应用,而不会触及宿主机的 Docker daemon、工作区之外的宿主机文件系统,也不会影响同一台机器上的其他 sandbox。

用 Docker Sandboxes 的命令行工具 sbx,一条命令即可启动。
sbx run claude
这样就创建了沙箱并启动了 agent。你可以停止它、恢复它,之后还能回到 agent 安装过的一切,直到你删除沙箱。
编程 agent 为什么需要一台完整的机器?
编程 agent 需要一台完整的机器,因为它们的会话会在数小时内不断累积状态,而且它们会依据未经审查的指令行事。容器是为依赖集合已知的单个进程构建的,而 agent 的工作不符合这种形态。
agent 需要一整台机器的权限,以及为整台机器设计的边界。让 agent 有用的那些能力,比如运行代码、安装软件包、访问网络,也正是不断侵蚀其周围边界的那些能力。agent 会试探环境的边缘,因为这份工作本身就要求它去改变环境。
agent 会持续数小时累积状态
编程 agent 的会话就像开发者的一个下午。克隆仓库、安装软件包、启动 PostgreSQL、运行迁移、构建镜像、用 Compose 启动应用、读日志、改代码、再试一次。这个循环可能持续数小时,每一步都依赖上一步留下的结果。
容器的设计前提是从镜像和几个显式卷重建。agent 在这些卷之外创建的软件包、数据库和构建产物,会在容器重建时丢失。对于一个每一步都建立在前一步之上的会话来说,这并不理想。
Box by ASCII把这个区别讲得很清楚:“它使用沙箱的方式,就像开发者使用笔记本电脑一样,所以沙箱必须表现得像一台笔记本电脑。”
agent 会依据不可信的指令行事
决定运行哪条命令的程序是概率性的,而且它能同时从许多地方读取指令,包括源文件、issue 描述、网页、软件包元数据以及 MCP 工具的输出。其中有些输入是不可信的,埋在 README 或工具描述里的恶意指令可以有意地操纵 agent。它生成的代码也可能有错,甚至带有敌意。
我们已经见过一个 agent 在误读任务之后删掉了生产数据库。一旦 agent 以 YOLO 模式无人值守地运行,就没有任何权限提示能拦住它了。一个权限这么大、可预测性这么低的工作负载,需要一道为它量身设计的边界。
把这些事实放在一起,就能明白我们为什么做 Docker Sandboxes。自主编程 agent 需要的是机器形态的能力,同时不能碰开发者机器上的所有东西,归结起来是四件事。
- 隔绝(Containment),也就是一道模型改不掉的边界
- 控制(Control),能观察 agent 在做什么,也能把它停下来
- 选择(Choice),可以自由更换 agent、模型和工具,不必重建整套环境
- 容量(Capacity),其他开发者能复现这套环境,并扩展到单机之外
接下来的几节逐一说明这四点各自是什么样子,先从隔离讲起。
容器与 Docker Sandboxes 的隔绝差异
简短地说,容器的边界是它与宿主机共享的内核,而 Docker Sandboxes 在 agent 独占的内核外面加了一层 hypervisor 边界。这一处差别决定了入侵一旦发生能走多远,也顺带解决了那个棘手的问题,也就是 agent 要怎么才能访问 Docker。
容器和隔离的分野就在这里。容器可以是隔离的一部分,而且往往也应该是一部分,但隔离覆盖的是 agent 周围的整个环境。它始于一道模型改不掉的边界,所以 Docker 为自主 agent 选用带独立内核的 microVM。
共享内核 vs. 专用内核
容器的边界由它共享的内核来强制执行,想逃出去就得靠内核漏洞利用或侧信道攻击。这些都不是随手就能找到的东西。但越过这道门槛之后,等着你的是整个宿主机内核、机器上的其他所有进程,以及与它们挂载在一起的任何凭据。
ⓘ 这一情形只适用于 Linux 环境。在 Docker Desktop(macOS 和 Windows)上,共享的内核是 Docker Desktop 虚拟机的内核,而不是宿主机内核,因此逃逸会落在那个虚拟机里,而不是操作系统里。
Docker Sandboxes 让 agent 拥有自己的内核,与宿主机之间隔着一道 hypervisor 边界。agent 即使逃出了容器,也只会落进一个用完即弃的 microVM,碰不到宿主机。而且你可以删掉沙箱再开一个。每个 agent 还各自拥有独立的 microVM,所以同一台机器上运行的两个 agent 也互相够不到对方的沙箱。不过,你选择共享给 agent 的东西它仍然能访问,包括工作区、允许的网络目标、MCP server 和 skill。
Docker socket 的问题
把 /var/run/docker.sock 挂载进容器是让容器获得 Docker 访问权限的老办法,Compose 配置、CI 流水线和可观测性工具里都能见到。代价是把宿主 Docker daemon 的控制权交给了容器,Docker 只把这项权限开放给受信任的用户,因为拿到它就能挂载宿主路径、启动特权容器。
agent 利用这一点不需要什么漏洞。把它放进一个挂载了 socket 的容器,它会探测周围环境,判断出自己在容器里,然后找到配置上的这个口子。在 Mark 的主题演讲演示中,仅凭这一点,agent 就读到了宿主机上的一个密钥文件,全程没有用到任何 zero-day。
socket 只是若干口子之一,而 agent 之所以能找到它们,是因为探测环境本来就是它工作的一部分。Docker-in-Docker、挂载的凭据、范围过宽的宿主挂载都是别的口子。容器是为隔离按配置行事的应用而设计的。但 agent 会不断试探这份配置,只要有缺口,它多半就能找到。
microVM 边界划在哪里
Docker Sandboxes 把缺失的那道边界放在了正确的位置。agent 与 guest 内部的私有 Docker Engine 通信,可以构建镜像、运行 Testcontainers、启动整套 Compose stack,而宿主 daemon 及其 socket 始终在 microVM 之外。容器继续做它最擅长的事,只是被关在 agent 无法拓宽的边界之内。
假设你让 Docker Sandboxes 里的 agent 去宿主机上找一个密钥文件。它会找到一个 Docker socket,试图用它挂载宿主路径、启动特权容器,但到不了宿主机。microVM 能提供的信任边界比容器强得多。Docker Sandboxes 背后的架构更详细地解释了为什么 microVM 才是适合这件事的形态。
内核之外的控制
隔绝划定边界。控制 则决定边界之内你能看到什么、能拦住什么,也就是 agent 被允许访问哪些东西,以及当它跑向不该去的地方时,你能不能挡住它。在沙箱里,这些控制由宿主机强制执行,agent 够不着,所以它既关不掉,也没法绕过去。出站流量、凭据、组织级策略都是这么运作的。控制还意味着清楚 agent 仍然能碰到什么,你选择与它共享的东西,microVM 藏不住。
| 标准容器中的 agent | Docker Sandboxes 中的 agent | |
|---|---|---|
| 内核 | 共享宿主机内核 | 在 microVM 中运行自己的 Linux 内核 |
| Docker | 需要宿主机 socket 或嵌套 daemon | 使用 microVM 内部的私有 Docker Engine |
| 工作区 | 能看到你挂载的宿主机路径 | 使用直接读写挂载,或 VM 内的私有克隆 |
| 网络 | 使用容器网络,以及其运维方提供的控制手段 | 出站流量经宿主机代理,默认拒绝策略 |
| 凭据 | 通常以环境变量、文件或挂载 socket 的形式注入 | 对支持的 HTTP 服务,由宿主机侧注入凭据 |
| 状态 | 通常从镜像和显式卷重建 | 包、镜像、容器和 agent 历史一直保留,直到 sbx rm |
| 编排 | 适配 Compose、Kubernetes 和大多数 CI 系统 | 使用 sbx 生命周期和实验性的环境文件 |
控制由宿主机强制执行
这些控制之所以成立,是因为它们运行在 agent 进程之外。agent 够得着的规则,它就能绕过,所以真正要紧的规则都放在宿主机上。出站流量经过宿主机侧代理,策略默认拒绝,agent 想去的目的地会一直处于封禁状态,直到有人把它加进列表。凭据也是同样的道理。对于支持的 HTTP 服务,代理会把凭据注入出站请求,agent 因此能用上凭据,而原始值从不进入 VM。
当一名开发者的配置需要成为团队标准时,Docker AI Governance 可以把网络、文件系统和 MCP 策略迁移为组织级管控。
agent 仍能触达什么
microVM 无法隐藏你主动共享给它的内容,因此共享的部分最值得关注。
工作区是其中最大的一块。它默认以读写方式挂载,所以 agent 可以编辑或删除项目中的文件。克隆模式让 agent 在 VM 内的一份私有克隆中工作,从而保护宿主工作树,不过原始仓库在沙箱内仍然可读。
MCP 服务器和技能同样是共享的。本地 stdio MCP 服务器运行在宿主机上,共享的 agent 技能使用宿主侧的存储,因此 agent 的触达范围也延伸到这两者。
所以无论选择哪种模式,运行被修改过的代码之前,务必先读一遍 diff。
选择与容量,Docker Sandboxes 的配置代价
Docker Sandboxes 可能需要一些配置工作,还需要一个受支持的 hypervisor。不过 Kits 和环境文件承担了配置部分,它们也正是你获得对 agent 和工具的选择权、以及在团队中复现同一套配置的能力的地方。
Kits 与环境文件
Kits把工具、文件、命令、网络规则、凭据和 agent 指令打包在一起,让配置可以重复。它们针对不同的 agent、工具和 IDE 分别发布,因此你可以更换沙箱内运行的内容,而不必围绕它重建环境。sbxenv.yaml 文件记录单个项目的沙箱配置,把它提交到仓库后,队友用一条命令就能重建同样的沙箱,每位开发者都从同一套配置开始工作。(Kits 处于早期访问阶段,环境文件属于实验性功能,两者都请预留变更的余地。)
宿主侧强制执行的管控也需要一些配置。网络策略需要有人决定哪些目标属于工作流的一部分,凭据中介需要添加服务绑定和已批准的域名,克隆模式则在改动落到宿主仓库之前增加一步 fetch。
Hypervisor 与资源要求
运行沙箱比运行容器对机器的要求更高。它需要受支持的 hypervisor,目前这意味着搭载 Apple silicon 的 macOS 14 或更高版本、Windows Hypervisor Platform,或受支持的 Ubuntu 系统上的 KVM;在另一个虚拟机里运行还需要嵌套虚拟化。独立的内核和 Docker Engine 也比多跑一个容器占用更多内存和磁盘。
如果瓶颈在你的机器上,Docker Cloud Sandboxes 在 Docker 托管算力上提供同样的 microVM 隔离,一条命令就能在笔记本和云之间迁移沙箱。本地沙箱和云沙箱各自维护独立的密钥和网络策略。
容器和 Docker Sandboxes 之间怎么选?
代码及其依赖由你掌控时选容器;工作负载在运行时生成或拉取代码、需要自己的边界时选 Docker Sandboxes。
| 选容器的情形 | 选 Docker Sandboxes 的情形 |
|---|---|
| 代码及其依赖由你掌控 | 工作负载在运行时生成或拉取代码 |
| 执行时间短,从镜像重建 | 会话持续数小时、不断累积状态 |
| 工作负载不需要 Docker,或运行在已提供 Docker 的 CI 中 | 工作负载需要自己的 Docker Engine,且不能访问宿主机 socket |
| 追求最高密度,并与 Compose 或 Kubernetes 契合 | 需要宿主机强制执行的网络和凭据策略,工作负载无法关闭 |
| 对所运行的代码来说,内核边界已经够用 | 希望在工作负载和内核之间隔一层 hypervisor |
如果下面任何一条符合你的项目,就应该从 Docker Sandboxes 开始。
- agent 无人值守运行,或其权限提示被自动批准
- agent 需要构建镜像,或运行 Compose、Testcontainers
- agent 读取的不是你写的输入,比如 issue、网页、包元数据或 MCP 输出
- agent 需要 API key,而你不希望它出现在其环境中
- 会话持续时间超过单个任务
先从 sbx run claude 开始。随着工作流逐步扩展,再依次加入 clone 模式、kit、网络策略、凭据中介和组织治理。
把 agent 关进沙箱,把应用装进容器
容器的地位不会动摇。服务、CI 任务,以及任何打包交付的东西,容器划出的边界都恰到好处,围绕它形成的生态也正是这项职责始终由它承担的原因。但要让编程 agent 承担真正的工作,光有一个容器还不够。它需要的是隔绝,一道模型改不掉的边界、一些它绕不过去的管控,同时又能自由选择工具、按需扩展环境。
Docker Sandboxes 在 microVM 里提供这种隔离,同时照样能跑你的容器。有了这道边界,agent 反而能跑得更快。不必逐条批准命令,放手让它干活。
一条命令就能起一个沙箱。从 sbx run claude 和 Docker Sandboxes 快速入门开始。当某个开发者的配置需要变成团队标准时,Docker AI Governance 可以把同一套管控扩展到整个组织。
常见问题
Docker Sandboxes 不就是容器吗?
不是。容器是共享宿主机内核的隔离进程。Docker Sandboxes 是 microVM,有自己的内核、文件系统、网络和 Docker Engine。沙箱里可以跑容器,所以两者很容易混淆。
能在 Docker Sandboxes 里运行 Docker 吗?
可以。每个沙箱都有独立的 Docker Engine,agent 可以构建镜像、运行 Testcontainers、启动 Compose 应用,既不需要宿主机的 socket,也不需要 Docker-in-Docker。
Docker Sandboxes 会取代容器吗?
不会。打包应用、CI 任务和短时执行,容器依然是最合适的工具。沙箱为自主 agent 加了一道更强的边界,容器继续在沙箱里运行。
容器和隔绝有什么区别?
容器隔离的是一个工作负载。隔绝涵盖的则是 agent 周围的整个环境,包括它运行在哪道边界之内、能访问什么、用哪些工具、如何复现。容器可以是隔绝的一部分,而 Docker Sandboxes 补上了自主 agent 所需的 microVM 边界。
AI agent 对环境有什么要求?
Docker 提出了四项要求。隔绝(模型无法改写的边界)、控制(能看清 agent 在做什么,也能随时叫停)、选择(更换模型、agent 和工具时不必推倒重来)、容量(其他开发者能复现这套配置,并扩展到单机之外)。
运行 Docker Sandboxes 需要什么?
需要一个受支持的 hypervisor,即 macOS 14 及以上版本上的 Apple silicon、Windows Hypervisor Platform,或受支持的 Ubuntu 系统上的 KVM。在另一个虚拟机里运行则需要嵌套虚拟化。