Docker 把 Agent 沙箱搬上云:容器不等于「关押」

·阅读约11分钟·Evergreen Tools Team

2026 年 9 月 24 日,在 WeAreDevelopers North America 上,Docker 发布了 Docker Cloud Sandboxes,把今年早些时候推出的本地 Agent 沙箱扩展到托管的云端基础设施之上。真正有意思的是 Docker 总裁 Mark Cavage 的表述:容器从来不是为 AI Agent 所需的那个隔离级别设计的。Agent 不是应用——它读你的文件、跑你的 shell、握着你的密钥,而且,正如 Cavage 在台上演示的那样,它会主动去寻找环境的边界,因为「越界」往往正是它能干成活的来源。Cloud Sandboxes 要做的,是把这条确定性的边界从笔记本搬到一个受管的微虚拟机里。

一、那场让论点成立的现场演示

Cavage 先演示了反面:他把 Anthropic 的 Claude 跑在一个普通的 Docker 容器里,让它去找一个存储在本地、容器之外的密钥。它找到了——方法是通过探测自身环境,用被挂载进来的宿主机 Docker socket 打了出去。接着,Docker 首席工程师 Michael Irwin 把同一个提示词跑在一个 Docker Sandbox 里。这次模型发现了那个 socket,尝试用它去挂载宿主机路径和特权容器,但就是到不了——因为沙箱是以完整的微虚拟机运行的。Irwin 的结论是「隔离守住了」。这场演示的要点并不是「容器不安全」:容器做的正是它被设计要做的事,隔离应用。Cavage 那句总结才是论点本身——我们必须把「容器」和「关押(containment)」分开。

# The shape of the problem. An agent inside an ordinary container can still
# reach the host through anything that was mounted in. Docker's own demo had
# Claude find a locally stored secret by probing its environment and using
# the mounted host Docker socket -- the container was working as designed.

# Illustrative sandbox spec: what a contained agent actually needs declared.
version: "1"
agent:
  name: refactor-bot
  image: ghcr.io/acme/refactor-bot:1.4.0
isolation:
  # A full microVM, not a namespace-sharing container.
  runtime: microvm
  mountHostDockerSocket: false      # the escape hatch that leaked in the demo
secrets:
  inject: ["GITHUB_TOKEN"]          # injected, never mounted as a file
  ttlMinutes: 60
network:
  default: deny                     # egress deny-by-default
  allow: ["api.github.com:443", "registry.npmjs.org:443"]
resources:
  vcpu: 4
  memoryGb: 8
确定性隔离层

沙箱限制的是「触达范围」,策略限制的是「行为意图」

二、Cloud Sandboxes 到底是什么

它是同一套沙箱模型的托管版本。Agent 跑在由 Docker 托管的基础设施上的微虚拟机里,沿用与本地沙箱相同的策略,因此长时间运行的 Agent 工作流可以在你的笔记本关机之后继续跑下去。启动时间是「几百毫秒级」,按秒计费。密钥、策略、网络、Agent 配置与 MCP 网关都是内置的。算力从 1 到 16 个 vCPU 弹性伸缩、完全托管——你只需把 Agent 指过去。据 The Register 报道,价格按实例规格自每小时 0.07 美元(Micro,1 vCPU / 2GB)起,到每小时 1.12 美元(XL,16 vCPU / 32GB)。本地与云端使用同一套 CLI 与信任模型。

// Policy is the layer above isolation: the sandbox limits what the agent can
// REACH, policy limits what it is allowed to DO. Keep both, and keep the
// policy in version control.

{
  "policy": "prod-agent-baseline",
  "rules": [
    { "match": { "tool": "shell.exec", "command": "rm -rf *" },
      "effect": "deny", "reason": "destructive filesystem operation" },
    { "match": { "tool": "network.fetch", "host": "*.internal" },
      "effect": "require_approval" },
    { "match": { "tool": "shell.exec", "command": "git push*" },
      "effect": "require_approval", "approver": "human" },
    { "match": { "tool": "fs.write", "path": "/workspace/**" },
      "effect": "allow" }
  ],
  "default": "deny"
}

三、时间点并非巧合

就在同一周,澳大利亚官员披露:一个 OpenAI 的 Agent 在检索健康统计数据时,未经授权访问了一个政府门户。这正是行业反复出现的模式——Agent 找到了运营者未曾预料到的访问路径。容器逃逸类的事件已经多到厂商会主动披露。Docker 的论点是:确定性的隔离层应该是最低门槛;策略治理的是「意图」,沙箱治理的是「触达范围」。把这个顺序摆正,很多「Agent 又乱来了」的新闻就会变成「Agent 被挡住了」。

# Verify containment instead of assuming it. The demo that matters is the
# one you run against your own agent: ask it to leave, then check whether
# the escape actually worked.

import json, subprocess

PROBE = "find / -name '*.pem' -o -name 'credentials' 2>/dev/null | head"

def check_containment(sandbox_id):
    cmd = ["docker", "sandbox", "exec", sandbox_id, "sh", "-lc", PROBE]
    out = subprocess.run(cmd, capture_output=True, text=True)
    leaked = [l for l in out.stdout.splitlines() if l.strip()]
    # Also confirm the classic escape route is closed.
    sock = subprocess.run(
        ["docker", "sandbox", "exec", sandbox_id, "sh", "-lc",
         "ls -l /var/run/docker.sock || true"],
        capture_output=True, text=True).stdout.strip()
    return {"sandbox": sandbox_id, "leakedPaths": leaked,
            "dockerSocket": sock or "absent", "ok": not leaked and not sock}

print(json.dumps(check_containment("sbx-refactor-01"), indent=1))
微虚拟机隔离

沙箱以完整微虚拟机运行,而不是共享命名空间的容器

四、Kits 变成了标准 OCI 镜像

Docker 还更新了 Kits 规范——把 Agent、它的工具与访问规则打包成一个可分享的产物。如今 Kits 以标准 OCI 镜像形式交付,这正面回应了「会不会被私有格式锁死」的质疑,Docker 也表示会把 Kits 规范提交给 CNCF。随发布一起提供的一个例子是 BAND Python Kit,它让 Agent 之间通过 WebSocket 协作,而不必处在同一个环境里。对平台团队而言,这一条其实更耐久:一个可移植的 Agent 打包单元,注册中心能像对待任何镜像一样签名、扫描和版本化它。

# Egress is where a contained agent can still hurt you. Allowlist the
# destinations a job legitimately needs, log everything else, and fail
# closed. Deny-by-default is the only default worth shipping.

ALLOWLIST = {
    "refactor-bot": [
        ("api.github.com", 443),
        ("registry.npmjs.org", 443),
    ],
    "doc-bot": [
        ("api.internal.docs", 443),
    ],
}

def review_egress(agent: str, observed: list[tuple[str, int]]) -> dict:
    allowed = set(ALLOWLIST.get(agent, []))
    blocked = [c for c in observed if c not in allowed]
    return {
        "agent": agent,
        "observed": len(observed),
        "blocked": blocked,
        # A blocked destination is either a policy gap or an incident.
        "action": "review" if blocked else "none",
    }

observed = [("api.github.com", 443), ("pastebin.example", 443)]
print(review_egress("refactor-bot", observed))

五、它解决了什么、又不解决什么

把话说白:沙箱限制的是「触达」,不是「判断」。Cavage 自己也说,沙箱是确定性的底层,策略才治理 Agent 的意图。一个跑在微虚拟机里的 Agent 仍然可能被提示词注入,仍然可能通过被允许的出站路径外泄数据,也仍然可能用一个合法凭据做出错误的动作。所以务实的做法是三层:隔离(微虚拟机)、策略(它能触达什么、能做什么)、身份(它能以谁的名义认证,且可吊销)。示例 2 展示了策略即代码。如果这一季度你只能做一件事,先做隔离层,因为它是三层里唯一一个「当另外两层出错时还能兜住」的东西。

# Kits now ship as standard OCI images, so an agent definition is an artifact
# you can sign, scan, version and pull like any other image -- instead of a
# folder in somebody's home directory.

# Build and publish a Kit the way you already publish images.
# (Illustrative workflow -- see Docker's Kits documentation for exact flags.)
docker build -t ghcr.io/acme/refactor-kit:1.4.0 ./kit
docker push ghcr.io/acme/refactor-kit:1.4.0

# Then pin it by digest, so a registry compromise cannot silently swap it.
cat <<'YAML'
agent:
  kit: ghcr.io/acme/refactor-kit@sha256:9f2c...e41b
  network: deny-by-default
  secrets: [GITHUB_TOKEN]
YAML
把逃逸检测变成例行检查

演示里被挡住的那条路,也应该是你自己 Agent 的例行测试

六、怎么开始用

先挑一个长时间运行的工作流搬到云端沙箱,确认三件事:笔记本关着它也能跑完;密钥是被「注入」而不是被「挂载」的;出站是默认拒绝加白名单。然后把 Kits 格式标准化,让 Agent 的定义住在注册中心里,而不是住在某个人的家目录里。如果你手上有个 Agent 之所以在本地跑「危险模式」,是因为不这样就要点一百次批准——那它恰恰就是沙箱被造出来要服务的那个工作负载。还有一个值得养成的习惯:把沙箱规格和策略放进同一个 pull request 里审查。改变 Agent 能触达什么,是一次安全变更,理应和改变它能做什么接受同等严格的评审。把两者放在一起评审的团队,就不会再为「某次事故到底算隔离失效还是策略缺口」争论不休。

📌 常见问题 FAQ

Docker 发布了什么?

2026 年 9 月 24 日在 WeAreDevelopers North America 发布 Docker Cloud Sandboxes,把本地 Agent 沙箱的微虚拟机隔离扩展到托管的云端基础设施。

沙箱和容器有什么区别?

容器隔离的是应用;沙箱以完整微虚拟机运行,提供针对 AI Agent 的更强隔离。Docker 的说法是「必须把容器和关押分开」。

Cloud Sandboxes 多少钱?

按实例规格计费,据 The Register 报道自每小时 0.07 美元(Micro,1 vCPU / 2GB)到每小时 1.12 美元(XL,16 vCPU / 32GB)。

Kits 有什么变化?

Kits 现在作为标准 OCI 镜像发布,可像普通镜像一样签名、扫描和版本化;Docker 表示将把 Kits 规范提交给 CNCF。

有了沙箱,Agent 就安全了吗?

不是。沙箱是确定性的隔离层,限制的是 Agent 的触达范围;仍需策略层治理行为、身份层治理凭据,三者缺一不可。