> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-TW/llms.txt # 部署至 Sandbox `@mastra/deployer-sandbox` 會將包含 Studio 的完整 Mastra 伺服器部署至暫時性的 Workspace Sandbox,並傳回可用的公開 URL。由於部署器會略過相依性安裝,重複部署可以更快完成。 Sandbox 部署適用於: - Agent 建置的應用程式:Agent 產生 Mastra 專案並部署,以驗證結果。 - 持續整合(CI):啟動實際伺服器執行檢查,完成後再將其關閉。 - 即時預覽:合併前與團隊分享可運作的 Agent。 - 多租戶不受信任程式碼:執行與基礎架構隔離的個別使用者 Mastra 執行個體。 Sandbox 有供應商強制規定的 runtime 上限,且會過期。正式環境代管請參閱[部署概覽](https://mastra.zisheng.pro/zh-TW/docs/deployment/overview)。 ## 支援的 Sandbox 部署器可搭配任何支援網路功能(公開連接埠 URL)的 Workspace Sandbox: - [Vercel Sandbox](https://mastra.zisheng.pro/zh-TW/reference/workspace/vercel-sandbox) (`@mastra/vercel`) - [E2B](https://mastra.zisheng.pro/zh-TW/reference/workspace/e2b-sandbox) (`@mastra/e2b`) - [Daytona](https://mastra.zisheng.pro/zh-TW/reference/workspace/daytona-sandbox) (`@mastra/daytona`) 供應商作者可在 [`WorkspaceSandbox`](https://mastra.zisheng.pro/zh-TW/reference/workspace/sandbox) 上實作選用的 `networking` 能力,以加入支援。 ## 快速開始 安裝部署器與你選擇的 Sandbox Provider。此範例使用 Vercel Sandbox: **npm**: ```bash npm install @mastra/deployer-sandbox @mastra/vercel ``` **pnpm**: ```bash pnpm add @mastra/deployer-sandbox @mastra/vercel ``` **Yarn**: ```bash yarn add @mastra/deployer-sandbox @mastra/vercel ``` **Bun**: ```bash bun add @mastra/deployer-sandbox @mastra/vercel ``` 在 `src/mastra/index.ts` 檔案中設定部署器。`sandboxName` 用來識別部署,因此後續使用相同名稱的部署會重複使用現有 Sandbox。 ```typescript import { Mastra } from '@mastra/core/mastra' import { SandboxDeployer } from '@mastra/deployer-sandbox' import { VercelSandbox } from '@mastra/vercel' export const mastra = new Mastra({ deployer: new SandboxDeployer({ sandbox: new VercelSandbox({ sandboxName: 'my-preview', timeout: 2_400_000, // 40 minutes ports: [4111], }), }), }) ``` Vercel 有兩項特定需求: - `timeout` 不得超過方案的 Sandbox 最長存續時間;Pro 方案為 45 分鐘。更高的值會讓部署收到 Vercel API 的 400 回應而失敗。 - 在 `ports` 中宣告伺服器連接埠。與 E2B 和 Daytona 不同,Vercel 只會公開建立時宣告的連接埠。 使用一個指令完成建置與部署: ```bash mastra build ``` 設定 `SandboxDeployer()` 後,`mastra build` 會打包專案並部署至 Sandbox。部署會印出 API 與 Studio URL,並將 `sandbox-deployment.json` manifest 寫入 `.mastra/output`: ```text API: https://-4111.vercel.run/api Studio: https://-4111.vercel.run ``` Sandbox Provider 回報到期時間時,manifest 會包含 `expiresAt`。 重新部署至同一個 Sandbox 時,若輸入未變更,便會略過相依性安裝。這些輸入包括 `package.json`、打包的 lockfile 及安裝指令。 ### URL 提供的內容 Studio URL 是不含 `/api` 的 Sandbox 根目錄。在瀏覽器中開啟即可使用 Studio。以 `studio: false` 執行部署時,根目錄會改為提供 Mastra 歡迎頁面。 API URL 只是其下方端點的前置路徑,例如 `/api/agents`。`/api` 本身沒有 handler,因此即使伺服器狀態正常,在瀏覽器中開啟仍會傳回「Not Found」回應。 若要檢查部署,請直接呼叫端點: ```bash curl -s -X POST https://4111-.e2b.app/api/agents/weatherAgent/generate \ -H "Content-Type: application/json" \ -d '{"messages":[{"role":"user","content":"Weather in London"}]}' | jq -r '.text' ``` ### Provider 認證資訊 每個 Provider 都使用各自的認證資訊進行驗證。請設定部署目標 Sandbox 所需的值: ```bash # E2B E2B_API_KEY= # Daytona DAYTONA_API_KEY= # Vercel VERCEL_TOKEN= VERCEL_TEAM_ID= VERCEL_PROJECT_ID= ``` 每個 Provider 也接受以建構函式選項傳入這些值。自行代管的 E2B 與 Daytona 安裝會接受 `E2B_DOMAIN` 或 `DAYTONA_API_URL`。 與 `mastra dev` 不同,`mastra build` 不會載入 `.env` 檔案。部署發生於建置期間,因此從環境讀取認證資訊的 Sandbox Provider(例如使用 `E2B_API_KEY` 的 E2B)會讀到空值,導致部署因驗證錯誤而失敗。 在 `src/mastra/index.ts` 加入 `import 'dotenv/config'` 無法解決此問題。為了找出部署器,建置流程只會從進入檔案擷取 `deployer` 選項,並透過 tree-shaking 移除其他所有內容,包括該匯入。 請在執行建置前,將 `.env` 檔案載入 shell 環境。[`dotenv-cli`](https://www.npmjs.com/package/dotenv-cli) 是其中一種方式: **npm**: ```bash npm install --save-dev dotenv-cli ``` **pnpm**: ```bash pnpm add --save-dev dotenv-cli ``` **Yarn**: ```bash yarn add --dev dotenv-cli ``` **Bun**: ```bash bun add --dev dotenv-cli ``` ```json { "scripts": { "deploy": "dotenv -e .env -- mastra build" } } ``` 接著執行 `npm run deploy`。由於設定 `SandboxDeployer()` 後,`mastra build` 就會進行部署,因此 script 名稱應反映其用途。請將它與一般的 `build` script 分開,以免代管平台或 CI 工作執行 `npm run build` 時意外部署 Sandbox。 在持續整合(CI)中,請改為將認證資訊匯出為 secret。無論採用何種機制,變數都必須存在於 shell 環境中,而不能只存在 `.env` 檔案內。 以上適用於部署器在本機所需的認證資訊。已部署伺服器所需的變數會分開處理:部署器會讀取 `.env`、`.env.production` 及 `.env.local`,並將其注入 Sandbox。請參閱[安全性](#security)。 ### 使用 E2B 對 E2B 而言,`id` 用來識別部署,因此後續使用相同值的部署會重新連線至現有 Sandbox,無論它正在執行或暫停。 ```typescript import { SandboxDeployer } from '@mastra/deployer-sandbox' import { E2BSandbox } from '@mastra/e2b' const deployer = new SandboxDeployer({ sandbox: new E2BSandbox({ id: 'my-preview', template: 'base', timeout: 3_600_000, // 1 hour }), }) ``` 除非需要掛載檔案系統,否則請傳入 `template: 'base'`;若未傳入,Provider 會在首次使用時建置自訂的 Filesystem in Userspace(FUSE)template。E2B 會暫停而非停止:`stop()` 會建立整部虛擬機器(VM)的快照,包括記憶體與執行中的處理程序。暫停的 Sandbox 喚醒後,Mastra 伺服器會從原處繼續執行,不需要像 Vercel 一樣重新啟動。 ### 使用 Daytona 對 Daytona 而言,`id` 用來識別部署,因此後續使用相同值的部署會重新連線至現有 Sandbox。設定 `public: true`,讓預覽 URL 無須 token 即可存取。 ```typescript import { SandboxDeployer } from '@mastra/deployer-sandbox' import { DaytonaSandbox } from '@mastra/daytona' const deployer = new SandboxDeployer({ sandbox: new DaytonaSandbox({ id: 'my-preview', public: true, autoStopInterval: 30, // minutes }), }) ``` 停止 Daytona Sandbox 會保留檔案系統,但不保留執行中的處理程序,因此喚醒方式與 Vercel 相同:resolver 會在 `wake: true` 時重新啟動伺服器。 Daytona 會依目的地篩選對外流量。對某些主機的要求能正常透過 Transport Layer Security(TLS)連線,其他則會在交握期間重設,在 Agent 或 Tool 中顯示為 Node 的一般 `fetch failed`。除錯前,先從 Sandbox 內對相同主機執行 `curl`,以排除程式碼問題: ```typescript const sandbox = new DaytonaSandbox({ id: 'my-preview' }) await sandbox.start() const result = await sandbox.executeCommand('curl -v --max-time 10 https://api.example.com') console.info(result.stdout, result.stderr) ``` TLS 交握期間出現 `Connection reset by peer`,表示問題在於篩選,而不是 Agent。請要求 Daytona 支援團隊允許該目的地。受限制的 Daytona 方案也會封鎖雲端儲存端點,掛載 helper 會以專用錯誤回報此情況。 ## 以程式部署 `deployToSandbox()` 不經 bundler,直接部署預先建置的輸出目錄。與 `SandboxDeployer()` 不同,除非傳入 `studio: true`,否則不會包含 Studio。請在 CI 或 Agent 程式碼中使用: ```typescript import { deployToSandbox } from '@mastra/deployer-sandbox' import { VercelSandbox } from '@mastra/vercel' const deployment = await deployToSandbox({ sandbox: new VercelSandbox({ sandboxName: 'ci-smoke', ports: [4111] }), dir: '.mastra/output', }) console.info(deployment.url) // https://-4111.vercel.run await deployment.logs() // tail the server log await deployment.stop() // stop the sandbox (resumable) await deployment.destroy() // permanently delete the sandbox ``` ## 生命週期 ### 管理部署 使用 `@mastra/deployer-sandbox/client` 僅供伺服器使用的 `getDeployment()` export,取得現有部署。它會透過 Provider 特有的設定識別 Sandbox,例如 Vercel `sandboxName`,或 E2B、Daytona 的 `id`。查詢不會綁定建立部署的處理程序,因此可從其他伺服器端服務或 CI 使用。 ```typescript import { getDeployment } from '@mastra/deployer-sandbox/client' import { VercelSandbox } from '@mastra/vercel' const deployment = await getDeployment({ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }), port: 4111, }) console.info(deployment.status, deployment.url) await deployment.logs() // tail the server log await deployment.stop() // stop the sandbox (resumable) await deployment.destroy() // permanently delete the sandbox ``` 傳入 `wake: true`,可在傳回前繼續已停止的 Sandbox。只有繼續後伺服器狀態不正常時,才會重新啟動伺服器。Provider Tool 也能使用,例如 `vercel sandbox ls`、`vercel sandbox stop` 及 `vercel sandbox rm`。 ### 到期與 URL Sandbox 會依 Provider 的 runtime 限制到期。Provider 回報到期時間時,部署會記錄該時間,並透過 `deployment.expiresAt` 供程式存取。 Sandbox 停止再繼續時,URL 可能變更。請將 URL 視為連線細節,並將 Sandbox 識別資訊(例如 `sandboxName`)視為穩定控制碼。下列路由層級會處理 URL 輪替。 ## 路由層級 ### 第 1 層:直接 URL 開發、示範與 CI 可直接使用印出的 URL,前提是每次部署使用全新 URL 沒有問題。 ### 第 2 層:在 runtime 解析 `getDeployment()` 會在 runtime 解析目前 URL,讓使用端不會持有過期 URL。任何知道 Sandbox 名稱的伺服器都能解析,包括與 Mastra 專案位於不同程式碼庫的伺服器: ```typescript import { getDeployment } from '@mastra/deployer-sandbox/client' import { VercelSandbox } from '@mastra/vercel' const deployment = await getDeployment({ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }), wake: true, }) console.info(deployment.url, deployment.status) ``` 使用 `wake: false`(預設值)時,不會啟動 Sandbox,而會取得 `{ url, status }` 以便採取動作。解析 URL、`stop()` 與 `destroy()` 都會依名稱附加至現有 Sandbox,不會將其繼續,因此針對已停止 Sandbox 的生命週期操作絕不會喚醒它或開始計費。使用 `wake: true` 時,Sandbox 會繼續;若伺服器未回應,則會重新啟動。是否需要重新啟動取決於 Provider:Vercel 與 Daytona 會還原檔案系統,但不還原執行中的處理程序;E2B 則會繼續包含伺服器處理程序的整部 VM。 > **警告:** `@mastra/deployer-sandbox/client` 僅供伺服器使用。解析 Sandbox 會使用絕不能傳至瀏覽器的 Provider 認證資訊。在瀏覽器環境中匯入此模組會擲回錯誤。 ### 第 3 層:提供終端使用者的穩定 URL 在自己的網域提供穩定 URL,並在伺服器端轉送至 Sandbox;可使用 route handler proxy 或 Edge Config alias。 下列範例使用 Vercel 與 Next.js,但此概念適用於任何能轉送要求的伺服器端框架或 Provider。 - **Route handler proxy。** `createSandboxHandler()` 會快取 Sandbox URL,並在連線層級失敗後重新解析,涵蓋 URL 輪替與冷喚醒: ```typescript import { createSandboxHandler, getDeployment } from '@mastra/deployer-sandbox/client' import { VercelSandbox } from '@mastra/vercel' const handler = createSandboxHandler({ resolve: async () => { const deployment = await getDeployment({ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }), wake: true, }) return deployment.url! }, }) export { handler as GET, handler as POST } ``` - **Edge Config alias。** 在部署器設定 `alias` 選項,使 [Vercel Edge Config](https://vercel.com/docs/edge-config) 項目在每次部署時都指向目前 URL: ```typescript const deployer = new SandboxDeployer({ sandbox: new VercelSandbox({ sandboxName: 'my-preview', ports: [4111] }), alias: { edgeConfigId: 'ecfg_...', key: 'my-preview', token: process.env.VERCEL_TOKEN! }, }) ``` 接著使用 `createSandboxProxy()` 在 Next.js middleware 中改寫要求: ```typescript import { createSandboxProxy } from '@mastra/deployer-sandbox/client' export const middleware = createSandboxProxy({ key: 'my-preview' }) export const config = { matcher: '/api/:path*' } ``` ## CI 範例 為每個 pull request 部署預覽: ```yaml name: Sandbox preview on: pull_request jobs: preview: runs-on: ubuntu-latest env: VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} VERCEL_TEAM_ID: ${{ secrets.VERCEL_TEAM_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - run: npm ci - run: npx mastra build - run: curl --fail "$(jq -r .url .mastra/output/sandbox-deployment.json)/api" ``` ## 安全性 - Sandbox URL 是公開的。任何擁有 URL 的人都能存取 Mastra 伺服器,包括 Studio。除拋棄式預覽外,請一律啟用[伺服器驗證](https://mastra.zisheng.pro/zh-TW/docs/server/auth)。 - `.env` 檔案中的環境變數會注入遠端 Sandbox VM,讓伺服器能夠執行。發生此情況時,部署會記錄警告。請勿部署你不願放在共用預覽伺服器上的 secret。 - 若要將存取限制為第 3 層流量,請將 `secret` 傳入 `createSandboxHandler()` 或 `createSandboxProxy()`。這些 helper 會在轉送要求上附加 `x-mastra-sandbox-secret` header。設定[伺服器驗證](https://mastra.zisheng.pro/zh-TW/docs/server/auth)以要求該 header,如此直接存取 Sandbox URL 會遭拒絕,而透過你網域的流量則可正常運作。 ## 相關資源 - [部署概覽](https://mastra.zisheng.pro/zh-TW/docs/deployment/overview) - [伺服器驗證](https://mastra.zisheng.pro/zh-TW/docs/server/auth) - [`WorkspaceSandbox` 參考](https://mastra.zisheng.pro/zh-TW/reference/workspace/sandbox)