各 コンテナ は Durable Object が管理します。@cloudflare/containers の Container クラス は DurableObject を拡張し、ライフサイクル管理、ポートの準備完了、スリープタイムアウトを代わりに処理します。Durable Object がルーティング、永続状態、ライフサイクルフックを管理し、コンテナプロセスは Linux VM 内でイメージを実行します。
このページで説明する低レベル API は、コンテナバインディングを持つ任意の Durable Object クラス内の this.ctx.container で使えます。コンテナプロセスを直接制御したい場合や、Container クラスを使えない場合に使います。
Container クラスは DurableObject を拡張するため、this.ctx.storage 経由の SQLite ストレージ、Alarms、そのほかすべての Durable Object API にもアクセスできます。
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();
});
}
}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 は、コンテナが現在実行中なら true を返します。コンテナが完全に起動し、リクエストを受け付けられる状態であることまでは保証しません。
this.ctx.container.running;start はコンテナを起動します。このメソッドは、コンテナが完全に起動するまでブロックしません。
使う前に、コンテナがリクエストを受け付けられる状態かを確認するとよいです。
this.ctx.container.start({
env: {
FOO: "bar",
},
enableInternet: false,
entrypoint: ["node", "server.js"],
});options(任意): 次のプロパティを持つオブジェクトです。env: コンテナへ渡す環境変数を含むオブジェクトです。設定値やシークレットをコンテナへ渡すときに使います。entrypoint: コンテナ内で実行するコマンドを表す文字列の配列です。enableInternet: コンテナのインターネットアクセスを有効にするかどうかを示す boolean です。
- なし。
exec は、すでに実行中の Container 内で別プロセスを開始します。停止中の Container は起動しません。
次の例は、@cloudflare/containers の Container を拡張したクラス内で this.ctx.container.exec() を呼び出します。RPC メソッドでは this.ctx.container.running を確認し、必要なら await this.start() を呼び出します。Container が起動するたびに一連のコマンドを実行するには、onStart() フックも使えます。
exec(
cmd: string[],
options?: ContainerExecOptions,
): Promise<ExecProcess>exec 操作は、渡した引数で実行ファイルを直接開始します。シェルは起動せず、パイプ、リダイレクト、展開、そのほかのシェル構文も解釈しません。イメージに Bash がある場合は、["bash", "-lc", "<COMMAND>"] で明示的に Bash を呼び出します。Portable Operating System Interface(POSIX)シェルだけのイメージでは ["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),
};
}
}cmd(string[])— 実行ファイルとその引数です。options(ContainerExecOptions、任意)— プロセスの設定です。stdin(ReadableStream | "pipe")— 標準入力のソースです。返されるstdinストリーム経由で書き込むには"pipe"を使います。省略すると、標準入力は閉じて EOF(end-of-file)を送ります。stdout("pipe" | "ignore"、既定は"pipe")— 標準出力をキャプチャするか破棄します。stderr("pipe" | "ignore" | "combined"、既定は"pipe")— 標準エラーをキャプチャ、破棄、または標準出力へマージします。"combined"にはstdout: "pipe"が必要です。結合した出力は、元ストリーム間の順序を保証しません。cwd(string)— プロセスの作業ディレクトリです。env(Record<string, string>)— 環境変数の追加と上書きです。プロセスは既存の Container 変数を継承します。同じキーは実行ごとの値を使います。user(string)— プロセスに使うイメージユーザーです。
Promise<ExecProcess> を返します。
ExecProcess には次のフィールドとメソッドがあります。
stdin(WritableStream | null)—stdinが"pipe"のときの書き込み可能な標準入力です。stdout(ReadableStream | null)— パイプしているときの読み取り可能な標準出力です。stderr(ReadableStream | null)— 別途パイプしているときの読み取り可能な標準エラーです。pid(number)— プロセス識別子です。exitCode(Promise<number>)— プロセス終了時に解決します。ゼロ以外のコードも reject せず、通常どおり解決します。output()(Promise<ExecOutput>)— バッファした出力を一度読みます。ExecOutputにはstdout(ArrayBuffer)、stderr(ArrayBuffer)、exitCode(number)が含まれます。無視したストリームは空のバッファになります。テキストへデコードするにはTextDecoderを使います。kill(signal?: number)(void)— プロセスへシグナルをキューします。既定はSIGTERM(シグナル15)です。シグナルは1から64である必要があります。
stderr: "combined" のとき、ExecProcess の stderr は null、ExecOutput では空の ArrayBuffer です。両方の出力チャネルは stdout から読みます。
output() を 2 回以上呼ぶか、いずれかの読み取りストリームの消費を始めたあとに呼ぶと、TypeError を投げます。大きな出力では、output() でバッファせず、両方の読み取りストリームを同時に消費してください。
exec に組み込みのタイムアウトはありません。終了を依頼するには kill() を使い、完了は exitCode で確認します。プロセスはシグナルを処理または無視できるため、これは厳しい期限にはなりません。シグナルから特定の終了コードを推測しないでください。
- Container が実行中でないとき、
exec()は例外を投げます。 cmdが空、オプションのモードが無効、またはstderr: "combined"をstdout: "ignore"と組み合わせたとき、exec()はTypeErrorを投げます。- ランタイムがプロセスを作成または開始できない場合、
exec()は reject します。 - 環境変数名に
=またはヌル文字は使えません。環境変数の値、cwd、userにヌル文字は使えません。 - シグナルが対応範囲外のとき、
kill()はRangeErrorを投げます。
作業向けの例は コマンドを実行する を参照してください。
destroy はコンテナを停止し、任意で monitor() のエラーコールバックへカスタムエラーメッセージを返します。
this.ctx.container.destroy("Manually Destroyed");error(任意):monitorメソッドのエラーハンドラーへ送る文字列です。ログやデバッグに使えます。
- コンテナが破棄されたときに解決する Promise です。
signal はコンテナへ IPC シグナル(SIGKILL や SIGTERM など)を送ります。コンテナを穏やかに、または強制的に止めるときに使います。
const SIGTERM = 15;
this.ctx.container.signal(SIGTERM);signal: コンテナへ送るシグナルを表す数値です。通常は POSIX シグナル番号で、SIGTERM(15)や SIGKILL(9)などです。
- なし。
getTcpPort はコンテナの TCP ポートを返します。TCP と HTTP でコンテナと通信できます。
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): コンテナとの通信に使う TCP ポート番号です。
TcpPort: TCP ポートを表すTcpPortオブジェクトです。TCP と HTTP でコンテナへリクエストを送れます。
monitor は、コンテナが終了すると解決し、コンテナがエラーになるとエラーになる Promise を返します。Workers コードでコンテナの状態変化を扱うコールバックを設定するときに使えます。
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);
}
}- なし
- コンテナが終了したときに解決する Promise です。
interceptOutboundHttp は、ホスト名、ホスト名グロブ、IP アドレス、IP:ポート、または CIDR 範囲に一致する送信 HTTP リクエストを WorkerEntrypoint 経由でルーティングします。コンテナの起動前でも起動後でも呼び出せます。開いている接続は切られず、新しいハンドラーを取り込みます。
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): 照合するホスト名、ホスト名グロブ(例:*.example.com)、IP アドレス、IP:ポート、または CIDR 範囲です。worker(WorkerEntrypoint): 一致するリクエストを処理するWorkerEntrypointインスタンスです。
- なし。
interceptAllOutboundHttp は、宛先に関係なく、コンテナからの送信 HTTP リクエストをすべて WorkerEntrypoint 経由でルーティングします。
await this.ctx.container.interceptAllOutboundHttp(worker);worker(WorkerEntrypoint): すべての送信 HTTP リクエストを処理するWorkerEntrypointインスタンスです。
- インターセプトルールがインストールされたときに解決する Promise です。
interceptOutboundHttps は、ホスト名またはホスト名グロブに一致する送信 HTTPS リクエストを WorkerEntrypoint 経由でルーティングします。動作は interceptOutboundHttp と同じで、対象は HTTPS トラフィックです。HTTPS インターセプトを動かすには、コンテナが /etc/cloudflare/certs/cloudflare-containers-ca.crt の CA 証明書を信頼する必要があります。
グロブパターンに対応しており、* は任意の文字シーケンスに一致します。
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): 照合するホスト名またはホスト名グロブパターンです。すべての HTTPS トラフィックをインターセプトするには*を使います。worker(WorkerEntrypoint): 一致するリクエストを処理するWorkerEntrypointインスタンスです。
- なし。
- Container クラスリファレンス — このインターフェイスの上に作られた、推奨の高レベル API
- Containers の概要
- Containers を始める
- SQLite ストレージ API — コンテナ再起動をまたいで状態を永続化します
- Durable Objects — Containers を支える基盤プラットフォーム