ARTICLE · 1029584
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 或宿主机执行命令安全很多。
实际部署时最容易踩的坑主要有几个:
Gateway 挂了 docker.sock,但容器里没有 Docker CLI。Sandbox 基础镜像没有提前准备。 workspaceAccess配成 none,导致 Skills 和 Memory 看不到。exec没有在 Tool Policy 里放行。 Docker Gateway 场景下,宿主机路径和容器路径映射错位。 Sandbox 网络默认关闭,导致远程 API 调不通。 错误地把 docker.sock暴露给 Sandbox。
如果这些问题都解决,最终体验其实很好:
Agent 收到任务
→ 自动创建隔离环境
→ 执行 Python / Shell / Skills
→ 使用完自动回收
这套模式非常适合 OpenClaw 这种需要调用工具、执行脚本、接入企业微信客服或知识库的 Agent 系统。
