夜雨聆风学习资料网

ARTICLE · 1029584

OpenClaw 沙箱环境运行实践:Docker 部署下如何动态创建 Sandbox

OpenClaw 沙箱环境运行实践:Docker 部署下如何动态创建 Sandbox

最近在折腾 OpenClaw 的过程中,我碰到一个比较典型的问题:

OpenClaw 本身已经运行在 Docker 容器里了,还能不能继续让 Agent 使用 Docker 沙箱执行 Python、Shell 和 Skills?

答案是可以。

而且这套架构本身也是比较常见的 Agent 隔离方案:

宿主机 Docker

├── OpenClaw Gateway 容器
│      │
│      └── docker.sock

├── Sandbox A
├── Sandbox B
└── Sandbox C

OpenClaw Gateway 本身运行在 Docker 中,但通过宿主机的:

/var/run/docker.sock

去调用宿主机 Docker daemon。

当 Agent 第一次需要执行 exec、Python、Shell 等工具时,OpenClaw 会动态创建一个独立的 Sandbox 容器。

这不是传统的 Docker-in-Docker,而更接近:

Docker-out-of-Docker

也就是:

Gateway 容器
    ↓
docker CLI
    ↓
/var/run/docker.sock
    ↓
宿主机 Docker daemon
    ↓
创建 Sandbox 容器

这样既可以保留 OpenClaw Docker 化部署,又可以继续使用 Sandbox 做隔离。

为什么需要 Sandbox

如果不开 Sandbox,Agent 调用:

exec
python3
shell

这些工具时,可能直接运行在 Gateway 所在环境。

对于生产环境来说,这个权限通常太大。

比如 Agent 理论上可能:

rm -rf
cat /etc/passwd
访问其他项目文件
读取敏感配置
执行任意脚本

Sandbox 的作用,就是给 Agent 单独划一个受限制的运行环境。

例如:

Agent
 ↓
Sandbox
 ├── /workspace
 ├── python3
 ├── curl
 ├── git
 └── limited network

Agent 可以完成任务,但不会直接拿到宿主机完整环境。

OpenClaw Sandbox 的几个关键配置

OpenClaw 的 Sandbox 主要配置在:

~/.openclaw/openclaw.json

核心配置类似:

{
"agents":{
"defaults":{
"workspace":"/home/node/.openclaw/workspace",

"sandbox":{
"mode":"all",
"backend":"docker",
"scope":"agent",
"workspaceAccess":"rw",

"docker":{
"image":"openclaw-sandbox:bookworm-slim",
"network":"bridge",
"readOnlyRoot":false,
"capDrop":[
"ALL"
],
"pidsLimit":256,
"memory":"1g",
"memorySwap":"2g",
"cpus":1
},

"prune":{
"idleHours":24,
"maxAgeDays":7
}
}
}
}
}

这里有几个关键参数。

mode 控制是否启用沙箱:

"mode":"all"

表示所有 Agent 会话都进入 Sandbox。

如果是:

"mode":"off"

则完全关闭 Sandbox。

backend:

"backend":"docker"

表示使用 Docker 创建沙箱。

scope:

"scope":"agent"

表示每个 Agent 使用一个独立 Sandbox。

例如:

main
  ↓
sandbox-main

agent1
  ↓
sandbox-agent1

agent2
  ↓
sandbox-agent2

如果隔离要求更高,也可以考虑每个 Session 单独一个 Sandbox。

workspaceAccess 非常重要

这个参数决定 Sandbox 是否能看到 Agent 的真实工作目录。

比如:

"workspaceAccess":"none"

表示 Sandbox 使用独立工作目录。

这种情况下:

memory/
skills/
AGENTS.md

通常不会直接出现在 Sandbox 的 /workspace 中。

如果改成:

"workspaceAccess":"ro"

Agent 可以读取 workspace,但不能修改。

如果改成:

"workspaceAccess":"rw"

Agent 可以读写真实 workspace。

对于需要执行 Skills 的场景,一般至少需要:

"workspaceAccess":"ro"

如果 Skill 会产生文件,则需要:

"workspaceAccess":"rw"

我这次就是因为 Skill 需要读取:

/workspace/skills/

以及:

/workspace/memory/

所以最终使用:

"workspaceAccess":"rw"

工具权限还要单独开放

Sandbox 开启并不代表 Agent 自动拥有所有工具。

OpenClaw 的工具策略和 Sandbox 是两层配置。

例如:

{
"tools":{
"sandbox":{
"tools":{
"allow":[
"exec",
"process",
"read",
"write",
"edit",
"apply_patch"
]
}
}
}
}

这意味着 Agent 可以在 Sandbox 里使用:

exec
process
read
write
edit
apply_patch

如果没有开放 exec,那么即使 Sandbox 正常启动,Agent 仍然不能执行:

python3 xxx.py

所以可以简单理解成:

Sandbox
→ 决定在哪里执行

Tool Policy
→ 决定能不能执行

两者缺一不可。

Docker 部署 OpenClaw 时还需要 docker.sock

如果 Gateway 本身就在 Docker 里,还需要让 Gateway 能调用宿主机 Docker。

docker-compose.yml 中需要:

volumes:
-/var/run/docker.sock:/var/run/docker.sock

例如:

services:
openclaw-gateway:
image:openclaw-openclaw138:latest
user:root

volumes:
-${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw
-${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace
-/var/run/docker.sock:/var/run/docker.sock

这样 Gateway 才能执行:

docker inspect
docker create
docker start
docker exec

进而动态管理 Sandbox。

一个常见坑:Gateway 容器里没有 docker 命令

即使挂了:

/var/run/docker.sock

如果 Gateway 容器本身没有:

docker

命令,也会报:

spawn docker ENOENT

典型错误:

Sandbox mode requires Docker,
but the "docker" command was not found in PATH.

这种情况下,需要给 Gateway 提供 Docker CLI。

一种方式是在容器启动时安装:

command:
-/bin/sh
--lc
-|
    if ! command -v docker >/dev/null 2>&1; then
      apt-get update &&
      apt-get install -y docker.io &&
      rm -rf /var/lib/apt/lists/*
    fi

execnodedist/index.jsgateway\
--bindlan\
--port18789

这样就不用重新构建 OpenClaw 镜像。

对于经常升级 OpenClaw 镜像的场景,这种方式比较方便。

第二个坑:Sandbox 镜像不存在

Docker CLI 打通之后,我又遇到:

Sandbox image not found:
openclaw-sandbox:bookworm-slim

说明 OpenClaw 已经可以调用 Docker,但 Sandbox 基础镜像还没有准备。

需要提前准备:

openclaw-sandbox:bookworm-slim

注意:

Sandbox 容器是动态创建的,但 Sandbox 镜像不是动态生成的。

也就是说:

镜像
→ 提前准备

容器
→ Agent 使用时自动创建

构建完成后:

docker images | grep openclaw-sandbox

应该能看到:

openclaw-sandbox   bookworm-slim

Sandbox 是动态创建的

这是 OpenClaw Sandbox 比较方便的地方。

你不需要手工:

docker run ...

第一次 Agent 使用执行工具时,OpenClaw 会自动创建。

例如:

用户发消息
 ↓
Agent 判断需要执行 Python
 ↓
调用 exec
 ↓
OpenClaw 检查 Sandbox
 ↓
不存在
 ↓
docker create
 ↓
docker start
 ↓
执行 Python

之后这个 Sandbox 可以继续复用。

配合:

"prune":{
"idleHours":24,
"maxAgeDays":7
}

还能实现自动回收。

也就是:

首次使用
→ 自动创建

后续调用
→ 继续复用

长时间不用
→ 自动清理

再次使用
→ 再创建

第三个坑:Skills 在 Sandbox 里是空的

这是我这次排查时间最长的地方。

Gateway 里可以看到:

/home/node/.openclaw/workspace/skills

但 Agent 却一直说:

/workspace/skills 是空的

检查 Sandbox:

docker inspect openclaw-sbx-xxx

发现挂载是:

Source=/home/node/.openclaw/workspace
Destination=/workspace

问题在于:

/home/node/.openclaw/workspace

其实是 Gateway 容器内部路径。

宿主机真正的数据目录却是:

/root/.openclaw137/workspace

而创建 Sandbox 的是宿主机 Docker daemon。

所以宿主机 Docker 会把:

/home/node/.openclaw/workspace

当成宿主机目录。

结果就是:

Gateway 有文件
Sandbox 没文件

最终表现为:

/workspace/memory 不存在
/workspace/skills 为空

这个问题本质上就是 Docker-out-of-Docker 环境下的路径映射问题。

所以如果使用 Docker Gateway + Sandbox,一定要特别注意:

宿主机路径
Gateway 容器路径
Sandbox Source

这三层关系。

如何检查 Sandbox 挂载

可以直接:

docker ps --format '{{.Names}}' | grep openclaw-sbx

找到:

openclaw-sbx-workspace-xxxx

然后:

docker inspect openclaw-sbx-workspace-xxxx \
  --format '{{range .Mounts}}Source={{.Source}} -> Destination={{.Destination}} RW={{.RW}}{{println}}{{end}}'

如果是正确状态,应该类似:

Source=/真实宿主机/workspace
-> Destination=/workspace
RW=true

然后:

docker exec openclaw-sbx-workspace-xxxx \
  sh -lc 'find /workspace -maxdepth 3 -type f | head -100'

就能直接看到 Sandbox 中真实可访问的文件。

网络默认也要注意

生产环境下,Sandbox 默认不应该拥有无限制网络权限。

如果设置:

"network":"none"

Sandbox 完全不能主动联网。

这非常安全。

但如果 Skill 要调用远程 API,例如:

requests.get("https://api.example.com")

就必须开放网络。

例如:

"network":"bridge"

因此应该按实际需求决定。

对于纯本地代码执行:

network: none

更安全。

对于知识库 API、外部服务:

network: bridge

才有必要。

docker.sock 不要挂进 Sandbox

这一点非常重要。

Gateway 可以有:

-/var/run/docker.sock:/var/run/docker.sock

但 Sandbox 不应该有。

正确结构:

Gateway
✅ docker.sock

Sandbox
❌ docker.sock

如果把 Docker socket 给 Sandbox,相当于 Agent 可以直接控制宿主机 Docker。

理论上就可以:

docker run -v /:/host ...

这样整个 Sandbox 隔离基本失去意义。

所以:

Gateway 是沙箱管理员

Sandbox 是被管理的执行环境

这两者权限一定要分开。

最终架构

最终我使用的结构大概是:

宿主机

├── Docker daemon

├── OpenClaw Gateway
│      │
│      ├── docker CLI
│      ├── docker.sock
│      └── openclaw.json

├── openclaw-sbx-main
│      ├── /workspace
│      ├── python3
│      ├── skills
│      └── memory

└── openclaw-sbx-agent2
       └── ...

OpenClaw 负责:

接收消息
→ Agent 判断任务
→ 调用工具
→ 动态创建 Sandbox
→ 在 Sandbox 执行
→ 返回结果

总结

OpenClaw 的 Docker Sandbox 思路其实很清晰:

Gateway 负责调度
Sandbox 负责执行

对于生产环境来说,比直接让 Agent 在 Gateway 或宿主机执行命令安全很多。

实际部署时最容易踩的坑主要有几个:

  1. Gateway 挂了 docker.sock,但容器里没有 Docker CLI。
  2. Sandbox 基础镜像没有提前准备。
  3. workspaceAccess
     配成 none,导致 Skills 和 Memory 看不到。
  4. exec
     没有在 Tool Policy 里放行。
  5. Docker Gateway 场景下,宿主机路径和容器路径映射错位。
  6. Sandbox 网络默认关闭,导致远程 API 调不通。
  7. 错误地把 docker.sock 暴露给 Sandbox。

如果这些问题都解决,最终体验其实很好:

Agent 收到任务
→ 自动创建隔离环境
→ 执行 Python / Shell / Skills
→ 使用完自动回收

这套模式非常适合 OpenClaw 这种需要调用工具、执行脚本、接入企业微信客服或知识库的 Agent 系统。

相关学习资料

返回首页浏览学习资料