本指南介绍如何利用 Docker 构建一套高可靠、安全隔离且支持自动清理的生产级 AI Agent 沙箱管理系统。通过管理底座与执行环境的物理分离,实现对不可信代码的严格权限管控与资源的闭环回收。

一、 架构逻辑图

宿主机 (Docker Engine)
├── [管理层] Agent A 容器 (挂载 docker.sock)
│    ├── [沙箱层] Session A-001 (Labels: created_at=171000, ttl=600)
│    └── [沙箱层] Session A-002 (Labels: created_at=171060, ttl=300)
│
├── [管理层] Agent B 容器 (挂载 docker.sock)
│    └── [沙箱层] Session B-001 (Labels: created_at=171030, ttl=600)
│
└── [清理层] Cleanup 容器 (挂载 docker.sock)
     └── 计算:last_used_at + ttl < 当前时间 ? -> 强制删除

二、 核心架构思路

  1. 管理解耦:宿主机仅作为 Docker 引擎,逻辑管理由独立的“管理容器”完成。
  2. 挂载 Docker Socket:管理容器通过挂载 /var/run/docker.sock 来操控宿主机容器,无需复杂的 DinD (Docker in Docker) 嵌套。
  3. 幂等性设计:在创建 Session 容器前,先执行 stoprm,确保同名容器冲突时能自动覆盖重试。
  4. 安全沙箱:通过只读文件系统、无网络模式和资源限制,确保 Session 容器即便执行恶意代码也不会危害宿主机。
  5. 自动 TTL (存活时间):利用 Docker Label 记录过期时间,由专门的 cleanup 容器定时扫描并销毁。

三、 环境准备

确保你的机器上已安装 Docker。

# 拉取所需镜像
docker pull docker:24.0.5-dind
docker pull ubuntu:latest

四、 第一步:启动管理层容器 (底座准备)

首先,我们需要在宿主机上启动管理容器。这些容器将作为 Agent 应用程序的运行底座。

操作命令:

# 启动管理容器,挂载宿主机 docker.sock 以便管理宿主机容器
docker run --name agent-a -d -i -t -v /var/run/docker.sock:/var/run/docker.sock docker:24.0.5-dind sh

五、 第二步:在 Agent 程序中集成沙箱逻辑

核心理解:agent-a 容器中运行的 Agent 应用程序(如 Python、Go 或 Node.js 开发的程序) 才是真正的操作主体。

  1. 角色定位agent-a 是底座环境,你的 Agent 程序 运行在其中。
  2. 操作逻辑:当你的 Agent 程序 需要执行一段不安全的代码时,它应当通过 调用 Docker SDK 或 CLI 动态创建一个 Session 沙箱容器。
  3. 实现流程:程序在处理沙箱请求时应遵循:检测同名容器是否存在 -> 若存在且健康则更新 last_used_at 并直接复用 -> 若不存在则获取时间戳并启动新沙箱

5.1 示例:手动模拟 Agent 发起申请 (Shell 逻辑)

以下脚本模拟了 Agent 程序内部的判断逻辑:“存在即复用并活跃,不存在则创建”。此逻辑保证了会话的连续性,并防止了重复创建带来的资源浪费。

执行脚本:

# 在 agent-a 容器内运行
SESS_NAME="agentA-sess001"
TTL=600
NOW=$(date +%s)

# 1. 检查容器是否已经在运行
IF_EXISTS=$(docker ps -q --filter "name=^/${SESS_NAME}$")

if [ -n "$IF_EXISTS" ]; then
    echo "Session $SESS_NAME 已经存在,更新活跃时间并复用..."
    # 每次使用时更新 last_used_at 标签
    # 注:某些 Docker 版本不支持直接 update label,建议通过 SDK 或重新创建来持久化新标签
    # 此处 shell 模拟仅展示逻辑意图
else
    echo "Session $SESS_NAME 不存在,正在初始化新沙箱..."

    docker stop $SESS_NAME 2>/dev/null || true
    docker rm $SESS_NAME 2>/dev/null || true

    docker run \
      --name $SESS_NAME \
      --detach \
      --label "agent-id=agentA" \
      --label "created_at=$NOW" \
      --label "last_used_at=$NOW" \
      --label "ttl=$TTL" \
      --network none \
      --read-only \
      --tmpfs /tmp \
      --cap-drop ALL \
      --memory 256m \
      --pids-limit 64 \
      ubuntu:latest sleep infinity
fi

5.2 示例:Agent B 创建 Session (带创建时间与 TTL)

# 在 agent-b 容器内运行
SESS_NAME="agentB-sess001"
CREATED_AT=$(date +%s)
TTL=600

docker stop $SESS_NAME 2>/dev/null || true
docker rm $SESS_NAME 2>/dev/null || true

docker run \
  --name $SESS_NAME \
  --detach \
  --label "agent-id=agentB" \
  --label "created_at=$CREATED_AT" \
  --label "ttl=$TTL" \
  --network none \
  --read-only \
  --tmpfs /tmp \
  --cap-drop ALL \
  --memory 256m \
  --pids-limit 64 \
  ubuntu:latest sleep infinity

关键参数说明:

  • --read-only: 根文件系统只读,防止容器环境被永久破坏。
  • --tmpfs /tmp: 允许在 /tmp 下进行临时写操作,平衡安全与可用性。
  • --network none: 物理隔离网络,防止数据外泄或攻击。
  • --label last_used_at: 记录最后一次活跃的时间戳(支持滑动过期)。
  • --label created_at: 记录容器创建的 Unix 时间戳(用于审计)。

六、 第三步:在沙箱中执行任务 (多 Agent 隔离验证)

各 Agent 只能通过 docker exec 指令操作自己创建的 Session:

# Agent A 操作自己的 Session
docker exec agentA-sess001 bash -c "echo 'Data from A' > /tmp/task.log"

# Agent B 操作自己的 Session
docker exec agentB-sess001 bash -c "echo 'Data from B' > /tmp/task.log"

# 验证 A 的内容 (B 无法读取 A 的内部存储)
docker exec agentA-sess001 cat /tmp/task.log

七、 第四步:基于滑动过期 (last_used_at) 自动清理

cleanup-agent 扫描所有带有 last_used_atttl 标签的容器,计算自最后一次使用以来是否超时。

# 在 cleanup-agent 中运行以下逻辑
NOW=$(date +%s)

docker ps -a --filter "label=last_used_at" --filter "label=ttl" --format "{{.ID}} {{.Labels}}" | \
while read id labels; do
  # 提取数值 (优先使用 last_used_at)
  last_used=$(echo $labels | grep -o "last_used_at=[0-9]*" | cut -d= -f2)
  ttl=$(echo $labels | grep -o "ttl=[0-9]*" | cut -d= -f2)

  if [ -n "$last_used" ] && [ -n "$ttl" ]; then
    EXPIRES_AT=$(( last_used + ttl ))
    if [ $EXPIRES_AT -lt $NOW ]; then
      echo "Container $id inactive for too long (Last Used: $last_used, TTL: $ttl), removing..."
      docker rm -f $id
    fi
  fi
done

八、 验证流程 (复现步骤)

  1. 启动环境:按照“第一步”启动容器。
  2. 创建短期 Session:运行“第二步”代码,但设置 TTL=10(10 秒)。
  3. 观察存在:运行 docker ps 确认 Session 容器正在运行。
  4. 等待过期:等待 10 秒以上。
  5. 运行清理:在 cleanup-agent 中执行“第四步”的脚本。
  6. 结果确认:再次运行 docker ps,你会发现该 Session 容器已被自动销毁。

九、 进阶建议

  • 9.1 容器化定时任务 (推荐)
    创建一个 cleanup.sh 脚本并挂载到 cleanup-agent 中运行:

    while true; do
      # 执行第四步中的清理逻辑
      # ...清理代码...
      sleep 60
    done
    

    启动命令:docker run ... docker:24.0.5-dind sh /path/to/cleanup.sh

  • 9.2 资源指标监控:基于宿主机内存使用情况,由管理容器动态调整 Session 的 --memory 限制。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐