@cloudflare/sandbox 配合你从 Durable Object 启动的容器使用。其类通过 exec() 在正在运行的容器中运行辅助进程。该包不会启动、停止或监视容器。
有关容器本身的 start()、exec()、快照以及其他方法,请参阅 Durable Object container API。
npm i @cloudflare/sandboxyarn add @cloudflare/sandboxpnpm add @cloudflare/sandboxbun add @cloudflare/sandbox该包中的每个类都有这些要求。类页面会列出其他额外要求。
-
容器镜像在
/usr/local/bin/sandbox-shim包含 helper 二进制。请从与已安装@cloudflare/sandbox版本匹配的cloudflare/sandbox镜像复制:COPY --from=docker.io/cloudflare/sandbox:<VERSION> /usr/local/bin/sandbox-shim /usr/local/bin/sandbox-shimhelper 是静态链接的
linux/amd64二进制。它可以在任何linux/amd64镜像中运行。 -
Worker 启用了
nodejs_compatcompatibility flag。该包通过node:os读取 Linux 错误名称。 -
当某个方法运行该辅助程序时,容器正在运行。类页面会列出无需运行它的方法,例如
DirectoryBackup.delete()。
此配置满足全部要求。Dockerfile 将 helper 复制到带有 Node.js 24 的 Debian Trixie 镜像中,sleep infinity 使容器保持运行:
FROM node:24-trixie-slim
COPY --from=docker.io/cloudflare/sandbox:1.0.1 /usr/local/bin/sandbox-shim /usr/local/bin/sandbox-shim
RUN mkdir /workspace
CMD ["sleep", "infinity"]Wrangler 配置设置 nodejs_compat,将 Dockerfile 构建为名为 workspace 的镜像,并将 MyContainer 声明为 Durable Object 类:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "sandbox-files",
"main": "src/index.ts",
"upload_source_maps": true,
// Set this to today's date
"compatibility_date": "2026-11-14",
"compatibility_flags": ["nodejs_compat"],
"containers": [
{
"class_name": "MyContainer",
"scheduling_policy": "durable_object",
"images": {
"workspace": {
"dockerfile": "./Dockerfile",
},
},
},
],
"durable_objects": {
"bindings": [
{
"class_name": "MyContainer",
"name": "MY_CONTAINER",
},
],
},
"exports": {
"MyContainer": {
"type": "durable-object",
"storage": "sqlite",
},
},
}"$schema" = "node_modules/wrangler/config-schema.json"
name = "sandbox-files"
main = "src/index.ts"
upload_source_maps = true
# Set this to today's date
compatibility_date = "2026-11-14"
compatibility_flags = [ "nodejs_compat" ]
[[containers]]
class_name = "MyContainer"
scheduling_policy = "durable_object"
[containers.images.workspace]
dockerfile = "./Dockerfile"
[[durable_objects.bindings]]
class_name = "MyContainer"
name = "MY_CONTAINER"
[exports.MyContainer]
type = "durable-object"
storage = "sqlite"Durable Object 启动 workspace 镜像,并将容器传给该包中的类:
import { Files } from "@cloudflare/sandbox";
import { DurableObject } from "cloudflare:workers";
const INACTIVITY_TIMEOUT_MS = 10 * 60 * 1000;
export class MyContainer extends DurableObject {
container;
files;
constructor(ctx, env) {
super(ctx, env);
const container = ctx.container;
if (!container) {
throw new Error("No container is configured");
}
this.container = container;
// ctx.container stays the same object while the Durable Object runs.
this.files = new Files(container);
// A restarted Durable Object sets the timeout again.
if (container.running) {
void ctx.blockConcurrencyWhile(() =>
container.setInactivityTimeout(INACTIVITY_TIMEOUT_MS),
);
}
}
async listWorkspace() {
// Files does not start the container.
if (!this.container.running) {
this.container.start({
image: this.container.images.workspace,
enableInternet: false,
});
await this.container.setInactivityTimeout(INACTIVITY_TIMEOUT_MS);
}
return this.files.readDirectory("/workspace");
}
}import { Files } from "@cloudflare/sandbox";
import { DurableObject } from "cloudflare:workers";
const INACTIVITY_TIMEOUT_MS = 10 * 60 * 1000;
export class MyContainer extends DurableObject<Env> {
private readonly container: Container;
private readonly files: Files;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
const container = ctx.container;
if (!container) {
throw new Error("No container is configured");
}
this.container = container;
// ctx.container stays the same object while the Durable Object runs.
this.files = new Files(container);
// A restarted Durable Object sets the timeout again.
if (container.running) {
void ctx.blockConcurrencyWhile(() =>
container.setInactivityTimeout(INACTIVITY_TIMEOUT_MS),
);
}
}
async listWorkspace() {
// Files does not start the container.
if (!this.container.running) {
this.container.start({
image: this.container.images.workspace,
enableInternet: false,
});
await this.container.setInactivityTimeout(INACTIVITY_TIMEOUT_MS);
}
return this.files.readDirectory("/workspace");
}
}有关构建镜像的更多信息,请参阅 images。