这篇不写体验流水账。我把一台云端沙箱实例从上到下拆成三层,每层给出我量到的边界和踩到的坑:控制面管什么、运行时怎么接、计费口径怎么进预算说明。对象先钉死:阿里云百炼在 2026 年 8 月 26 日上线的 Sandbox,bl sandbox 底下一十五条命令。它不是 coding CLI 里那个本地 sandbox 开关,也不是函数计算那条线的云沙箱,更不是容器计算服务的 Agent Sandbox,这几套价目互不通用,文中出现的每个价格数字只出自百炼自己那页《Sandbox 计费说明》。
环境:Node.js 18+,npm install -g bailian-cli,bl skill init,bl auth login --api-key sk-你的key(API Key、CLI 安装)
一、控制面:十五条命令,两个 ID,一个返回陷阱
控制面只管建模版、起实例、断网、休眠、释放。get 和 connect 都只返回连接信息,不开 shell,命令组里没有 bl sandbox exec 这种东西。这层分工决定了封装位置:做统一网关的话,控制面调用可以直接走 CLI 或 HTTP,运行时那一跳得单独实现,而且它不走 REST 风格。
两个 ID 要分清。sandboxID 带 sbx- 前缀,是后续所有命令和运行时域名要用的那个;bailianSandboxId 是平台内部 ID,拿它去拼域名会失败。资产台账里写错一个字段,排查成本是一次线上事故。
返回陷阱在字段不全。create 的返回里没有 startedAt 和 endAt,要看寿命得再取一次详情。get 比 create 多吐八个字段:startedAt、endAt、lifecycle、cpuCount、memoryMB、allowInternetAccess、network、metadata。做实例到期监控的话,数据源只能是 get。
模版这层我只用 dry-run 摊请求体,没有真建。建模版会留下持久资源,删它属于高风险操作要逐次确认:
css
bl sandbox template create --name my-python --image code-interpreter --cpu-count 1 --memory-mb 2048 --dry-run --output json
控制台建模版只有两种规格:配置 1(1 Core|2 GB,推荐)和配置 2(4 Core|8 GB),挂载本地文件最多 5 个。内置三个镜像 code-interpreter、browser、all-in-one,版本都是 :v0.0.44。看镜像清单这条命令不要鉴权、不发请求、离线能跑:
bl sandbox official-images
二、运行时:Connect 协议封装,不是普通 JSON POST
真正的执行走 envd 的运行时接口。拿 envdUrl 加 envdAccessToken,POST 到 /process.Process/Start,请求体要用 Connect 协议的流式封装:1 字节 flags、4 字节大端长度、再加 JSON。直接发普通 JSON POST 打不通。事件还包一层 {"event": {...}} 外层,我第一版解析器少剥了这层,拿到一串空结果,以为实例没起来。先打 /health,回 {"status":"ok"} 就是活的。
取 token 要加 --show-credentials,会明文打印 envd 和 traffic 两个 token。我不在文章里给这个参数的示例,你也别让它进 shell 历史、CI 日志或者提交进仓库的文件。我的做法是重定向到 umask 077 的临时目录,脚本从文件读,用完删。
这层对无人值守长程任务是必要的:边界焊在平台侧,实例里的代码动不了它。容器内没有 ip 也没有 iptables,登录用户是 uid 1000 的 user 而不是 root,cgroup 只读挂载,进程改不了自己的资源限额。
三、出网策略:五臂单变量对照
同一个模版、同一规格,只改出网参数,开了五台做单变量对照。三条对接入方有直接影响的结论。
第一,传 --allow-out 等于把总开关关掉再只放行你列的那些。帮助文本里没写这层联动,我是从 get 的回读里看出来的:只传 --allow-out,回读却是 allowInternetAccess: false。
第二,--allow-out 收域名,--deny-out 只收 IP 和 CIDR。传域名会被服务端拒掉,原文是 denyOut only supports IP / CIDR, domains are not supported。而 --dry-run 照不出这个错:写命令的 dry-run 会短路不发请求,读命令加了它照样打服务端,核对参数时这一点要留意。
第三,用一个 /32 封不住 CDN 域名。我封的 104.20.23.154 正是沙箱内解析到的地址,curl 却拿到 200。补一台判定臂 --deny-out 0.0.0.0/0,IPv4 全部十秒超时,机制本身没问题,问题在粒度。把实际连接地址打出来才看得清:
bash
curl -4 -w '%{remote_ip}' https://example.com
# HTTP 200 remote_ip=172.66.147.243:443 server: cloudflare
解析地址不等于连接地址,两个都在 Cloudflare 的地址池里。要收紧出网走 --allow-out 白名单这条路,别指望 --deny-out 做域名级封锁。
还有一个意外收获:断网之后平台自动往白名单塞了两个内网 OSS 域,*.oss-cn-hangzhou-internal.aliyuncs.com 和 *.oss-cn-beijing-internal.aliyuncs.com。"断网"不是字面意义的全断,跟内网对象存储的通路留着。
断网臂的失败形态也值得记:不是干净的 connection refused,是 TLS 层一个 unexpected eof,八到十四毫秒就断,第一眼看很像证书问题。判据只看 TCP 和 TLS 建不建得起来,DNS 在断网状态下照样解析出地址。
四、编排风险点:pause 之后 state 仍是 running
pause 五秒返回 {"paused": true},resume 三秒返回新的连接信息。休眠不丢盘,我写在 /tmp/marker.txt 和 /home/user/work/note.txt 的两个文件唤醒后原样在;连接信息也不轮换,envdAccessToken 与 envdUrl 前后一致,脚本可以存着跨休眠周期用;resume 还会把寿命重新给满,我这台原本 endAt 是 09:37:47Z,resume --instance-timeout 900 之后变成 09:43:00Z,休眠那段时间不吃寿命。
风险在状态字段:pause 之后 get 和 list 都还写着 running。能看出它已经休眠的只有两处,bl sandbox list --state paused 能筛到它(同时 --state running 筛不到),以及这时候往 envd 发执行请求会拿到 HTTP 500,消息是 "an internal error has occurred. Please retry."。那不是内部错误,是它睡着了。
对编排系统的含义很具体:任何靠轮询 state 判断实例可用性的调度器,在休眠这条路上会给出假阳性。探活要打在 envd 的 /health 上,或者用 --state paused 过滤。两个连带项:--state 不校验取值,bl sandbox list --state bogus-state 返回空数组、退出码 0,拼错一个字母就会以为自己没有运行中的实例;实例列表也翻不了页,list 的 --limit 上限 50,既没有 --all 也没有 --cursor,规模上去之后资产盘点得换路子。
五、资源口径:控制面写的和容器里看到的不是一个数
模版写 1 vCPU / 2048 MB,进去看 nproc 是 2,cpu.cfs_quota_us 是 -1(没有硬配额),只有 cpu.shares 12288 这个权重;内存那边 memory.limit_in_bytes 是 2147483648,正好 2048 MB,卡得死死的。忙循环对照下来,2 并发时每个进程掉到约一半,4 并发时掉到约四分之一,总吞吐没有随并发上升,真实可用并行度约等于一核,跟控制面的 cpuCount: 1 对得上,跟容器里的 nproc 对不上。容量规划以模版字段为准,容器里看到的核数是宿主机漏进来的。
六、计费口径:三档小时价,和一个官方没填的空
会话运行费基础款 0.156 元每小时、进阶款 0.312、旗舰款 0.624;数据保留费 0.0021 元每 GiB 每小时,暂停和 Snapshot 都算。运行中的实例含 15 GiB 系统盘不另收费,这句原文限定的是运行中的实例。官方自己举的例子:进阶款跑 40 加 20 分钟、暂停两小时占 8 GiB、Snapshot 6 GiB 留三小时,合计 0.3834 元;算例里的会话运行费只算了 40 加 20 分钟,暂停那两小时不算运行费,只算保留费。所以休眠省的是运行费,不是全部。
预算说明里要写清的空缺有四处。计费页按三档计价,但整套 Sandbox 公开文档没有任何一处说明基础款、进阶款、旗舰款各是多少 vCPU 和内存;这三个词只出现在计费页,规格只在快速开始和模版管理两页出现,三档对两配置,数量都对不上,我不做任何映射推断。Sandbox 也没有专属免费额度,模型 Token 免费额度不覆盖它。出账周期和不足一秒怎么进位,这一页没写。Snapshot 会计数据保留费,但整套文档没有任何创建和管理它的入口,十五条命令里也没有,这是个悬空的计费项。
还有一条默认值要写进操作规范:不传 --instance-timeout,请求体里根本不带 timeout 字段,服务端按 604800 秒处理,整七天。我专门建了一台不传这个参数的实例验过,endAt 减 startedAt 是 604799 秒。忘删的实例不会无限烧,七天封顶,但七天也不短。我现在的习惯是创建命令里永远带 --instance-timeout,演示用 300。
七、接入路径与退出码
装起来就是环境行里那三条命令,official-images 不要鉴权、不发请求、离线就能跑,先看一眼三个镜像再决定要不要往下走。模版要在控制台的 Sandbox 页建,第一次建会弹服务关联角色授权,角色名 AliyunServiceRoleForSFMSandbox,一次性完成,注意弹窗出现在建模版时而不是建实例时,想跳过控制台直接拿 API Key 起实例的自动化流程得先确认账号早就授权过了。
退出码这套是清楚的:0 成功,1 服务端错误,2 客户端参数校验失败,7 高风险待确认;delete 不带 --yes 会直接停在 7。参数校验也做得挺前置,--instance-timeout 要在 300 到 604800 之间,--cpu-count 得是正整数,这些在本地就拦下来了,不用等服务端报错。
用"文件、网络、权限、资源"这四问去量它,前三问都能给出干脆的读数。第四问的答案在账单里,不在文档里;而这一点对做预算的人恰恰最要紧。