外掛沙箱

本頁內容

沙箱外掛在沙箱執行器提供的隔離執行時中執行。Marketplace 和登錄檔安裝始終在沙箱中執行,emdash() 整合中 sandboxed: [] 下列出的外掛也是如此。plugins: [] 下列出的外掛在伺服器程序中執行,不使用執行器。

執行器取決於部署平台。在 Cloudflare Workers 上,每個外掛作為透過 Worker Loader 繫結建立的 Dynamic Worker 執行。在 Node.js 上,伺服器啟動 workerd(開源 Workers 執行時)作為子程序,並將每個外掛作為其中的服務執行。emdash()sandboxRunner 選項選擇執行器。沒有它,sandboxed: [] 下的外掛永遠不會被載入,配置的 marketplace 會使建置失敗並顯示「Marketplace requires sandboxRunner to be configured」。

下表總結了每個執行器的需求和強制執行的內容。

Cloudflare WorkersNode.js
sandboxRunner@emdash-cms/cloudflaresandbox()"@emdash-cms/sandbox-workerd/sandbox"
要求Workers 付費方案、worker_loaders 繫結、從 Worker 進入點匯出的 PluginBridgeworkerd 套件
資料庫存取DB D1 繫結(與配置的適配器無關)配置的資料庫
強制限制CPU 時間、子請求、牆鐘時間牆鐘時間

Cloudflare Workers

Dynamic Workers 在 Workers 付費方案 中可用。執行器需要以下繫結和進入點匯出;*-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_ENV 設定為 productionnode ./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 秒。當 workerd 在 60 秒內當機超過五次時,執行器停止重啟並記錄 [emdash:workerd] workerd crashed 5 times in 60 seconds, giving up。此後,所有沙箱外掛鉤子和路由都會失敗並顯示 Plugin sandbox unavailable for <plugin>: workerd is not running,直到伺服器重啟。向伺服器傳送 SIGTERM 也會終止 workerd

資源限制

每個執行器對每次外掛呼叫套用相同的限制集。限制是固定的;emdash() 整合沒有相關選項。

限制Cloudflare WorkersNode.js
CPU 時間50 ms由 Worker Loader 強制;外掛達到限制時拋出未強制
子請求10由 Worker 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: [] 下的外掛不會被載入,已安裝的 marketplace 和登錄檔外掛不會執行,從管理後台進行的新安裝會失敗並顯示錯誤碼 SANDBOX_NOT_AVAILABLE。網站的其餘部分不受影響。

在程序內執行沙箱外掛

emdash() 中設定 sandbox: false 以在沒有隔離或限制的情況下在伺服器程序中執行 sandboxed: [] 下的外掛和已安裝的 marketplace 外掛。這是一個除錯選項,用於區分外掛中的錯誤和沙箱中的錯誤。以下配置在 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.jsonc 有一個名為 LOADERworker_loaders 繫結,main 指向匯出 PluginBridge 的檔案。部署繫結需要 Workers 付費方案。

在 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

由於執行器缺失或不可用,管理後台的安裝請求被拒絕。為平台配置執行器,或修復上述啟動警告的原因,然後重新部署。