範例 repo
兩個公開 repo,都在 https://github.com/parallel-sandbox 底下。兩個本機 docker compose up 就能跑,README 都逐一工具寫了在箱子裡怎麼跑。我們自己測平台也用這兩個。
example-compose-app
https://github.com/parallel-sandbox/example-compose-app
一個排工作的 Node API(3000 埠)加一個做工作的 Go worker(8080 埠),用 docker-compose.yml 接起來。e2e/ 是一支 Playwright 測試:在真的瀏覽器打開頁面、新增一件工作、等 worker 做完、存截圖。
在箱子裡練到的:git clone、docker compose up --build、兩個服務的 sandbox_wire、虛擬螢幕上的有頭瀏覽器、sandbox_shot 錄影、sandbox_get 拿截圖。
sandbox_start { "services": [{ "name": "api", "port": 3000 }, { "name": "worker", "port": 8080 }] }
sandbox_exec { "id": "<id>", "cmd": "git clone https://github.com/parallel-sandbox/example-compose-app.git" }
sandbox_exec { "id": "<id>", "cmd": "docker compose up -d --build --wait", "cwd": "example-compose-app", "timeoutSec": 600 }
sandbox_wire { "id": "<id>", "service": "api", "mode": "box" }
sandbox_wire { "id": "<id>", "service": "worker", "mode": "box" }
sandbox_exec { "id": "<id>", "cmd": "npm ci && npx playwright install chromium", "cwd": "example-compose-app/e2e", "timeoutSec": 600 }
sandbox_shot { "id": "<id>", "record": "start" }
sandbox_exec { "id": "<id>", "cmd": "DISPLAY=:99 HEADED=1 BASE_URL=http://localhost:3000 npx playwright test", "cwd": "example-compose-app/e2e", "timeoutSec": 300 }
sandbox_shot { "id": "<id>", "record": "stop" }
sandbox_get { "id": "<id>", "path": "example-compose-app/e2e/screenshots/jobs.png" }
sandbox_stop { "id": "<id>" }
README 也示範另一種接線:箱子裡只跑你改的那個服務,沒改的用 externalBaseUrl 加 mode: "external" 指到你自己的環境。
example-web-with-logs
https://github.com/parallel-sandbox/example-web-with-logs
一頁靜態網頁,掛上瀏覽器 log SDK @parallelsandbox/log。一個按鈕會在三層函式呼叫深處丟出未捕捉的錯誤。頁面用 esbuild 建(壓縮、帶 source map)、nginx 供應、容器啟動時從環境變數寫設定,所以 project 的 write key 不會進 image。
在箱子裡練到的:sandbox_start 帶 secrets、上傳 source map、虛擬螢幕上的網頁、logs_errors 撈回錯誤且 stack 還原到 src/app.js 的行號。
sandbox_start { "services": [{ "name": "web", "port": 8080 }], "secrets": ["PSBX_LOG_WRITE_KEY"] }
sandbox_exec { "id": "<id>", "cmd": "git clone https://github.com/parallel-sandbox/example-web-with-logs.git" }
sandbox_exec { "id": "<id>", "cmd": "PSBX_RELEASE=$(git rev-parse --short HEAD) PSBX_LOG_PROJECT=<project id> PSBX_LOG_ENDPOINT=https://log.parallelsandbox.com docker compose up -d --build --wait", "cwd": "example-web-with-logs", "timeoutSec": 600 }
sandbox_wire { "id": "<id>", "service": "web", "mode": "box" }
source map 在你自己的機器上傳,不要在箱子裡跑,API key 才不會進箱子。同一個 commit,release id 就相同:
git clone https://github.com/parallel-sandbox/example-web-with-logs.git && cd example-web-with-logs
npm ci && PSBX_RELEASE=$(git rev-parse --short HEAD) npm run build
PSBX_API_KEY=<api key> PSBX_LOG_PROJECT=<project id> ./scripts/upload-sourcemaps.sh
回到箱子:
sandbox_exec { "id": "<id>", "cmd": "DISPLAY=:99 chromium --no-sandbox --kiosk --window-size=1280,800 --user-data-dir=/tmp/chrome http://localhost:8080/", "background": true }
sandbox_shot { "id": "<id>" }
sandbox_exec { "id": "<id>", "cmd": "DISPLAY=:99 xdotool mousemove 640 300 click 1" }
logs_errors { "project": "<project id>", "since": "10m" }
sandbox_stop { "id": "<id>" }
拿來當範本
兩個 repo 都很平常:根目錄一個 docker-compose.yml,每個服務一個目錄、各自的 Dockerfile,測試自己一個目錄。長這樣的 repo 在箱子裡都是同一套跑法。跟 ParallelSandbox 有關的只有 sandbox_start 的 services 清單(名稱與埠),以及想收瀏覽器錯誤時掛的 log SDK。