预热模板服务
普通模板可以预装系统和依赖,但应用仍可能在每次沙箱启动后执行耗时初始化,例如加载 SDK、创建 Agent 会话、扫描工作区或建立本地缓存。CubeSandbox 可以等待应用完成这些工作后再制作模板快照,使后续沙箱从已初始化的内存和进程状态恢复。
本文以 examples/pi-agent-integration 为例,介绍如何设计和制作预热模板。开始前建议先阅读模板概览,了解探针如何决定制作快照的时机。
工作原理
预热模板的关键是让应用提供一个准确的就绪端点:
- 镜像启动常驻服务。
- 服务完成需要预热的初始化工作。
- 初始化完成后,就绪端点才返回 HTTP 2xx。
- CubeSandbox 探测到成功响应,保存此时的文件系统、内存和进程状态。
- 从模板创建沙箱时,常驻服务随快照恢复,可以直接处理请求。
就绪端点不应在 HTTP 服务器刚开始监听时就返回成功。应先返回 503,直到所有需要保存在快照中的状态都已准备完成。
Pi Agent 预热示例
Pi Agent 的普通运行方式会为每个任务启动新进程。示例中的 warmup adapter 则作为镜像的常驻进程,在启动阶段创建一个 Pi SDK AgentSession。只有会话初始化完成后,GET /readyz 才返回 200。
1. 准备常驻服务
示例实现位于 pi_warmup_adapter.mjs。其核心逻辑可以概括为:
let ready = false;
const server = http.createServer((request, response) => {
if (request.method === "GET" && request.url === "/readyz") {
response.writeHead(ready ? 200 : 503);
return response.end();
}
// 处理恢复后的业务请求。
});
session = await createAgentSession(/* ... */);
ready = true;
server.listen(8080, "0.0.0.0");实际示例还提供 POST /prompt,用于向恢复后的常驻 AgentSession 发送任务。
2. 将常驻服务设为镜像命令
Dockerfile.warmup 基于已安装 Pi Agent 的镜像,复制 adapter,并将其设为镜像的 CMD:
ARG PI_AGENT_IMAGE=pi-agent-cube:latest
FROM ${PI_AGENT_IMAGE}
COPY pi_warmup_adapter.mjs /tmp/pi_warmup_adapter.mjs
RUN PI_PACKAGE_DIR="$(npm root -g)/@earendil-works/pi-coding-agent" \
&& install -m 0755 /tmp/pi_warmup_adapter.mjs \
"${PI_PACKAGE_DIR}/pi_warmup_adapter.mjs" \
&& rm /tmp/pi_warmup_adapter.mjs
ENV PI_WARMUP_HOST=0.0.0.0 \
PI_WARMUP_PORT=8080
EXPOSE 49983 8080
CMD ["sh", "-c", "exec node \"$(npm root -g)/@earendil-works/pi-coding-agent/pi_warmup_adapter.mjs\""]端口 8080 提供应用就绪检查和任务接口;49983 由基础镜像中的 envd 使用,以保留 SDK 的命令、文件和终端能力。
3. 构建并推送镜像
在仓库根目录先构建基础镜像,再构建 warmup 镜像:
docker build --platform linux/amd64 \
-t localhost:5000/pi-agent-cube:latest \
examples/pi-agent-integration
docker build --platform linux/amd64 \
-f examples/pi-agent-integration/Dockerfile.warmup \
--build-arg PI_AGENT_IMAGE=localhost:5000/pi-agent-cube:latest \
-t localhost:5000/pi-agent-warmup-cube:latest \
examples/pi-agent-integration
docker push localhost:5000/pi-agent-cube:latest
docker push localhost:5000/pi-agent-warmup-cube:latest请将示例地址替换为 CubeSandbox 集群能够访问的镜像仓库。
4. 使用应用探针制作模板
创建模板时暴露 envd 和 warmup adapter 的端口,但将探针指向真正代表 Pi 会话初始化完成的 /readyz:
cubemastercli tpl create-from-image \
--image localhost:5000/pi-agent-warmup-cube:latest \
--alias pi-warmup \
--writable-layer-size 4G \
--expose-port 49983 \
--expose-port 8080 \
--probe 8080 \
--probe-path /readyz这里不能使用 49983/health 作为预热完成信号:它只能说明 envd 已经就绪,不能说明 Pi AgentSession 已创建完成。而是应当等待 /readyz 就绪,此时所有的服务才均已启动完成。
设计自己的预热服务
将同一模式应用到其他服务时,请遵循以下原则:
- 探测真实的预热状态。 完成模型加载、运行时初始化或缓存构建后,再让就绪端点返回 2xx。
- 保持进程常驻。 完成初始化的进程必须继续运行,才能随内存快照一起恢复。
- 不要把密钥写入模板。 构建期间不要注入 API Key、令牌或用户数据;应在沙箱恢复后通过请求、密钥保险柜或其他运行时机制提供。
- 谨慎处理外部连接。 数据库连接、长连接和临时凭证在恢复时可能已失效。恢复后应检测并重建这类连接,而不是假设快照中的连接仍可使用。
- 明确并发模型。 Pi 示例中的一个 adapter 只维护一个 session,并发任务返回 HTTP 409。需要并发时,应实现连接池、会话池,或让每个沙箱只处理一个任务。
- 保持就绪检查轻量。 探针应只读取本地状态,不应重复执行昂贵初始化或产生外部副作用。
排查问题
| 现象 | 检查项 |
|---|---|
| 模板构建一直等待探针 | 确认服务监听 0.0.0.0、端口和路径匹配,并查看初始化日志。 |
| 模板 READY,但应用首次请求仍需初始化 | 就绪端点返回过早;将 ready 状态设置移到完整初始化之后。 |
| SDK 命令或文件 API 不可用 | 确认镜像包含 envd,并通过 --expose-port 49983 暴露其端口。 |
| 恢复后外部请求失败 | 检查快照前建立的连接或凭证是否过期,并在恢复后重新建立。 |
完整 Pi Agent 的构建、调用和网络策略示例见 examples/pi-agent-integration/README_zh.md。