Skip to Content
操作流程本機重現與除錯

本機重現與除錯

沙盒執行你的程式時只做一件事:在你的環境映像裡,以 /bin/sh 跑一個固定 session:

. /workspace/startup.sh && . /workspace/driver.sh

三個 UI 欄位落地成三個固定檔名(上傳檔案的原始檔名不會保留):

欄位落地路徑誰讀它
前置腳本(startup_script)/workspace/startup.sh永遠是 sh
執行指令(work_command)/workspace/driver.sh永遠是 sh(空白時內容是 . /workspace/work.sh)
工作腳本(work_script)/workspace/work.sh看 driver 寫什麼——填了 python3 /workspace/work.sh 它就是 Python

其餘的每次執行輸入:input JSON 會在腳本啟動前寫到 $TEAMSYNC_INPUTS_FILE 指的檔案;結果寫到 $TEAMSYNC_OUTPUT_FILE 指的路徑;之後想下載的檔案放到 $TEAMSYNC_ARTIFACTS_DIR(/workspace/artifacts,runner ≥ #1152);secret slot 以環境變數匯出。cwd 名義上是 /workspace,但契約不保證——腳本與 work_command 一律寫絕對路徑。

本機 harness

自訂環境的 Dockerfile 是你自己寫的,所以你可以在本機 build 出同一個 base,然後用同一份契約跑:

# 1) build 你上傳給環境的同一份封存 docker build -t my-env ./env-context # 2) 組出 /workspace,跟平台落地的一模一樣 mkdir -p ws cp startup.sh ws/startup.sh # 沒有就放空檔 cp my-work.py ws/work.sh # 注意:固定叫 work.sh,不管原本副檔名 printf '%s' 'python3 /workspace/work.sh' > ws/driver.sh # = 你的 work_command echo '{"demo": 1}' > ws/inputs.json # 3) 用同一個 session 跑(--network=none 是模擬 runtime_egress_enabled=false 的公司; # 預設部署執行期可對外連線——要一致就把這個旗標拿掉) docker run --rm --network=none \ -v "$PWD/ws":/workspace \ -e TEAMSYNC_INPUTS_FILE=/workspace/inputs.json \ -e TEAMSYNC_OUTPUT_FILE=/workspace/output.json \ -e TEAMSYNC_ARTIFACTS_DIR=/workspace/artifacts \ -e MY_SECRET_SLOT=dev-value \ my-env \ /bin/sh -c '. /workspace/startup.sh && . /workspace/driver.sh' cat ws/output.json

路徑錯、套件沒裝到、runtime 版本不對、node_modules 解析失敗——這些在本機各花五秒就能排除,不必每次都走一次「上傳 → 建置 → ready → 執行」的迴圈。

本機 harness 與真沙盒的差異

面向本機 harness真沙盒
Base 映像你 docker build 的那份同一份封存建的映像 + 平台簽章 runner layer(只加 teamsync-runner/ 底下的檔案,不動你的內容)
網路只有模擬 runtime_egress_enabled=false 時才加 --network=none預設可對外連線(runtime_egress_enabled,GET /settings),會計量;私有/loopback/metadata 網段沒有被過濾
隔離一般容器gVisor 沙盒、非 root、資源上限(依 resource_profile)
環境變數你的 -e 參數加上映像自己的 ENV只有 PATH、ordinary_env、secret slot 與三個 TEAMSYNC_* 路徑——映像的其他 ENV(JAVA_HOME、LANG……)不會繼承(地端自 v5.10.11 起也一樣)
行程模型/bin/sh 是容器的 PID 1;id -u 是映像的 USER託管雲端開啟對外網路、且 runner release 以 v5.10.11 原始碼建置的 run 會嘗試巢狀 user+PID 命名空間;主機允許私有 /proc 設定時,/bin/sh 是該命名空間的 PID 1,否則 runner 會記錄或使用直接 shell fallback。地端使用 Docker worker 的直接 /bin/sh;runner 會保留 /workspace/.teamsync/
Secrets-e 直接塞密封通道匯出成環境變數,不落盤
逾時無timeout_seconds(也受公司 ceiling)

行為差異幾乎只剩隔離強度、資源上限與被剝掉的映像 ENV;契約(檔名、session、TEAMSYNC_* 變數)完全相同。本機通過、上去失敗時,先查資源上限與逾時,再查腳本是否依賴映像 ENV 裡的變數,最後查映像是否真的是同一版。

Node 的 node_modules 陷阱

程式在 /workspace/work.sh,Node 的模組解析只會往上找 /workspace/node_modules → /node_modules。所以環境 Dockerfile 裝相依時要落在根目錄:

FROM node:20-slim WORKDIR / # 關鍵:讓 npm ci 產生 /node_modules COPY package*.json ./ RUN npm ci --omit=dev

寫 WORKDIR /app 的話,require('axios') 在執行期找不到——本機 harness 會重現出一模一樣的失敗。Python 沒有這個問題(pip 裝進 site-packages,跟路徑無關)。

「不知道映像裡裝了什麼」

環境的建置內容是你上傳的封存——把 Dockerfile 與 lockfile(package-lock.json/requirements.txt)留在自己的版本控制裡,映像內容就永遠可考。版本回應上的 source_digest/source_ref(owner 才看得到)能對回是哪一包封存。策展環境(SCFG Standard)目前拿不到 Dockerfile——需要清單請開票給營運方。

Last updated on