[PR #210] [MERGED] fix(tools-image): fall back to BusyBox ionice for minimal user images #255

Closed
opened 2026-10-29 14:21:31 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/kvcache-ai/AgentENV/pull/210
Author: @dushulin
Created: 8/24/2026
Status: ✅ Merged
Merged: 9/10/2026
Merged by: @yingdi-shan

Base: main ← Head: feat/tools-image-ionice-fallback


📝 Commits (1)

  • dff156a fix(tools-image): fall back to BusyBox ionice for minimal user images

📊 Changes

2 files changed (+12 additions, -4 deletions)

View changed files

📝 tools-image/Dockerfile (+5 -1)
📝 tools-image/pivot-init (+7 -3)

📄 Description

背景

envd 的进程 wrapper 硬编码调用 /usr/bin/ionice -c 2 -n 4 /usr/bin/nice -n N ...(packages/envd/internal/services/process/handler/handler.go),只要用户 rootfs 里没有 /usr/bin/ionice,每一次进程 spawn 都会立刻失败并报 /usr/bin/ionice: not found。这在 Alpine/musl、distroless、FROM scratch、以及各类不带 util-linux 的 slim 镜像上都能稳定复现——envd 自身能起来,用户在 sandbox 里跑任何命令都会立刻挂掉。

相关上游 issue / PR:

方案

复用现有 nice(1) 兜底思路(tools-image/pivot-init):

  • 在 pivot_root 之后、envd 启动之前,如果用户 rootfs 里没有可执行的 /usr/bin/ionice,就把它软链到 /agentenv/bin/busybox。BusyBox 是 multi-call binary,通过 argv[0]=ionice 直接走 ionice applet。
  • [ ! -x /usr/bin/ionice ] guard 保证自带 util-linux 的镜像原样保留自己的 ionice,不会被覆盖。
  • 同时把 pivot-init 里的注释补上,说明现在同时兜底 nice/ionice。
  • Dockerfile 里补两条 BusyBox applet 断言(nice + ionice),万一以后 upstream BusyBox 改默认配置或有人重编 BusyBox,能在镜像构建阶段就报错,不至于到 guest 里才发现。

与 util-linux ionice 的能力对齐

envd 调用的形式是 ionice -c 2 -n 4 <cmd>,用到的是 -c/-n 以及 exec 新进程的能力。BusyBox 的 ionice applet 覆盖 -c/-n/-p/-t 与 exec 语义,与 util-linux 落到同一个 ioprio_set(2) syscall,语义完全一致。util-linux 独有的 -P PGID、-u UID envd 用不到;如果 sandbox 内部用户脚本自己在 fallback 镜像里手动调这两个 flag 会拿到 unknown option,这跟现有 nice fallback 面临的情况完全对称。

兼容性

  • 自带 util-linux 的镜像(大多数发行版基础镜像):[ ! -x ] guard 短路,/usr/bin/ionice 保留镜像原有实现,零回退。
  • 缺 ionice 的镜像(Alpine/musl/distroless 等):拿到 BusyBox 的 ionice,envd 能正常 spawn。
  • pivot-init 在每次 boot 都会跑一遍,symlink 是幂等的,pause/resume 或 snapshot 提交后 symlink 会跟着上层写走。

Test plan

  • docker build tools-image/ 通过,BusyBox applet 断言不报错
  • 用一个不带 util-linux 的 Alpine-based 用户镜像启动 sandbox,ionice -c 2 -n 4 echo ok 通过 envd wrapper 能正常输出 ok
  • 用一个自带 util-linux 的镜像启动 sandbox,readlink /usr/bin/ionice 仍指向镜像原有二进制(不是 /agentenv/bin/busybox)
  • envd 的 process spawn 端到端在两种镜像上都正常,echo $? 返回 0

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/kvcache-ai/AgentENV/pull/210 **Author:** [@dushulin](https://github.com/dushulin) **Created:** 8/24/2026 **Status:** ✅ Merged **Merged:** 9/10/2026 **Merged by:** [@yingdi-shan](https://github.com/yingdi-shan) **Base:** `main` ← **Head:** `feat/tools-image-ionice-fallback` --- ### 📝 Commits (1) - [`dff156a`](https://github.com/kvcache-ai/AgentENV/commit/dff156abaf3ac33c692f2d26533194186f1941d8) fix(tools-image): fall back to BusyBox ionice for minimal user images ### 📊 Changes **2 files changed** (+12 additions, -4 deletions) <details> <summary>View changed files</summary> 📝 `tools-image/Dockerfile` (+5 -1) 📝 `tools-image/pivot-init` (+7 -3) </details> ### 📄 Description ## 背景 envd 的进程 wrapper 硬编码调用 `/usr/bin/ionice -c 2 -n 4 /usr/bin/nice -n N ...`(`packages/envd/internal/services/process/handler/handler.go`),只要用户 rootfs 里没有 `/usr/bin/ionice`,每一次进程 spawn 都会立刻失败并报 `/usr/bin/ionice: not found`。这在 Alpine/musl、distroless、`FROM scratch`、以及各类不带 util-linux 的 slim 镜像上都能稳定复现——envd 自身能起来,用户在 sandbox 里跑任何命令都会立刻挂掉。 相关上游 issue / PR: - e2b-dev/infra#3597 — Alpine 模板构建失败,缺 `/usr/bin/ionice` 和 `/usr/bin/nice` - e2b-dev/infra#3598 — 修复 Alpine/musl 缺失时的 symlink - e2b-dev/infra#2681 — envd 引入 I/O 优先级,是 hardcode ionice 的源头 ## 方案 复用现有 `nice(1)` 兜底思路(`tools-image/pivot-init`): - 在 pivot_root 之后、envd 启动之前,如果用户 rootfs 里没有可执行的 `/usr/bin/ionice`,就把它软链到 `/agentenv/bin/busybox`。BusyBox 是 multi-call binary,通过 `argv[0]=ionice` 直接走 `ionice` applet。 - `[ ! -x /usr/bin/ionice ]` guard 保证自带 util-linux 的镜像原样保留自己的 `ionice`,不会被覆盖。 - 同时把 pivot-init 里的注释补上,说明现在同时兜底 `nice`/`ionice`。 - Dockerfile 里补两条 BusyBox applet 断言(`nice` + `ionice`),万一以后 upstream BusyBox 改默认配置或有人重编 BusyBox,能在镜像构建阶段就报错,不至于到 guest 里才发现。 ## 与 util-linux ionice 的能力对齐 envd 调用的形式是 `ionice -c 2 -n 4 <cmd>`,用到的是 `-c`/`-n` 以及 exec 新进程的能力。BusyBox 的 ionice applet 覆盖 `-c`/`-n`/`-p`/`-t` 与 exec 语义,与 util-linux 落到同一个 `ioprio_set(2)` syscall,语义完全一致。util-linux 独有的 `-P PGID`、`-u UID` envd 用不到;如果 sandbox 内部用户脚本自己在 fallback 镜像里手动调这两个 flag 会拿到 unknown option,这跟现有 `nice` fallback 面临的情况完全对称。 ## 兼容性 - 自带 util-linux 的镜像(大多数发行版基础镜像):`[ ! -x ]` guard 短路,`/usr/bin/ionice` 保留镜像原有实现,零回退。 - 缺 ionice 的镜像(Alpine/musl/distroless 等):拿到 BusyBox 的 ionice,envd 能正常 spawn。 - pivot-init 在每次 boot 都会跑一遍,symlink 是幂等的,pause/resume 或 snapshot 提交后 symlink 会跟着上层写走。 ## Test plan - [x] `docker build tools-image/` 通过,BusyBox applet 断言不报错 - [ ] 用一个不带 util-linux 的 Alpine-based 用户镜像启动 sandbox,`ionice -c 2 -n 4 echo ok` 通过 envd wrapper 能正常输出 `ok` - [ ] 用一个自带 util-linux 的镜像启动 sandbox,`readlink /usr/bin/ionice` 仍指向镜像原有二进制(不是 `/agentenv/bin/busybox`) - [ ] envd 的 process spawn 端到端在两种镜像上都正常,`echo $?` 返回 0 --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-29 14:21:31 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
kvcache-ai/AgentENV#255
No description provided.