适用场景
当你把「写代码」这件事交给智能体后,真正难的不是生成,而是在哪里执行:直接跑在宿主机上,一次 rm -rf 或一次意外的 pip install 就可能污染环境;跑在本地容器里,又受限于机器资源,且很难并发几十个隔离实例。Daytona 提供的是一层「沙箱即服务」:你用 CLI 或 SDK 申请一个隔离的云端执行环境,几秒内拿到可用的 shell、文件系统和进程接口,智能体在里面随便折腾,用完直接销毁。这套方案适合要做代码执行类 Agent、自动化评测、在线 IDE 或 CI 型任务的中小型团队,也适合个人开发者快速验证想法。
环境与前置条件
- 操作系统:macOS、主流 Linux 发行版均可;Windows 建议使用 WSL2,避免路径与符号链接带来的兼容问题。
- 运行时:Daytona CLI 是单文件二进制,装完即可用;若用 SDK 编排,需要 Python 3.10+ 或 Node 18+,具体最低版本以官方文档当前版本为准。
- 本地依赖:只有「构建自定义快照」这一步需要本地有 Docker;只使用官方或已构建好的快照时,本地不需要 Docker。
- 凭证:一个 API Key。可以来自 Daytona 托管服务,也可以来自自建控制面。不要把 Key 写进代码,统一走环境变量。
- 资源建议(自建场景):控制面建议 4 核 8GB 起步;沙箱节点每个实例预留 1~2 vCPU、2~4GB 内存,磁盘按快照镜像层大小留出 2~3 倍余量,因为每个沙箱都会从快照派生出可写层。
- 网络:本机能访问 Daytona API 端点与镜像仓库。如果处在受限网络环境,提前配好镜像加速,否则快照构建会卡在拉取基础镜像这一步。
下文以「CLI 装好 → 建快照 → 起沙箱 → SDK 编排 → 收网络策略 → 回收」为主线,托管与自建在命令层面基本一致,差异只在 API 地址。
分步骤部署
步骤 1:安装 CLI 并确认能跑
按官方文档给出的安装方式装好 CLI(不同系统的安装渠道以官方页面为准),然后验证:
```bash
daytona version
```
能打印出版本号就说明二进制可执行。若提示 command not found,检查安装目录是否在 PATH 里:
```bash
which daytona
echo $PATH
```
步骤 2:配置 API 端点与 Key
Daytona 的 CLI 和 SDK 都靠三个信息定位服务:API 地址、API Key、目标区域(target)。用环境变量注入是最干净的方式:
```bash
export DAYTONA_API_URL="https://<你的控制面地址>/api"
export DAYTONA_API_KEY="<你的 API Key>"
export DAYTONA_TARGET="<区域或目标名,留空则用默认>"
```
把这三行写进 ~/.zshrc 或 ~/.bashrc,新开终端后自检:
```bash
echo $DAYTONA_API_URL
daytona list
```
daytona list 返回一张(可能为空的)沙箱表格,而不是 401 或连接超时,说明认证与服务发现都通了。自建场景里 DAYTONA_API_URL 指向你自己部署的 API 服务地址即可。
步骤 3:构建一个带工具链的沙箱快照
快照(snapshot)是沙箱的「母版」:基础镜像 + 预装依赖。沙箱启动之所以能到秒级,就是因为不用每次从零装环境。准备一个 Dockerfile:
```dockerfile
FROM python:3.12-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends git curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN pip install --no-cache-dir pytest requests
WORKDIR /workspace
```
要点是够用就好:镜像每大一层,冷启动就慢一点,派生的可写层也更大。构建并推送:
```bash
daytona snapshot create my-agent-base --dockerfile ./Dockerfile
```
命令会输出构建日志,最后给出快照名与状态。确认状态:
```bash
daytona snapshot list
```
看到目标快照状态为可用(active 或同义状态)即可进入下一步。若参数名与你的 CLI 版本不一致,用 daytona snapshot create --help 查当前支持的写法。
步骤 4:用 CLI 起第一个沙箱
```bash
daytona create --snapshot my-agent-base
daytona list
```
daytona list 里会多出一行,包含沙箱 ID 和状态。想进去看看:
```bash
daytona ssh <sandbox-id>
```
进去以后执行 python --version、pytest --version,能对上 Dockerfile 里装的东西,说明快照继承正常。
手工验证完记得清理,别让它一直计费:
```bash
daytona stop <sandbox-id>
daytona delete <sandbox-id>
```
步骤 5:用 SDK 接管生命周期
真实场景里,沙箱是由程序申请和释放的。下面用 Python SDK 演示一个最小闭环——建沙箱、传文件、执行、取回结果:
```python
from daytona import Daytona, DaytonaConfig, CreateAI 词典:Sandbox">SandboxParams
daytona = Daytona(DaytonaConfig(
api_key="<你的 API Key>", # 生产环境从环境变量读取
api_url="<你的 API 地址>",
))
sandbox = daytona.create(CreateSandboxParams(
snapshot="my-agent-base",
language="python",
auto_stop_interval=15, # 空闲 15 分钟后自动停止
auto_delete_interval=60, # 停止 60 分钟后自动删除
))
print("sandbox id:", sandbox.id)
把智能体生成的代码写进沙箱
sandbox.fs.upload_file("main.py", "/workspace/main.py")
执行并拿到 stdout / exit_code
resp = sandbox.process.exec("cd /workspace && python main.py")
print("exit:", resp.exit_code)
print(resp.result)
sandbox.delete()
```
这段代码是整个方案的核心:沙箱对智能体来说就是三个能力——写文件、跑命令、读输出。把这三件事封装成工具函数,接进你的 Agent 循环即可。注意 CreateSandboxParams 的字段名与 upload_file 的参数顺序在不同版本间可能有调整,落地时以官方 SDK 文档为准,用 help() 确认一眼最省事。
步骤 6:收网络策略,防止沙箱乱连
执行不可信代码时,默认应该「断网」。创建沙箱时把出网能力关掉,只放行确实需要的地址:
```python
sandbox = daytona.create(CreateSandboxParams(
snapshot="my-agent-base",
network_block_all=True,
network_allow_list="203.0.113.10/32,198.51.100.0/24", # 仅允许访问这些网段
))
```
这样即使智能体生成的代码里有 curl 外发、pip install 拉包这类动作,也会直接失败,而不是把数据带出去。需要装包时,正确做法是把依赖预先做进快照,而不是在运行时开网。验证策略是否生效:在沙箱里执行 curl -m 5 https://example.com,预期是连接失败或超时;再访问白名单内的地址,预期能通。
步骤 7:配置回收策略
云沙箱按使用时长计费,忘记回收是常见的成本泄漏点。三道防线一起用:
1. 创建时设自动回收:auto_stop_interval 控制空闲多久停机,auto_delete_interval 控制停机多久后彻底删除。
2. 业务侧 try/finally:无论 Agent 是否抛异常,都在 finally 里 sandbox.delete()。
3. 定期巡检:daytona list 拉全量,找出运行时长异常或长期 started 的实例。
```bash
daytona list
daytona delete <sandbox-id>
```
验证部署是否成功
按顺序跑一遍,全部通过说明链路打通:
```bash
1. CLI 可用
daytona version
2. 认证与服务可达(应返回表格而非报错)
daytona list
3. 快照存在且可用
daytona snapshot list
4. 端到端:建沙箱 → 执行 → 销毁
time daytona create --snapshot my-agent-base
daytona ssh <sandbox-id> -- uname -a
daytona delete <sandbox-id>
```
预期结果:第 2、3 步有正常输出;第 4 步能拿到沙箱 ID,uname -a 打印出 Linux 内核信息,删除后 daytona list 里不再出现该实例。time 的输出可以记录冷启动耗时作为基线,通常落在秒级,具体取决于区域、快照大小和节点负载,不必追求某个固定数字。
再跑一遍步骤 5 的 Python 脚本,终端应打印出沙箱 ID、exit: 0 和 main.py 的实际输出。
常见报错与解决
报错:401 Unauthorized 或 failed to connect to Daytona API
→ 原因:API Key 未设置、已失效,或 DAYTONA_API_URL 指向了错误地址(自建场景里很容易漏掉 /api 后缀)。
→ 解决:
```bash
echo $DAYTONA_API_URL $DAYTONA_API_KEY
daytona list # 复测
```
确认无误仍失败,去控制台重新签发一个 Key 再试。
报错:创建沙箱时提示 snapshot not found 或状态不可用
→ 原因:快照还在构建中,或名字拼错,或构建失败留下了半成品。
→ 解决:
```bash
daytona snapshot list
daytona snapshot create my-agent-base --dockerfile ./Dockerfile # 重建
```
等状态变为可用后再 daytona create。
报错:快照构建卡住,日志停在拉取基础镜像
→ 原因:构建节点访问镜像仓库受限,或基础镜像标签写错。
→ 解决:给构建环境配置镜像加速,或先把基础镜像推到你能访问的私有仓库,再把 FROM 改成私有地址。同时精简 Dockerfile,减少不必要的层。
报错:沙箱内 curl 全部超时、pip install 无法联网
→ 原因:这是 network_block_all=True 生效后的正常表现,不是故障。
→ 解决:把需要的依赖预先写进快照;确实要临时放行时,把目标地址加进 network_allow_list 后重建沙箱(网络策略一般在创建时确定,改已有实例通常不生效)。
报错:程序里拿到的沙箱 ID 再去查询时报 not found
→ 原因:自动回收策略到期,实例已被停止或删除。
→ 解决:调大 auto_stop_interval / auto_delete_interval;长任务期间定时发心跳保活;把「沙箱不存在」当作可重试异常,在代码里自动重建。
后续维护
备份:沙箱本身是易失的,别把它当存储用。约定所有产物(生成的代码、测试报告、日志)在任务结束前通过 SDK 下载回本地或对象存储;快照用有语义的标签管理版本,例如 my-agent-base-2024xx,改动 Dockerfile 就发新标签,旧标签保留一段时间便于回滚。自建场景还要定期备份控制面数据库,pg_dump 之类的手段按官方部署文档执行。
升级:CLI 与 SDK 尽量保持同代版本,跨大版本升级前先在测试环境跑一遍步骤 5 的脚本和步骤 6 的网络策略验证,因为参数名和默认行为在版本间会变。自建控制面升级前先备份数据库、读完 release note,采用先升控制面、再升节点的方式滚动进行。
日志与监控:重点盯四个指标——沙箱创建成功率、创建耗时 P95、并发实例数、平均存活时长。前两个反映服务健康,后两个直接对应成本。SDK 调用处统一加日志,记录沙箱 ID、快照名、执行耗时和 exit_code,排障时能一眼定位是环境问题还是代码问题。
安全:沙箱里不放长期凭证,需要访问外部服务时签发短时效 token;默认全量阻断出网,按需开白名单;快照保持最小化,不要把自己公司的内部工具和密钥烤进镜像。做到这三条,即使智能体执行了意料之外的代码,影响范围也被限制在一个随时可以销毁的临时环境里。
