內部做法

從 git push 到上線的 11 分鐘:我們的部署流水線全揭密

2026.09.08 · 15 次瀏覽
從 git push 到上線的 11 分鐘:我們的部署流水線全揭密

ScriptWalker 的 production 沒有任何人有手動部署權限。這篇公開 Laravel 與 Flutter 專案的完整流水線:GitHub Actions 的 workflow 設定、Laravel Forge 的 deploy script、Sentry release 標記、失敗自動回滾,以及四個真實代價與三種不該這樣做的情境。

分享:

那次漏掉一行指令,賠掉兩天對帳

幾年前接手一個電商後台,上線靠工程師 SSH 進去依序跑 git pullcomposer installmigrate、清 cache。某次週五晚上趕改版漏跑 php artisan config:cache,站台繼續讀舊的金流設定,三小時內 27 筆訂單的付款回調全部落空。技術修復 40 分鐘,人工對帳花了兩天。結論不是誰不小心:當上線是靠記性執行的指令,任何人在疲勞的夜裡都會漏掉一步。

我們的做法:把上線變成沒人能手動介入的按鈕

ScriptWalker 的 production 沒有人握有手動部署權限,所有變更走同一條流水線。Laravel 專案從 git push 到上線平均 11 分鐘:CI 約 7 分鐘、部署與驗證約 4 分鐘。

git push(feature 分支)
  → GitHub Actions CI:Pint 格式檢查 → Larastan 靜態分析 → Pest 測試 → Playwright E2E(8 條關鍵路徑)
  → PR 全綠 + 1 位 reviewer 核可
  → squash 合併 main
  → Actions 產生版本 tag
  → 呼叫 Laravel Forge deploy hook(新版本 clone 進 releases/,symlink 切換)
  → migrate --force + artisan optimize
  → 對 /health 與 3 條關鍵路徑跑煙霧測試
  → 建立 Sentry release 並關聯 commit
  → Slack #deploys 回報;失敗自動把 symlink 指回上一版

Flutter 走平行支線:同一個 tag 觸發 Codemagic 建 iOS 與 Android,簽章後直送 TestFlight 與 Play 內部測試軌。

為什麼不做更「完整」的版本

三件常見做法,我們刻意不做。

  • 沒有 Kubernetes、沒有真的 Blue-Green。專案多是單機或雙機規模,Laravel Forge 的 zero-downtime 部署releases/ 加 symlink 切換就能讓使用者無感;養一套 K8s 只會吃掉小團隊產能。
  • E2E 只跑 8 條,不是 80 條。CI 時間預算上限是 10 分鐘;超過,工程師就會把 PR 堆著、一次合五個,那才是風險來源。Playwright 官方 CI 章節也建議用 sharding 分散。
  • main 直上 production,金流與推播除外。paymentpush-notification 標籤的 PR 會進 GitHub Environments 的 required reviewer 閘門。

取捨是:流程極短、關鍵路徑加鎖,而不是流程完整卻沒人走完。

實際怎麼跑:工具、設定與檔案

Step 1|本地攔截。pre-commit hook 只跑 Pint 與 dart format,兩秒結束、不跑測試——慢的 hook 就是會被跳過的 hook。

Step 2|CI。workflow 檔節錄:

name: ci
on:
  pull_request:
  push: { branches: [main] }
concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true
jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/cache@v4
        with:
          path: vendor
          key: composer-${{ hashFiles('composer.lock') }}
      - run: composer install --no-interaction --prefer-dist
      - run: ./vendor/bin/pint --test
      - run: ./vendor/bin/phpstan analyse --memory-limit=1G
      - run: php artisan test --parallel
  e2e:
    needs: quality
    runs-on: ubuntu-latest
    steps:
      - run: npx playwright test --shard=1/2

concurrency 讓同分支的舊 run 自動取消,省時也省錢,細節見 GitHub Actions 官方文件

Step 3|部署與驗證。Forge deploy script 的尾段固定是:

php artisan migrate --force
php artisan optimize
php artisan queue:restart
curl -fsS https://APP_URL/health || exit 1
sentry-cli releases new "$FORGE_SHA"
sentry-cli releases set-commits --auto "$FORGE_SHA"

artisan optimize 正是當年漏掉的那一步,Laravel 官方部署文件列為必跑;queue:restart 讓 worker 載入新程式碼;最後推進 Sentry Releases,錯誤就能對應到哪次部署。

Step 4|Flutter。Flutter 官方 CD 指南用 Fastlane 包裝簽章與上傳、交給 Codemagic 執行。

這個做法的代價(誠實版)

  • CI 帳單是真的要付。十幾個 repo 同時跑,每月都超出免費額度,GitHub 方案頁寫明超出按分鐘計費,我們自己吸收。
  • 改一個錯字也要 11 分鐘。沒有例外通道,客戶通常很難理解。
  • pipeline 本身要養。每季約 4 到 6 小時處理 flaky E2E、更新 action 版本、修升版後炸掉的 job,這些工時不進報價單。
  • 新人前兩週會卡住。第一支 PR 常常紅三四次才變綠。

什麼情況不該這樣做

  • 還在驗證題目的小產品。生命週期六週、使用者不到一百人,時間花在 pipeline 不如花在跟使用者談;這種案子只開 Forge quick deploy。
  • 伺服器在不能對外連線的內網。金融與醫療常見。Actions 打不到部署目標,得改用 self-hosted runner,成本結構不同,要在報價階段講清楚。
  • 零自動測試的既有專案。先蓋 CI 只會得到一條什麼都沒檢查、卻很慢的流水線。

身為客戶,你為什麼該在意

  • 時程可預測。「改完什麼時候看得到」有固定答案,不是「等我晚上有空」。
  • 回滾成本近零。symlink 指回前一版通常兩分鐘恢復,不必開會決定要不要 revert,雙方都更敢試。
  • 你付的是功能,不是重工。格式與靜態分析由機器擋掉,review 平均 15 分鐘,沒有一分鐘在講縮排。

如果你的團隊也想這樣做

  • 先定時間預算再挑測試。講定 CI 不超過 10 分鐘,取捨自然發生;反過來做一定膨脹到沒人願意等。
  • 先把部署指令寫成腳本,再談測試。就算仍由人觸發,它是檔案而不是記憶,問題就少一半。
  • 把回滾練成肌肉記憶。每季在 staging 演練一次;沒演練過的回滾等於沒有這個機制。
  • 快取相依套件。actions/cachecomposer.lock 快取,通常省三到四成 CI 時間。
  • 讓失敗吵一點。部署失敗進 Slack 主頻道,不是靜悄悄的 email。

我們在哪些客戶身上跑過

某連鎖餐飲的線上訂餐系統(Laravel + Flutter)。接手前是手動 FTP,平均每次改版漏傳一兩個檔案。導入後六個月 140 次部署、2 次自動回滾、0 次因部署失誤造成的中斷。

某 B2B SaaS 後台。客戶自己有兩位工程師共同開發,同一套 workflow 直接交給他們。最明顯的改變是 PR 討論:以前一半在爭寫法,現在全部集中在商業邏輯。

常見問題

團隊只有兩三個人,值得建 CI/CD 嗎?

值得,但範圍要小。人越少越輸不起一次半夜的失誤。最小可行版本是一條跑 lint 與關鍵路徑測試的 CI,加一個一鍵部署腳本。

導入要多久、多少成本?

既有 Laravel 專案約 3 到 5 個工作天,補測試佔一半以上;持續成本是 CI 分鐘數與 Forge 訂閱,中小專案多半每月數十美元。

可以只做 CI、不做自動部署嗎?

可以,對很多團隊還是正確的第一步:先讓每個 PR 被檢查、累積信任,再打開自動部署。

migration 自動跑不危險嗎?

會,所以有兩條紀律:破壞性變更拆成兩次部署,先加後刪;部署前自動快照。Laravel migration 文件也提醒用 --force 前要清楚會執行什麼。

會把流程交接給客戶團隊嗎?

會,這是預設交付內容;workflow、部署腳本與 runbook 都在客戶自己的 repo。

下一步

如果你正在評估 Laravel 或 Flutter 專案,而過去經驗讓你對「上線」不安,我們可以先看你現在的 repo,給一份改善順序,不收費。如果你是工程師,喜歡把重複的事變成腳本、對 CI 綠燈有執念,我們長期在找這樣的人。

分享: