跳转到内容
本站为社区维护的非官方中文翻译,与 Cloudflare, Inc. 无关联。本站不提供账户登录,请勿在任何非官方站点输入您的 Cloudflare 账户信息。官方文档:developers.cloudflare.com

@cloudflare/sandbox

最后更新 查看 MarkdownAgent 设置

@cloudflare/sandbox 配合你从 Durable Object 启动的容器使用。其类通过 exec() 在正在运行的容器中运行辅助进程。该包不会启动、停止或监视容器。

有关容器本身的 start()、exec()、快照以及其他方法,请参阅 Durable Object container API。

安装

npm i @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-shim

    helper 是静态链接的 linux/amd64 二进制。它可以在任何 linux/amd64 镜像中运行。

  • Worker 启用了 nodejs_compat compatibility flag。该包通过 node:os 读取 Linux 错误名称。

  • 当某个方法运行该辅助程序时,容器正在运行。类页面会列出无需运行它的方法,例如 DirectoryBackup.delete()。

示例配置

此配置满足全部要求。Dockerfile 将 helper 复制到带有 Node.js 24 的 Debian Trixie 镜像中,sleep infinity 使容器保持运行:

Dockerfiledockerfile
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 镜像,并将容器传给该包中的类:

src/index.jsjs
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");
	}
}
src/index.tsts
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。

类

这篇文档对您有帮助吗?