百炼 Sandbox 踩坑记录:六个读数不能信,两个参数会骗人

这篇是我自己的实践记录,不写成教程。前因是我需要一个跟笔记本架构不同、能整体断网、能休眠、用完就消失的 Linux,让 agent 在里面自己装依赖跑测试。阿里云百炼八月底上线的 Sandbox 看着正合适,bl sandbox 十五条命令管完整生命周期。我开了六台实例,合计活了 648 秒,全部显式删除。下面是我记下来的坑,按踩的顺序。

坑一:不传 --instance-timeout,默认七天

第一条就写它,因为这条最贵。

bl sandbox create --template-id <模版ID>

这样写,请求体里连 timeout 字段都没有,服务端按 604800 秒处理。我专门建了一台验,endAt 减 startedAt 是 604799 秒,整七天。而这产品按小时计费,官方《Sandbox 计费说明》写的是会话运行费基础款 0.156、进阶款 0.312、旗舰款 0.624 元每小时,另有数据保留费 0.0021 元每 GiB 每小时。

好消息是忘删不会无限烧,七天封顶。我现在的习惯是创建命令里永远带 --instance-timeout 300。

坑二:create 的返回里没有寿命字段

三秒返回 state: running,挺爽,但返回体里没有 startedAt 和 endAt。要看什么时候到期得再跑一次 bl sandbox get --sandbox-id <ID> --output json,它比 create 多八个字段。我第一版监控脚本拿 create 的返回做台账,到期时间全是空的。

坑三:pause 之后 state 还是 running

pause 五秒返回 {"paused": true},我以为完事了。结果 get 和 list 都还写着 running。

真正能看出它睡着的只有两处:bl sandbox list --state paused 筛得到它(同时 --state running 筛不到),以及往 envd 发执行请求会拿到 HTTP 500,消息是 "an internal error has occurred. Please retry."。那不是内部错误,是它睡着了。我的轮询脚本在这上面给了半小时假阳性,后来把探活改成打 envd 的 /health。

顺带记三个好的地方:休眠不丢盘,我写的两个文件唤醒后原样在;token 不轮换,连接信息可以存着跨休眠用;resume 把寿命重新给满,endAt 从 09:37:47Z 变成 09:43:00Z,休眠那段时间不吃寿命。

坑四:--deny-out 不收域名,dry-run 也不告诉你

bl sandbox create --template-id <模版ID> --instance-timeout 300 --deny-out example.com

创建直接失败,服务端原文 invalid denyOut entry "example.com": denyOut only supports IP / CIDR, domains are not supported。--allow-out 收域名,--deny-out 只收 IP 和 CIDR,两个参数在 --help 里句式一模一样。

更阴的是 --dry-run 照不出这个错:写命令的 dry-run 会短路不发请求、把请求体摊给你看,摊得整整齐齐一点告警都没有,只有真发出去才知道。另外 --dry-run 只对写命令短路,list、get 这类读命令加了它照样打服务端,加 --verbose 能看见真实 GET。

坑五:封一个 /32 封不住 CDN 域名

我改成封 IP。自己电脑上解析 example.com 是 104.20.23.154,建 /32,服务端接受、回读一致。然后沙箱里 curl -4 https://example.com 拿到 HTTP 200。没封住。

我差点在笔记里写"denyOut 无效"。幸好先补了一台判定臂 --deny-out 0.0.0.0/0,IPv4 全部十秒超时,机制是好的。再开一台把 curl 实际连的地址打出来:

沙箱内 gethostbyname("example.com") = 104.20.23.154   <- 我封的就是这个
curl -4 https://example.com  ->  HTTP 200, remote_ip=172.66.147.243:443, server: cloudflare

解析地址和连接地址不是同一个,俩都在 Cloudflare 池子里。结论只能是:单个 /32 封不住 CDN 域名,要封得封整个前缀,而 CDN 的前缀你未必拿得全。要收紧就走 --allow-out 白名单,注意它会隐式把总开关关掉(只传 --allow-out,回读是 allowInternetAccess: false),这层联动帮助文本里也没有。

断网那臂还有个反直觉的:DNS 照样解析,断的是传输层。沙箱里 getent hosts 出地址不代表能出网,失败形态是 TLS 层 unexpected eof,八到十四毫秒断,第一眼看像证书问题。

坑六:nproc 报 2,实际只有一核

模版写 1 vCPU / 2048 MB。进去 nproc 是 2,os.cpu_count() 是 2,cpu.cfs_quota_us 是 -1 没有硬配额,只有 cpu.shares 12288。内存是硬的,memory.limit_in_bytes 正好 2147483648。

我跑了个忙循环,每进程空转两秒:1 并发 918 万次,2 并发各 466 万和 448 万,4 并发各 235 万上下。总吞吐没随并发涨,真实并行度约等于一核。以后配线程池看模版的 cpuCount,不看容器读数。

零碎的几个

--metadata 传了之后 get 回读是 null,想靠它打标签做批管理的先自己验。--state 不校验取值,拼错返回空数组、退出码 0。实例列表 --limit 上限 50,没有 --all 也没有 --cursor,template list 有 --cursor 但服务端不返回 next cursor,等于也翻不了页。服务端报错是中文的,即使 CLI 配英文,匹配 api_code 更稳:12000082 是运行时不存在,12000094 是模板不存在。退出码 0 成功、1 服务端错误、2 参数校验失败、7 高风险待确认,delete 不带 --yes 就停在 7。

两个不写进结论的观察

白名单那臂 pypi.org 十秒只收到 46.9 MB 里的 957 KB,基线臂同一页面 1.76 秒下完。看着像走了代理,但同一命令在另外两臂分别 3.69 秒和 12 秒超时,每臂只跑一次,没有重复对照,所以我只记观察不下结论。

还有计费那档:官方按三档计价,但全套公开文档没说基础款、进阶款、旗舰款各是多少 vCPU 内存,规格只在另外两页写了 1C2G 和 4C8G 两种,三档对两配置数量都不吻合。所以我这六台 1 vCPU 的实例花了多少钱,我算不出来,也不推。Sandbox 没有专属免费额度,模型 Token 额度不覆盖它,这两句倒是写得明明白白。

核查口径

六台实例都是同一模版起的 1 vCPU / 2048 MB,出网那组每次只改一个参数。时刻一律拿服务端返回的 startedAt 和 endAt 对,因为我这台电脑的系统钟快了约 174 秒,是拿两个站点的 HTTP Date 头校出来的,同一台机器上的时长差才敢直接用。六台合计存活 648 秒,逐台显式删除,删完 bl sandbox list 复查为空,workspace 里原有三个模版一个没动。

值不值得用

需要 root 的活不行,uid 1000、cgroup 只读。域名级封锁不行,deny-out 不收域名。海外节点没有,只有 cn-beijing。Snapshot 先别碰,计费页对它收费但全套文档没有创建入口。免费额度没有。

但它适合我这件事:三秒起一台干净的 x86_64 Linux,境内直连,能整体断网能白名单,休眠不丢盘,一条命令释放,删完 bl sandbox list 是空的。我的 agent 现在在里面跑测试,出了事只影响那台机器。

装是三条命令的事(CLI 安装页,API Key 签发页),bl sandbox official-images 不用鉴权不发请求,先看镜像再决定。模版在控制台建,第一次建弹 SLR 授权 AliyunServiceRoleForSFMSandbox,一次性。

六台实例都释放了,workspace 里原有三个模版一个没动。六个读数不能信、两个参数会骗人,记下来,下次少踩。

posted @ 2026-10-10 14:27  新的白白酱  阅读(16)  评论(0)    收藏  举报