プラグインサンドボックス

このページ

サンドボックスプラグインは、サンドボックスランナーが提供する分離されたランタイムで実行されます。マーケットプレイスとレジストリのインストールは常にサンドボックスで実行され、emdash() インテグレーションの sandboxed: [] にリストされたプラグインも同様です。plugins: [] にリストされたプラグインはサーバープロセスで実行され、ランナーを使用しません。

ランナーはデプロイメントプラットフォームに依存します。Cloudflare Workersでは、各プラグインはWorker Loaderバインディングを通じて作成される Dynamic Worker として実行されます。Node.jsでは、サーバーがオープンソースのWorkersランタイムである workerd を子プロセスとして起動し、各プラグインをその中のサービスとして実行します。emdash()sandboxRunner オプションでランナーを選択します。これがないと、sandboxed: [] のプラグインはロードされず、設定された marketplace は「Marketplace requires sandboxRunner to be configured」でビルドを失敗させます。

以下の表は、各ランナーが必要とするものと適用するものをまとめています。

Cloudflare WorkersNode.js
sandboxRunner@emdash-cms/cloudflaresandbox()"@emdash-cms/sandbox-workerd/sandbox"
要件Workers Paidプラン、worker_loaders バインディング、Workerエントリポイントからエクスポートされた PluginBridgeworkerd パッケージ
データベースアクセスDB D1バインディング(設定されたアダプターに依存しない)設定されたデータベース
適用される制限CPU時間、サブリクエスト、ウォールタイムウォールタイム

Cloudflare Workers

Dynamic Workersは Workers Paidプラン で利用できます。ランナーには以下のバインディングとエントリポイントエクスポートが必要です。*-cloudflare テンプレートには両方が含まれています。

  1. Worker Loaderバインディングを wrangler.jsonc に追加します。ランナーは LOADER という名前で読み取ります:

    {
    	"worker_loaders": [
    		{
    			"binding": "LOADER",
    		},
    	],
    }
  2. Workerエントリポイントから PluginBridge をエクスポートし、main をそのファイルに向けます。PluginBridge はサンドボックスプラグインがコンテンツ、メディア、ストレージ、メールにアクセスするためのエントリポイントです。ランナーはエントリモジュールのエクスポートからこれを検索します:

    import handler, { createScheduledHandler, PluginBridge } from "@emdash-cms/cloudflare/worker";
    
    export { PluginBridge };
    
    export default {
    	...handler,
    	scheduled: createScheduledHandler(),
    } satisfies ExportedHandler;
    {
    	"main": "./src/worker.ts",
    }
  3. emdash() インテグレーションでランナーを選択します:

    import { d1, r2, sandbox } from "@emdash-cms/cloudflare";
    
    emdash({
    	database: d1({ binding: "DB" }),
    	storage: r2({ binding: "MEDIA" }),
    	sandboxRunner: sandbox(),
    });

Node.js

  1. ピア依存関係である workerd とともにランナーをインストールします:

    npm install @emdash-cms/sandbox-workerd workerd

    workerd パッケージは、オプショナル依存関係を通じて現在のプラットフォーム(x64のLinux、macOS、Windows、arm64のLinuxおよびmacOS)用のバイナリをインストールします。サーバーが実行されるプラットフォームで、オプショナル依存関係を有効にしてインストールしてください。マルチステージDockerビルドでは、ランタイムステージと同じプラットフォームのステージでインストールを実行してください。

  2. emdash() インテグレーションでランナーを選択します:

    import { sqlite } from "emdash/db";
    
    emdash({
    	database: sqlite({ url: "file:./data/emdash.db" }),
    	sandboxRunner: "@emdash-cms/sandbox-workerd/sandbox",
    });
  3. 開発用に、miniflare を開発依存関係としてインストールします:

    npm install -D miniflare

    NODE_ENVdevelopmentastro dev が設定)で miniflare がインストールされている場合、ランナーはプラグインをMiniflareに渡し、Miniflareが自身の workerd プロセスを管理します。以下のクラッシュポリシーは適用されません。astro previewNODE_ENVproduction に設定し、node ./dist/server/entry.mjs は未設定のままにします。両方とも workerd を使用します。

workerd プロセスの動作方法

EmDashはサイトへの最初のリクエスト時の初期化中に workerd を起動し、サンドボックスプラグインがロードされた後、プラグインサービスが応答するまで最大10秒待ちます。管理画面からプラグインのインストールまたは更新を行うと再起動されます。workerd がstdoutまたはstderrに書き出すすべてのものは、[emdash:workerd] プレフィックス付きでサーバーの出力に表示されます。

プラグインサービスは 127.0.0.1 でリッスンし、サーバーへの戻りチャネルはUnixドメインソケット(Windowsでは 127.0.0.1 TCPポート)です。インバウンドポートを開く必要はありません。

子プロセスはサーバーの環境から PATHHOMETMPDIRTMPTEMPLANGLC_ALL のみを受け取るため、サーバー環境のシークレットはサンドボックスに入りません。より多くの変数を渡すには、EMDASH_WORKERD_PASSTHROUGH_ENV をカンマ区切りの変数名リストに設定してください。

workerd が予期せず終了した場合、ランナーは [emdash:workerd] workerd exited with <reason> をログに記録し、次の呼び出し時に再起動します。遅延は1秒から始まり、30秒まで倍増します。60秒以内に workerd が5回以上クラッシュした場合、ランナーは再起動を停止し、[emdash:workerd] workerd crashed 5 times in 60 seconds, giving up をログに記録します。それ以降、サーバーが再起動されるまで、すべてのサンドボックスプラグインフックとルートは Plugin sandbox unavailable for <plugin>: workerd is not running で失敗します。サーバーへの SIGTERMworkerd も終了させます。

リソース制限

各ランナーはプラグイン呼び出しごとに同じ制限セットを適用します。制限は固定されており、emdash() インテグレーションにはそれらのオプションはありません。

制限Cloudflare WorkersNode.js
CPU時間50 msWorker Loaderが適用;プラグインは制限に達するとスローする適用されない
サブリクエスト10Worker Loaderが適用;プラグインは制限に達するとスローする適用されない
メモリ128 MBプラグインごとには適用されない;プラットフォームのアイソレートメモリ上限が適用適用されない
ウォールタイム30 sランナーが適用ランナーが適用

フックまたはルートがウォールタイム制限を超えた場合、呼び出しは Plugin <id> exceeded wall-time limit of 30000ms during hook:<name>(または route:<name>)で失敗します。フックの場合、EmDashは EmDash: Sandboxed plugin <id> プレフィックスで失敗をログに記録し、そのプラグインの結果なしでリクエストを続行します。制限を超えたプラグインルートは呼び出し元に対して失敗します。

ランナーが利用できない場合

設定されたランナーでも利用できない場合があります:Cloudflare Workersで worker_loaders バインディングまたは PluginBridge エクスポートが欠落している場合、Node.jsで workerd がインストールされていないかそのバイナリが実行されない場合です。EmDashはランタイム起動時に以下の警告をログに記録します:

EmDash: Plugin sandbox is configured but not available on this platform. Sandboxed plugins will not be loaded. If using @emdash-cms/sandbox-workerd/sandbox, ensure workerd is installed.

sandboxed: [] のプラグインはロードされず、インストール済みのマーケットプレイスおよびレジストリプラグインは実行されず、管理画面からの新規インストールはエラーコード SANDBOX_NOT_AVAILABLE で失敗します。サイトの残りの部分は影響を受けません。

サンドボックスプラグインをインプロセスで実行する

emdash()sandbox: false を設定すると、sandboxed: [] のプラグインとインストール済みのマーケットプレイスプラグインを、分離や制限なしでサーバープロセスで実行します。これはプラグインのバグとサンドボックスのバグを区別するためのデバッグオプションです。以下の設定はNode.jsサイトでサンドボックスをオフにします:

emdash({
	sandboxRunner: "@emdash-cms/sandbox-workerd/sandbox",
	sandbox: false,
});

Cloudflare Workersでは、ランタイムは sandbox: false is not supported in Cloudflare Workers で起動を拒否します。

トラブルシューティング

各エントリは、サーバーがログに記録するメッセージ、または管理画面が返すエラーコードで始まります。

“Plugin sandbox is configured but not available on this platform”

Cloudflare Workersでは、両方の要件を確認してください:wrangler.jsoncLOADER という名前の worker_loaders バインディングがあること、mainPluginBridge をエクスポートするファイルを指していること。バインディングのデプロイにはWorkers Paidプランが必要です。

Node.jsでは、ランナーが使用するバイナリを実行します:

npx workerd --version

コマンドが失敗した場合、workerdnode_modules にないか、インストールされたバイナリがこのプラットフォームで実行されません。ターゲットプラットフォームでオプショナル依存関係を有効にして再インストールしてください。

“workerd failed to start within 10 seconds”

子プロセスは起動しましたが、そのプラグインサービスが10秒以内に応答しませんでした。このメッセージの前の [emdash:workerd] プレフィックス付きの行には、設定エラーや起動エラーを含む workerd 自体の出力が含まれています。ランナーは次の呼び出し時に再試行します。

“workerd crashed 5 times in 60 seconds, giving up”

ランナーは workerd の再起動を停止しました。このメッセージの前の [emdash:workerd] workerd exited with <reason> 行は、各クラッシュの終了コードまたはシグナルを示します。原因を修正してからサーバーを再起動してください。

プラグインインストール時の SANDBOX_NOT_AVAILABLE

ランナーが欠落しているか利用できないため、管理画面のインストールリクエストが拒否されました。プラットフォーム用にランナーを設定するか、上記の起動警告の原因を修正して再デプロイしてください。