Agent沙箱环境Docker隔离
如果你正在开发或部署 Agent 应用,通常会遇到一个现实问题:Agent 执行命令、读写文件、调用外部工具时,一旦代码有漏洞或被提示注入攻击,主机系统就可能被波及。
把 Agent 的所有动作约束在 Docker 容器内部,是当前成本最低、见效最快的沙箱方案。
本文以零基础可跟做的思路,为你完整演示这类 Agent 沙箱环境 Docker 隔离的搭建、避坑和验证方法。
为什么选 Docker 做 Agent 沙箱
Docker 容器不是虚拟机,它共享宿主机内核,但通过命名空间、Cgroups 和只读文件系统实现进程、网络、文件、资源的逻辑隔离。
对 Agent 来说,容器能限制它的文件访问范围、网络出口和 CPU 内存占用,足以应对大多数自动化操作场景。
相比单独建虚拟机,Docker 更轻量,启动秒级,镜像可复用,非常适合需要频繁创建和销毁的 Agent 执行环境。
动手前需要准备什么
你需要一台 Linux 服务器(Ubuntu 22.04 / Debian 12 均可),已安装 Docker Engine。
如果没有安装,可执行:
curl -fsSL https://get.docker.com | sh
sudo systemctl enable --now docker
确认 Docker 正常:
docker --version
另外准备一个干净的目录用于存放 Agent 代码和配置,例如 /opt/agent-sandbox。
第一步:拉取一个精简基础镜像
Agent 环境越精简,攻击面越小。
这里以 debian:bookworm-slim 为例:
docker pull debian:bookworm-slim
如果需要 Python 环境,可以换用 python:3.11-slim。
不要直接使用包含完整桌面或大量开发工具的大镜像。
第二步:编写受限容器启动配置
用 docker run 启动时,要重点限制权限、网络和本地文件挂载。
下面是一个生产可用示例:
docker run -d --name my-agent-sandbox \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--network none \
--cap-drop ALL \
--security-opt no-new-privileges \
--pids-limit 128 \
--memory 512m \
--cpus 0.5 \
debian:bookworm-slim sleep infinity
参数含义如下:
--read-only:根文件系统挂载为只读,Agent 无法修改系统文件。--tmpfs:允许临时目录写入,但不执行文件,避免反弹 shell。--network none:完全禁用网络。如果你的 Agent 需要访问 API,可改用--network bridge并配合防火墙规则。--cap-drop ALL:丢弃所有 Linux 内核能力,容器内进程无法执行特权操作。--security-opt no-new-privileges:禁止提升权限。--pids-limit、--memory、--cpus:限制进程数量、内存和 CPU,防止 Agent 异常消耗宿主机资源。
第三步:如何将 Agent 代码放进容器又不破坏只读限制
只读文件系统下,Agent 代码不能直接写入 / 和 /etc。
推荐的做法:把代码目录挂载为只读,把输出目录挂载为可写临时卷。
先在宿主机准备目录:
mkdir -p /opt/agent-sandbox/code /opt/agent-sandbox/output
chown -R 1000:1000 /opt/agent-sandbox/output
然后重新创建容器(加上挂载):
docker rm -f my-agent-sandbox
docker run -d --name my-agent-sandbox \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size=100m \
--network none \
--cap-drop ALL \
--security-opt no-new-privileges \
--pids-limit 128 \
--memory 512m \
--cpus 0.5 \
-v /opt/agent-sandbox/code:/app/code:ro \
-v /opt/agent-sandbox/output:/app/output \
--user 1000:1000 \
debian:bookworm-slim sleep infinity
其中 --user 1000:1000 让容器内进程以普通用户运行,而不是 root。/app/code 是只读代码目录,/app/output 是 Agent 可写的结果目录。
如果你用 docker-compose,可以写成:
services:
agent:
image: debian:bookworm-slim
command: sleep infinity
read_only: true
tmpfs:
- /tmp:rw,noexec,nosuid,size=100m
network_mode: none
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
pids_limit: 128
mem_limit: 512m
cpus: 0.5
user: "1000:1000"
volumes:
- /opt/agent-sandbox/code:/app/code:ro
- /opt/agent-sandbox/output:/app/output
第四步:让 Agent 真正在容器内执行动作
启动后,Agent 主程序可以放在 /app/code 中,通过 docker exec 进入容器执行:
docker exec -it my-agent-sandbox /bin/bash
在容器内,Agent 只能看到挂载的代码目录和输出目录,无法访问宿主机的 /etc、/root 等路径。
代码中执行子进程、写临时文件,都只能用 /tmp 或 /app/output。
如果你要让外部程序调用容器内 Agent,可以用 docker exec 或 Docker API。
注意每次调用都要使用 --user 和 --read-only 等安全参数,防止副作用。
高频问题与排错
容器启动后立即退出?
查看日志:docker logs my-agent-sandbox。常见原因是 sleep infinity 在某些精简镜像中不存在,换成 tail -f /dev/null 或 sleep 2147483647 即可。
Agent 需要联网怎么办?
将 --network none 改为 --network bridge,然后使用宿主机防火墙限制容器只允许访问特定域名或端口。更严格的做法是用 --network container:代理容器 让流量经过专门代理。
写文件提示 Read-only file system?
这是正常现象,因为根目录是只读的。请把输出路径配置到挂载的卷中,例如 /app/output,别写 /var 或 /root。
避坑指南:这些细节决定沙箱是否安全
- 不要使用默认的 bridge 网络:默认 bridge 下容器间可以互相通信,如果同一宿主机有其他服务,建议为沙箱单独创建 network,并开启
--internal。 - 不要挂载 Docker Socket:很多教程会把
/var/run/docker.sock挂进容器方便管理,但这对 Agent 来说等于给了宿主机 root 权限,必须避免。 - 镜像漏洞要定期扫描:沙箱镜像本身也可能有系统漏洞,建议用
docker scout或trivy定期检查。 - 隐藏内核信息:可以加上
--security-opt seccomp=default让容器使用系统默认 seccomp 配置,或自定义配置文件,减少内核 syscall 暴露。
最后:如何验证隔离是否生效
验证分为四步,建议每一次部署后执行:
docker exec my-agent-sandbox ls /app/code
docker exec my-agent-sandbox ls /app/output
docker exec my-agent-sandbox cat /etc/passwd
docker exec my-agent-sandbox touch /test.txt
前两步分别验证代码和输出目录挂载正常;
第三步能读到 /etc/passwd 说明容器内文件系统正常;
第四步如果报 Read-only file system 或 Permission denied,说明只读限制已生效。
再验证资源限制:
docker stats my-agent-sandbox
可以看到内存和 CPU 使用上限已经被锁定。
最后测试网络:docker exec my-agent-sandbox ping 8.8.8.8。
如果输出 Network is unreachable,说明 --network none 生效。
完成以上步骤后,你的 Agent 沙箱环境 Docker 隔离就算落地了。
日常使用时,只需把 Agent 代码更新到 /opt/agent-sandbox/code,然后重启容器即可。
如果遇到容器权限、网络或写目录异常,优先回到本文避坑指南检查对应的启动参数,大部分问题都是参数遗漏导致。