在 Docker Sandboxes 中安全运行 OpenClaw
AI 核心摘要
文章由 Oleg Šelajev 撰写,详细介绍了如何在 Docker Sandboxes 中安全地运行开源 AI 编程智能体 OpenClaw。Docker Sandboxes 提供了一个隔离的微型虚拟机环境,能够通过网络代理控制 Agent 的互联网访问,并安全注入 API 密钥(如 ANTHROPIC_API_KEY),防止泄露。结合 Docker Model Runner,用户可以在本地零成本、完全隐私地运行模型(如 qwen2.5 或 gpt-oss),并在同一个沙盒中无缝切换到云端模型。文章还提供了构建自定义 OpenClaw 镜像的技术细节,包括如何创建一个轻量级的 Node.js 桥接器来绕过 Node.js 对 HTTP_PROXY 的限制,从而成功连接宿主机上的 Docker Model Runner。
Docker Sandboxes 是 Docker 生态系统中的一个新基础组件,它允许你在隔离的微型虚拟机(micro VMs)中运行 AI Agent 或任何其他工作负载。它提供了强大的隔离性、便捷的开发者体验以及强大的安全边界,其网络代理可配置为拒绝 Agent 连接到任意互联网主机。网络代理还能方便地将诸如 ANTHROPIC_API_KEY 或 OPENAI_API_KEY 之类的 API 密钥注入其中,因此 Agent 根本无法访问这些密钥,也不可能将其泄露。
在上一篇文章中,我展示了 Docker Sandboxes 如何让你将 AI Agent 可能需要的任何工具(例如用于 Java 项目的 JDK 或某些自定义 CLI)安装到与主机隔离的容器中。今天我们将更进一步:我们将通过 Docker Model Runner 在本地模型上运行 OpenClaw——一个开源的 AI 编程 Agent。
没有 API 密钥泄露风险,没有云端成本,完全私密。而且你只需大约两条命令就能搞定。
快速开始
确保你安装了 Docker Desktop,并且启用了 Docker Model Runner(设置 → Docker Model Runner → 启用),然后拉取一个模型:
docker model pull ai/gpt-oss:20B-UD-Q4_K_XL
现在创建并运行沙盒:
docker sandbox create --name openclaw -t olegselajev241/openclaw-dmr:latest shell .
docker sandbox network proxy openclaw --allow-host localhost
docker sandbox run openclaw
在沙盒内部运行:
~/start-openclaw.sh
就这么简单。你现在进入了 OpenClaw 的终端用户界面(TUI),正在与你机器上本地的 gpt-oss 模型对话。模型在你的宿主机上的 Docker Model Runner 中运行,而 OpenClaw 则在沙盒中完全隔离运行:它只能读取和写入你提供给它的工作区文件,并且有一个网络代理来拒绝连接到不需要的主机。
云端模型也能用
沙盒代理会自动从你的宿主机环境中注入 API 密钥。如果你设置了 ANTHROPIC_API_KEY 或 OPENAI_API_KEY,OpenClaw 就可以运行云端模型,只需在 OpenClaw 设置中指定它们即可。代理负责凭证注入,因此你的密钥永远不会在沙盒内部暴露。
这意味着你可以使用免费的本地模型进行实验,然后在同一个沙盒中切换到云端模型进行正式工作。对于云端模型,你甚至不需要允许代理访问宿主机的 localhost,所以无需运行 docker sandbox network proxy openclaw --allow-host localhost。
选择你的模型
启动脚本会自动发现你的 Docker Model Runner 中可用的模型。列出它们:
~/start-openclaw.sh list
使用特定模型:
~/start-openclaw.sh ai/qwen2.5:7B-Q4_K_M
任何你使用 docker model pull 拉取过的模型都可以使用。
工作原理(稍微涉及点技术)
预构建的镜像 (olegselajev241/openclaw-dmr:latest) 基于 shell 沙盒模板,并增加了三个东西:Node.js 22、OpenClaw 和一个微型的网络桥接器。
需要这个桥接器是因为 Docker Model Runner 运行在你的宿主机上,并绑定到 localhost:12434。但是沙盒内部的 localhost 指的是沙盒本身,而不是你的宿主机。沙盒确实有一个 HTTP 代理,位于 host.docker.internal:3128,它可以访问宿主机服务,并且我们允许它通过 docker sandbox network proxy --allow-host localhost 访问 localhost。
问题在于 OpenClaw 是 Node.js 写的,而 Node.js 不遵循 HTTP_PROXY 环境变量。所以我们写了一个大约 20 行的桥接脚本,OpenClaw 连接到 127.0.0.1:54321,该脚本会明确地将请求通过代理转发,以到达宿主机上的 Docker Model Runner:
OpenClaw → 桥接器 (localhost:54321) → 代理 (host.docker.internal:3128) → Model Runner (宿主机 localhost:12434)
start-openclaw.sh 脚本启动桥接器,启动 OpenClaw 的网关(清除了代理环境变量以便直接命中桥接器),并运行 TUI。
自己动手构建
想自定义镜像或者只是想看看它是如何工作的?这是完整的构建过程。
1. 创建基础沙盒并安装 OpenClaw
docker sandbox create --name my-openclaw shell .
docker sandbox network proxy my-openclaw --allow-host localhost
docker sandbox run my-openclaw
现在让我们在沙盒中安装 OpenClaw:
# 安装 Node 22 (OpenClaw 需要它)
npm install -g n && n 22
hash -r
# 安装 OpenClaw
npm install -g openclaw@latest
# 运行初始设置
openclaw setup
2. 创建 Model Runner 桥接器
这是关键所在——一个微型的 Node.js 服务器,它将请求通过沙盒代理转发到你宿主机上的 Docker Model Runner:
cat > ~/model-runner-bridge.js << 'EOF'
const http = require("http");
const { URL } = require("url");
const PROXY = new URL(process.env.HTTP_PROXY || "http://host.docker.internal:3128");
const TARGET = "localhost:12434";
http.createServer((req, res) => {
const proxyReq = http.request({
hostname: PROXY.hostname,
port: PROXY.port,
path: "http://" + TARGET + req.url,
method: req.method,
headers: { ...req.headers, host: TARGET }
}, proxyRes => {
res.writeHead(proxyRes.statusCode, proxyRes.headers);
proxyRes.pipe(res);
});
proxyReq.on("error", e => { res.writeHead(502); res.end(e.message); });
req.pipe(proxyReq);
}).listen(54321, "127.0.0.1");
EOF
3. 配置 OpenClaw 使用 Docker Model Runner
现在将 Docker Model Runner 提供商合并到 OpenClaw 的配置中:
python3 -c "
import json
p = '$HOME/.openclaw/openclaw.json'
with open(p) as f: cfg = json.load(f)
cfg['models'] = cfg.get('models', {})
cfg['models']['mode'] = 'merge'
cfg['models']['providers'] = cfg['models'].get('providers', {})
cfg['models']['providers']['docker-model-runner'] = {
'baseUrl': 'http://127.0.0.1:54321/engines/llama.cpp/v1',
'apiKey': 'not-needed',
'api': 'openai-completions',
'models': [{
'id': 'ai/qwen2.5:7B-Q4_K_M',
'name': 'Qwen 2.5 7B (Docker Model Runner)',
'reasoning': False, 'input': ['text'],
'cost': {'input': 0, 'output': 0, 'cacheRead': 0, 'cacheWrite': 0},
'contextWindow': 32768, 'maxTokens': 8192
}]
}
cfg['agents'] = cfg.get('agents', {})
cfg['agents']['defaults'] = cfg['agents'].get('defaults', {})
cfg['agents']['defaults']['model'] = {'primary': 'docker-model-runner/ai/qwen2.5:7B-Q4_K_M'}
cfg['gateway'] = {'mode': 'local'}
with open(p, 'w') as f: json.dump(cfg, f, indent=2)
"
4. 保存并分享
退出沙盒并将其保存为可复用的镜像:
docker sandbox save my-openclaw my-openclaw-image:latest
将它推送到镜像仓库,以便任何人都可以使用:
docker tag my-openclaw-image:latest yourname/my-openclaw:latest
docker push yourname/my-openclaw:latest
任何拥有 Docker Desktop(包含现代沙盒功能)的人都可以通过以下命令启动相同的环境:
docker sandbox create --name openclaw -t yourname/my-openclaw:latest shell .
下一步
Docker Sandboxes 使在隔离的、可重复的环境中运行任何 AI 编程 Agent 变得容易。通过 Docker Model Runner,你获得了一个完全本地化的 AI 编程设置:没有云端依赖,没有 API 成本,并且完全保护隐私。
