跳转到内容
搜索文档

Durable Object Container

最后更新 查看 MarkdownAgent 设置

描述

每个 container 由 Durable Object 管理。Container 来自 @cloudflare/containers,扩展 DurableObject 并为您处理生命周期管理、端口就绪和休眠超时。Durable Object 管理路由、持久状态和生命周期钩子,而 container 进程在 Linux VM 内运行您的镜像。

本页记录的底层 API 在具有 container 绑定(binding)的任何 Durable Object 类内的 this.ctx.container 上可用。当您需要对 container 进程进行直接控制或无法使用 Container 类时使用它。

由于 Container 类扩展 DurableObject,您还可以通过 this.ctx.storage 访问 SQLite storagealarms 以及所有其他 Durable Object API。

index.jsjs
export class MyDurableObject extends DurableObject {
	constructor(ctx, env) {
		super(ctx, env);

		// boot the container when starting the DO
		this.ctx.blockConcurrencyWhile(async () => {
			this.ctx.container.start();
		});
	}
}
index.tsts
export class MyDurableObject extends DurableObject {
	constructor(ctx: DurableObjectState, env: Env) {
		super(ctx, env);

    	// boot the container when starting the DO
    	this.ctx.blockConcurrencyWhile(async () => {
    		this.ctx.container.start();
    });
    }

}

属性

running

running 在 container 当前正在运行时返回 true。它不保证 container 已完全启动并准备好接受请求。

	this.ctx.container.running;

方法

start

start 启动 container。此方法在 container 完全启动前不会阻塞。 您可能希望在使用 container 之前确认其已准备好接受请求。

this.ctx.container.start({
	env: {
		FOO: "bar",
	},
	enableInternet: false,
	entrypoint: ["node", "server.js"],
});

参数

  • options(可选):包含以下属性的对象:
    • env:包含要传递给 container 的环境变量的对象。这对于向 container 传递配置值或密钥很有用。
    • entrypoint:表示要在 container 中运行的命令的字符串数组。
    • enableInternet:指示是否为 container 启用互联网访问的布尔值。

返回值

  • 无。

exec

exec 在已在运行的 Container 内启动另一个进程。它不会启动已停止的 Container。

以下示例在扩展 @cloudflare/containersContainer 的类内调用 this.ctx.container.exec()。在 RPC 方法中,检查 this.ctx.container.running,并在需要时调用 await this.start()。您也可以使用 onStart() 钩子,在 Container 每次启动时运行一系列命令。

exec(
  cmd: string[],
  options?: ContainerExecOptions,
): Promise<ExecProcess>

exec 操作直接以提供的参数启动可执行文件。它不会启动 shell,也不会解释管道、重定向、展开或其他 shell 语法。当镜像中存在 Bash 时,使用 ["bash", "-lc", "<COMMAND>"] 显式调用 Bash。对于仅有 Portable Operating System Interface (POSIX) shell 的镜像,使用 ["sh", "-c", "<COMMAND>"]

以下 RPC 方法在执行命令前启动 Container:

import { Container } from "@cloudflare/containers";

export class MyContainer extends Container {
	async runCommand() {
		if (!this.ctx.container.running) {
			await this.start();
		}

		const process = await this.ctx.container.exec(["node", "--version"]);
		const output = await process.output();

		return {
			pid: process.pid,
			exitCode: output.exitCode,
			stdout: new TextDecoder().decode(output.stdout),
		};
	}
}
import { Container } from "@cloudflare/containers";

export class MyContainer extends Container {
	async runCommand() {
		if (!this.ctx.container.running) {
			await this.start();
		}

		const process = await this.ctx.container.exec(["node", "--version"]);
		const output = await process.output();

		return {
			pid: process.pid,
			exitCode: output.exitCode,
			stdout: new TextDecoder().decode(output.stdout),
		};
	}
}

参数

  • cmdstring[])— 可执行文件及其参数。
  • optionsContainerExecOptions,可选)— 进程配置:
    • stdinReadableStream | "pipe")— 标准输入的来源。使用 "pipe" 可通过返回的 stdin 流写入。省略时,标准输入关闭并发送 end-of-file (EOF)。
    • stdout"pipe" | "ignore",默认 "pipe")— 捕获或丢弃标准输出。
    • stderr"pipe" | "ignore" | "combined",默认 "pipe")— 捕获、丢弃,或将标准错误合并到标准输出。"combined" 值需要 stdout: "pipe"。合并输出不保证其源流之间的顺序。
    • cwdstring)— 进程的工作目录。
    • envRecord<string, string>)— 环境变量的添加与覆盖。进程继承现有的 Container 变量。匹配的键使用每次执行的值。
    • userstring)— 进程使用的镜像用户。

返回值

返回 Promise<ExecProcess>

ExecProcess 具有以下字段和方法:

  • stdinWritableStream | null)— 当 stdin"pipe" 时可写的标准输入。
  • stdoutReadableStream | null)— 管道时可读的标准输出。
  • stderrReadableStream | null)— 单独管道时可读的标准错误。
  • pidnumber)— 进程标识符。
  • exitCodePromise<number>)— 进程退出时解析。非零退出码正常解析,而不是拒绝。
  • output()Promise<ExecOutput>)— 一次性读取缓冲输出。ExecOutput 包含 stdoutArrayBuffer)、stderrArrayBuffer)和 exitCodenumber)。被忽略的流产生空缓冲区。使用 TextDecoder 解码文本。
  • kill(signal?: number)void)— 为进程排队一个信号。默认为 SIGTERM,信号 15。信号必须在 164 之间。

使用 stderr: "combined" 时,ExecProcess 上的 stderrnullExecOutput 上为空 ArrayBuffer。从 stdout 读取两个输出通道。

output() 被多次调用,或在任一可读流开始被消费后调用时,会抛出 TypeError。对于大型输出,请并发消费两个可读流,而不是用 output() 缓冲它们。

exec 没有内置超时。使用 kill() 请求终止,然后通过 exitCode 观察完成。进程可以处理或忽略信号,因此这不会强制硬截止时间。不要从信号推断特定的退出码。

异常

  • 当 Container 未运行时,exec() 会抛出异常。
  • cmd 为空、选项模式无效,或在 stdout: "ignore" 时使用 stderr: "combined" 时,exec() 会抛出 TypeError
  • 若运行时无法创建或启动进程,exec() 会拒绝。
  • 环境变量名称不能包含 = 或空字符。环境值、cwduser 不能包含空字符。
  • 当信号超出支持范围时,kill() 会抛出 RangeError

面向任务的示例请参阅 Execute commands

destroy

destroy 停止 container,并可选地向 monitor() 错误回调返回自定义错误消息。

this.ctx.container.destroy("Manually Destroyed");

参数

  • error(可选):将发送到 monitor 方法错误处理程序的字符串。这对于日志记录或调试很有用。

返回值

  • 在 container 被销毁后返回的 promise。

signal

signal 向 container 发送 IPC 信号,例如 SIGKILL 或 SIGTERM。这对于优雅或强制停止 container 很有用。

const SIGTERM = 15;
this.ctx.container.signal(SIGTERM);

参数

  • signal:表示要发送给 container 的信号的数字。通常是 POSIX 信号编号,例如 SIGTERM (15) 或 SIGKILL (9)。

返回值

  • 无。

getTcpPort

getTcpPort 返回 container 的一个 TCP 端口。这可用于通过 TCP 和 HTTP 与 container 通信。

const port = this.ctx.container.getTcpPort(8080);
const res = await port.fetch("http://container/set-state", {
	body: initialState,
	method: "POST",
});
const conn = this.ctx.container.getTcpPort(8080).connect("10.0.0.1:8080");
await conn.opened;

try {
	if (request.body) {
		await request.body.pipeTo(conn.writable);
	}
	return new Response(conn.readable);
} catch (err) {
	console.error("Request body piping failed:", err);
	return new Response("Failed to proxy request body", { status: 502 });
}

参数

  • port(number):用于与 container 通信的 TCP 端口号。

返回值

  • TcpPort:表示 TCP 端口的 TcpPort 对象。此对象可用于通过 TCP 和 HTTP 向 container 发送请求。

monitor

monitor 返回一个 promise,在 container 退出时解析,在 container 出错时出错。这对于在 Workers 代码中设置回调以处理 container 状态更改很有用。

class MyContainer extends DurableObject {
	constructor(ctx, env) {
		super(ctx, env);
		function onContainerExit() {
			console.log("Container exited");
		}

		// the "err" value can be customized by the destroy() method
		async function onContainerError(err) {
			console.log("Container errored", err);
		}

		this.ctx.container.start();
		this.ctx.container.monitor().then(onContainerExit).catch(onContainerError);
	}
}

参数

返回值

  • 在 container 退出时解析的 promise。

interceptOutboundHttp

interceptOutboundHttp 将匹配主机名、主机名 glob、IP 地址、IP:port 或 CIDR 范围的出站 HTTP 请求通过 WorkerEntrypoint 路由。可在启动 container 之前或之后调用。打开的连接会采用新处理程序而不会被丢弃。

const worker = this.ctx.exports.MyWorker({ props: { message: "hello" } });

// Match a specific hostname
this.ctx.container.interceptOutboundHttp("api.example.com", worker);

// Match a hostname glob pattern
this.ctx.container.interceptOutboundHttp("*.example.com", worker);

// Match an IP:port
await this.ctx.container.interceptOutboundHttp("15.0.0.1:80", worker);

// Match a CIDR range (IPv4 and IPv6)
await this.ctx.container.interceptOutboundHttp("123.123.123.123/23", worker);

参数

  • target(string):要匹配的主机名、主机名 glob(例如 *.example.com)、IP 地址、IP:port 或 CIDR 范围。
  • worker(WorkerEntrypoint):用于处理匹配请求的 WorkerEntrypoint 实例。

返回值

  • 无。

interceptAllOutboundHttp

interceptAllOutboundHttp 将 container 的所有出站 HTTP 请求(无论目标如何)通过 WorkerEntrypoint 路由。

await this.ctx.container.interceptAllOutboundHttp(worker);

参数

  • worker(WorkerEntrypoint):用于处理所有出站 HTTP 请求的 WorkerEntrypoint 实例。

返回值

  • 在拦截规则安装完成后解析的 promise。

interceptOutboundHttps

interceptOutboundHttps 将匹配主机名或主机名 glob 的出站 HTTPS 请求通过 WorkerEntrypoint 路由。工作方式与 interceptOutboundHttp 相同,但针对 HTTPS 流量。container 必须信任 /etc/cloudflare/certs/cloudflare-containers-ca.crt 处的 CA 证书,HTTPS 拦截才能工作。

支持 glob 模式,其中 * 匹配任意字符序列。

const worker = this.ctx.exports.MyWorker({ props: {} });

// Match a specific hostname
this.ctx.container.interceptOutboundHttps("api.example.com", worker);

// Match a hostname glob pattern
this.ctx.container.interceptOutboundHttps("*.example.com", worker);

// Intercept all HTTPS traffic
this.ctx.container.interceptOutboundHttps("*", worker);

参数

  • target(string):要匹配的主机名或主机名 glob 模式。使用 * 拦截所有 HTTPS 流量。
  • worker(WorkerEntrypoint):用于处理匹配请求的 WorkerEntrypoint 实例。

返回值

  • 无。

相关资源

这篇文档对您有帮助吗?