山姆鍋現在一人開發 NT² Vault ⎘。產品本身怎麼設計、選什麼架構,那是產品站與產品部落格的事;這篇只想講一件很土、卻會讓人半夜起來看帳單的事——CI 的分鐘數與機器到底放哪裡。
如果你也在一人出產品、儲存庫還不小、又想留著自動測試,大概遲早會撞上同一面牆。
目錄
分鐘數比程式碼先爆
一開始山姆鍋很老實:PR、推到 dev/main,就讓 GitHub Actions ⎘ 在 ubuntu-latest 上跑完 typecheck、lint、單元測試,再跑 Playwright E2E。感覺很「正經」。
問題是 Free 方案的分鐘數不是無限的。完整 Offline E2E 一跑就是好一段真實時間;一個月還沒過完,額度已經見底。部署、發版那些還真的需要 hosted runner 的工作,反而沒預算了。
那時山姆鍋做過一個很醜、但有效的暫時解法:關掉自動觸發,改成幾乎只靠 workflow_dispatch 手動跑。品質閘還在,只是不再「每次 push 都跑」。代價也很清楚——忘記手點、或者懶得等的時候,壞東西就比較容易溜進分支。一人團隊裡,這種偷懶會直接變成技術債利息。
本機當 runner?先跟自己搶 port
既然 hosted 分鐘數貴,下一個直覺是:家裡不是有台 Mac Studio 嗎?日常開發機再掛個 self-hosted runner,E2E 丟上去跑就好。
實務上撞牆的方式很蠢,也很真實。Studio 同時開著 pnpm run dev、各種 preview/靜態預覽埠(山姆鍋這邊常見是一串 4173、4174 之類),CI 上的 Playwright 也要起一組預覽服務。兩邊搶同一個埠,失敗訊息看起來像測試不穩,其實是開發機跟 CI 機是同一台時的空間重疊。
結論很單純:日常開發機當「偶爾手動跑測試的機器」可以;當成「權威、自動、跟 PR 綁死的 E2E 主機」就不適合。一人團隊最缺的不是 CPU,是上下文不被打斷——CI 跑一輪就把本機開發環境弄髒,等於跟自己搶工位。
後來怎麼拆
山姆鍋後來把測試面搬到標成 nt2-ci 的 Linux 自架 runner(ARM64 上用 Colima 那類環境)。大致原則是:
- 品質閘與 E2E:走 self-hosted,不再吃 GitHub Free 的測試分鐘數。
- Cloudflare 部署、桌面/行動發版:仍留在 GitHub-hosted。部署密鑰、環境變數不要送到家裡那台 runner 上——機器在客廳跟機器在 GitHub,信任邊界不一樣。
- PR 上的重活要收斂:進行中的舊 run 要能取消,避免 force-push 一路燒;lint/檢查盡量只打「有碰到的套件」,整庫 type-aware ESLint 留給完整閘,而不是每張 PR 都付一次全價。
這些不是什麼高深架構,比較像一人維運的會計科目:哪些成本可以外包給 Free 額度、哪些必須自己扛機器、哪些密鑰絕對不能搬家。
自架之後,新的帳單改為「你要醒著」
分鐘數壓力小了,換成另一種壓力:
- runner 離線,PR 就排隊或直接紅燈——沒有同事幫你重開機器。
- 映像/系統函式庫版本不對(例如某些工具要較新的 GLIBC),job 會在很前面就掛;除錯時間算在你頭上。
- 測試池若只有一台,fast-gate 跟 E2E 可能會互搶,體感變成「CI 永遠在排隊」。
所以自架不是「免費無限 CI」,而是把雲端帳單換成自己當 SRE 的時間帳單。山姆鍋覺得,一人產品可以接受這筆帳,前提是你清楚:自動化恢復了,維運責任也回來了。
給同樣一人扛產品的人
沒有放諸四海皆準的原則,但這幾條山姆鍋願意再走一次:
- 先算分鐘數,再談理想管線。 完整 E2E 放 hosted Free,很容易月中就沒子彈。
- 開發機 ≠ CI 機。 埠衝突、相依快取、心理負擔,都會反噬日常開發。
- 測試可以自架;持有密鑰的部署,想清楚再搬家。
- 取消過期 run、縮小 PR 檢查範圍,往往比再買分鐘數更划算。
- 暫時關掉自動 CI 可以救命,但別當長期策略。 忘記手點的成本,一人團隊特別高。
這篇刻意不寫成「如何設定 self-hosted runner」逐步教學——那種文件網路上很多,也容易過期。山姆鍋比較想留下的是決策過程:卡在哪、為什麼放棄某條路、最後願意用什麼交換什麼。
若你對山姆鍋正在做的產品本身有興趣,官網在 nt2.me ⎘;之後若還寫一人開發系列,大概會輪到回饋通道怎麼開才不會把自己淹沒,或本機視覺測試這類「請不起 QA 時怎麼妥協」的題目。

