昨天我們談了金絲雀部署,讓新版本只先跑 10%,出了事影響不會全毀。
但再小心,還是有可能爆炸──bug 總會有你想不到的形態。
所以今天的重點不是「避免失敗」,而是 「失敗時要能退路」 。
能上線是一種能力,但能下線才是生存力。
就像玩遊戲打 Boss,誰會不先存檔?如果沒準備回滾,等於是 Hardcore 模式,炸了就直接遊戲結束。
避免長時間當機
新版本掛掉,能馬上切回舊版,服務不中斷。
降低人工干預
工程師不需要半夜爬起來手動打指令救火。
安全網效應
開發敢於快速嘗試,因為知道隨時能退回。
回滾就像是遊戲裡的「讀檔機制」。
你敢放心衝副本,不是因為你不怕死,而是因為你隨時能復活。
手動回滾
最原始的方式:ssh 進伺服器,把 container 停掉,重新啟動舊版本。
缺點是:慢、容易出錯、而且常常人還在睡覺。
半自動回滾
Pipeline 偵測到健康檢查失敗,發 Slack 通知給工程師,由人決定要不要回滾。
速度比手動快一點,但還需要人參與判斷。
全自動回滾
Pipeline 自己判斷:
缺點是需要設定「判斷條件」,不然太敏感會變成版本一直亂跳。
但在正確的配置下,它就是你的自動保命符。
每次 push image 時,打兩個 tag:
:latest → 現在線上跑的版本
:<commit_sha> → 存檔點
例如:
docker build -t ghcr.io/你帳號/vps:latest -t ghcr.io/你帳號/vps:${GITHUB_SHA} .
docker push ghcr.io/你帳號/vps --all-tags
這樣每次部署都有「快照」,能回到過去。
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request,sys; urllib.request.urlopen('http://127.0.0.1:8000/healthz'); sys.exit(0)"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
只要 /healthz 沒回 200,服務就會被判斷 unhealthy。
- name: Health check
run: |
for i in {1..5}; do
if curl -fsS http://localhost/healthz; then
echo "Service healthy"
exit 0
fi
echo "Waiting..."
sleep 5
done
echo "Deployment failed, rolling back..."
docker compose pull app:${{ github.event.before }}
docker compose up -d
exit 1
這邊的 ${{ github.event.before }} 就是上一個 commit SHA。
也就是如果這次掛掉 → 自動切回前一版。
Q: 會不會太敏感,一點小延遲就觸發回滾?
A: 可以設定 retry,例如連續 3 次失敗才觸發。避免因為短暫網路波動就亂退。
如果舊版本也有Bug,回滾至少能保證服務能活著,再人工debug。然後回滾後記得要再跑一次健康檢查,確認舊版本是健康安全的。
今天我們把 回滾 加進來。
搭配前幾天的藍綠部署、金絲雀部署,整個流程就是
這才是完整的生存循環。
畢竟現在注重的不再是「有沒有 bug」,而是「出了 bug 還能不能活著」。