ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Cloudflare Sandbox 完全指南:5 分钟在 Workers 上跑通隔离代码沙箱

Cloudflare Sandbox 完全指南:5 分钟在 Workers 上跑通隔离代码沙箱 Cloudflare Sandbox 完全指南5 分钟在 Workers 上跑通隔离代码沙箱【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skillsCloudflare Sandbox 是跑在 Cloudflare 边缘的沙箱代码执行服务专门解决如何安全地运行不受信任的代码把命令、脚本或服务进程关进隔离容器里执行AI 代码执行、多租户执行、数据分析都能承载。在 Workers 里引入 cloudflare/sandbox SDK 之后一个 fetch handler 就能完成启动沙箱、执行代码、拿到结果的全流程。1. 5 分钟跑通一个 Worker 加两个配置文件跑通只需要三样东西一个最小 Worker、一份 wrangler.jsonc、一个 Dockerfile。架构上每个沙箱由一个 Durable Object可以理解为边缘上带状态的单例负责记住沙箱身份加一个容器组成相同 ID 永远指向同一个沙箱文件、进程、网络都与其他沙箱彻底隔离跨请求持续存活。Worker 里先加两行接线代码import { getSandbox, proxyToSandbox, type Sandbox } from cloudflare/sandbox; export { Sandbox } from cloudflare/sandbox;然后是 fetch handler。注意这里第一行是 proxyToSandbox预览 URL 的请求要靠它转发进沙箱必须最先调用type Env { Sandbox: DurableObjectNamespaceSandbox }; export default { async fetch(request: Request, env: Env): PromiseResponse { const proxied await proxyToSandbox(request, env); if (proxied) return proxied; const sb getSandbox(env.Sandbox, demo); const r await sb.exec(python3 -c print(2 4)); return Response.json({ output: r.stdout }); } };wrangler.jsonc 负责声明容器与 DO 绑定。实例规格 lite / standard / heavy 对应 256MB/0.5vCPU、512MB/1vCPU、1GB/2vCPU默认给的是 lite{ name: my-sandbox-worker, compatibility_date: 2025-01-01, containers: [{ class_name: Sandbox, image: ./Dockerfile, instance_type: lite }], durable_objects: { bindings: [{ class_name: Sandbox, name: Sandbox }] }, migrations: [{ tag: v1, new_sqlite_classes: [Sandbox] }] }Dockerfile 决定容器里能跑什么基于官方镜像装依赖即可。EXPOSE 这一行本地调试离不开生产环境会自动暴露所有端口FROM docker.io/cloudflare/sandbox:latest RUN pip3 install --no-cache-dir pandas numpy EXPOSE 8080 # wrangler dev 需要生产自动暴露部署之后日常操作基本就靠这几条 CLI日志级别和超时阈值还能用 SANDBOX_LOG_LEVEL、SANDBOX_INSTANCE_TIMEOUT_MS 之类的环境变量微调wrangler dev # 本地开发 wrangler deploy # 部署生产 wrangler tail # 实时日志 wrangler containers list # 查看容器状态getSandbox 的全部选项、规格对照和超时默认值都在 configuration.md 里本地跑不通时先翻它。2. 沙箱能替你做什么从不可信代码到多租户场景 A把不可信代码关进 execexec 是沙箱的总入口返回 stdout、stderr、exitCode、success、duration 五个字段。注意命令跑失败不会抛异常只会让 success 变成 false所以每次调用后都要显式看一眼。cwd 指定容器内的工作目录env 是向命令进程注入环境变量的通道也是传密钥的标准姿势stream 配合 onOutput 回调可以边跑边看日志timeout 控制执行上限——默认 120 秒长任务要自己收紧或放宽const r await sb.exec(python3 run.py, { cwd: /workspace/proj, env: { API_KEY: env.OPENAI_KEY }, stream: true, onOutput: (_stream, chunk) console.log(chunk), timeout: 30000 }); if (!r.success) console.error(r.exitCode, r.stderr);文件 API 同样直白writeFile 会自动创建缺失的父目录readFile、listFiles、deleteFile删目录记得传 recursive: true、mkdir、pathExists 各管一段。有一条铁律要记牢只有 /workspace 会持久化写进 /tmp 的数据在休眠唤醒或重启后大概率找不回来gotchas.md 里的 File not persisting 条目说的就是这件事。因为 exec 接收的是 shell 字符串把用户输入直接拼进去就是命令注入。官方推荐的做法是先落盘、再执行// ❌ exec(python3 -c ${userCode})用户输入直接进 shell await sb.writeFile(/workspace/code.py, userCode); // ✅ 先写文件 const r await sb.exec(python3 /workspace/code.py); // ✅ 再执行文件场景 B把容器端口变成带令牌的预览 URL常驻服务不用 exec用 startProcess 起一个后台进程返回 id、pid、command再靠进程句柄上的三种探测等它就绪waitForPort 等端口开始监听、waitForLog 等日志匹配正则、waitForExit 等进程退出。端口监听起来之前千万别急着对外暴露。进程起好之后的管理也齐了listProcesses、getProcess、stopProcess、getProcessLogs。就绪的标准动作是三步——起进程、等端口、再暴露。exposePort 返回的 URL 形如 https://8080-sandbox-xxxx.yourdomain.com里面带着自动生成的令牌每次执行暴露操作令牌都会换拿不到令牌就等于访问不了const p await sb.startProcess(node server.js, { processId: server }); await p.waitForPort(8080); const { url } await sb.exposePort(8080, { hostname: request.hostname });端口管理侧还有 isPortExposed 查询、getExposedPorts 列表、unexposePort 收回。⚠️ 预览 URL 不是调通了 exposePort 就一定能打开四个前提缺一不可绑自定义域名并配好通配 DNS*.yourdomain.com → worker.yourdomain.com不支持 .workers.dev 域名getSandbox 里打开 normalizeId: trueID 会被转成小写fetch handler 的第一行调用 proxyToSandbox()。顺带把 WebSocket 说了握手请求带 Upgrade: websocket 头识别出来之后交给 sb.wsConnect(request, 8080)就能把双向流量代理进容器的 8080 端口想给客户 wss 地址把 exposePort 拿到的 URL 里 https 换成 wss 即可完整写法在 patterns.md 的 WebSocket 小节。把上面这些串起来就是一个交互式开发环境访问 /start 时 exec 装 code-server、startProcess 起在 8080、exposePort 回地址浏览器里直接开一个云端 VS Code——await sb.exec(curl -fsSL https://code-server.dev/install.sh | sh); await sb.startProcess(code-server --bind-addr 0.0.0.0:8080, { processId: vscode }); const { url } await sb.exposePort(8080);场景 C一个沙箱里关住 N 个互不可见的用户多租户靠 Session同一个沙箱里每个会话拥有独立的 shell 状态、环境变量、cwd 和进程命名空间API 面与沙箱完全相同。标准写法是先查、没有再建首次访问创建会话后续直接复用let s; try { s await sb.getSession(userId); } catch { s await sb.createSession({ id: userId, cwd: /workspace/users/${userId} }); } const r await s.exec(echo hi);如果要更强的隔离边界就干脆给每个租户一个独立 sandbox ID——不同沙箱之间文件、进程、网络完全隔离且无法直接通信这是平台级保证不需要你写任何拦截代码。场景 D给 AI Agent 一个带记忆的代码解释器Agent 场景最常用的是 Code Context创建时注入初始变量之后 runCode 可以反复执行变量跨轮次保留上下文里的数据不用每轮重新喂一遍。返回值是富输出结构outputs 数组里每个元素带 typetext / image / html和 content画好的图能作为 image 直接回传给聊天窗口const ctx await sb.createCodeContext({ language: python, variables: { data: [1, 2, 3, 4, 5] } }); const r await ctx.runCode(print(data[0])); // data 依然可用 // r.outputs: [{ type: text | image | html, content }]要泼一盆冷水上下文状态是易失的。容器休眠唤醒后变量会清空Agent 会话一旦跨了容器重启就得重建 context 重新注入变量gotchas.md 里专门列过这一条。场景 E数据落在 R2成本睡得起mountBucket 能把 R2 桶挂成容器里的一个目录挂上去之后就是普通文件路径写进去的内容回落到 R2天然持久化。两个限制要先知道它依赖 FUSE把远端存储映射成本地目录的文件系统机制wrangler dev 本地环境不可用本地调试请换 mock 数据作用域是沙箱级桶内文件对该沙箱的所有会话可见不是单会话私有await sb.mountBucket(env.DATA_BUCKET, /data, { readOnly: false }); await sb.exec(python3 /workspace/process.py, { env: { DATA_DIR: /data/input } });env.DATA_BUCKET 来自 wrangler.jsonc 的 r2_buckets 绑定挂载 → 处理 → 结果回写 R2是数据处理的标准链路。生命周期这边成本旋钮有三个。第一destroy() 立刻终止容器连带清掉文件、进程、会话和已暴露端口。第二keepAlive: true 表示永不休眠代价是必须与 destroy 成对出现——官方解法就是 try/finallyconst sb getSandbox(env.Sandbox, temp, { keepAlive: true }); try { const r await sb.exec(python3 job.py); return r.stdout; } finally { await sb.destroy(); // 漏掉它 容器一直跑、一直计费 }第三sleepAfter默认 10m控制空闲多久后休眠休眠的沙箱在下次请求时自动唤醒冷启动大约 2-3 秒。怕首请求慢在 wrangler.jsonc 里加triggers: { crons: [*/5 * * * *] }scheduled handler 里 exec 一句 echo 就能把热沙箱焐着关键沙箱也可以直接上 keepAlive。3. 线上怎么不出事错误码、重试与密钥管理错误分两层处理方式完全不同。命令级错误不抛异常靠 success: false 显式检查用 exitCode 和 stderr 定位问题SDK 级错误会抛带 error.code 的异常常见的三个FILE_NOT_FOUND路径写错或文件还没建、CONTAINER_NOT_READY容器还在供给首次请求或休眠唤醒后最常见、TIMEOUT超时调整 timeout 或把任务拆开。另外容器供给默认 30 秒、端口就绪默认 90 秒都能用 containerTimeouts 覆盖。针对 CONTAINER_NOT_READY官方给的重试模式是等 2 秒、最多试三次async function execWithRetry(sb, cmd) { for (let i 0; i 3; i) { try { return await sb.exec(cmd); } catch (e) { if (e.code CONTAINER_NOT_READY) { await new Promise(r setTimeout(r, 2000)); continue; } throw e; } } }密钥管理只有一条纪律绝不硬编码。用 wrangler secret put 存一次运行时从 env 读出再经 exec 的 env 选项注入容器进程// ❌ const token ghp_xxx 写死在代码里 await sb.exec(git clone ..., { env: { GIT_TOKEN: env.GITHUB_TOKEN } });4. 生产避坑清单✅ 上线前把这 11 条过一遍每一条都能在 gotchas.md 里找到出处坑后果正确做法keepAlive: true 后忘了 destroy容器无限运行、持续计费try/finally 里调 destroy()数据写进 /tmp 等临时目录休眠唤醒后文件丢失持久文件一律放 /workspace每次请求用 Date.now() 拼 ID每个请求都触发冷启动又慢又贵按用户或业务复用固定 ID中途改动 normalizeId 选项DO ID 的 hash 变了等于换了个沙箱选项写死并全局保持一致本地 wrangler dev 里测 Bucket 挂载FUSE 不可用直接失败本地用 mock 数据上生产再验Dockerfile 漏写 EXPOSE本地 dev 端口 connection refused补上 EXPOSE预览 URL 打不开用户看不到服务逐条核对场景 B 的四个前提冷启动 2-3 秒没人管首请求明显卡顿sleepAfter 复用 Cron 预热 关键沙箱 keepAlive以为代码上下文一直在那容器重启后变量清空Agent 断片唤醒后重建 code context长命令不设 timeout默认 120 秒后抛 TIMEOUT用 timeout 收紧或拆分任务只判 exitCode 不判 success失败被当成功继续跑显式检查 result.success5. 参考索引五个文档各管一段架构总览与核心规则sandbox/README.md完整 API 参考本文代码均出自这里sandbox/api.mdgetSandbox 选项、实例规格与 CLIsandbox/configuration.md工作流合集AI 执行、IDE、WebSocket、CI/CD、多租户sandbox/patterns.md限制表与安全实践sandbox/gotchas.md容器会替你挡住不受信任的代码但 ID 策略、持久路径和 destroy 配对这三件事得你自己盯住。【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表