自動化、發布工程與簡單性:讓『改變』又快又安全

· tech

#sre#automation

📑 目錄

自動化、發布工程、簡單性,乍看是三個不相干的主題。但把它們擺在一起,會發現它們在回答同一個問題:怎麼讓「變更」既快又不出事?SRE 的三招答案分別是——用機器一致地做、把上線做成可重現的流程、以及讓要改的東西本身夠小

自動化:終點是「把人從迴圈裡拿掉」

大家對自動化的直覺是「省時間」,但 SRE 眼中,自動化最大的價值其實是一致性——人做十次會有十種微妙差異,機器做一萬次都一樣。省時只是附帶好處,真正的目標是沿著一條階梯往上爬,最後讓系統自己管自己、把人從操作迴圈裡拿掉:

自動化的演進:一路往上,把人從迴圈裡拿掉 自動化↑ · 人越不用碰 ④ 自主 / 自癒系統系統自己管自己 → 人退出迴圈 ③ 通用自動化平台跨系統重用、一致、可擴展 ② 針對任務寫腳本省時,但腳本要人養、換場景就失效 ① 手動操作(toil)慢、易錯、不一致、無法規模化 ⚠ 但自動化會放大 blast radius 能一致地做對,就能一致地闖禍——一鍵下錯,關掉的可能是整個機房
自動化不只是省時,它的核心價值是一致性可規模化。但同一枚硬幣的反面是:自動化把「做對」放大的同時,也把「做錯」放大——Google 就有過自動化工具一口氣關掉整個資料中心的慘案。所以越往上爬,越要配上護欄(dry-run、逐步生效、人為確認關卡)

這裡最反直覺的一課,是自動化的危險來自它的優點。一段會自動修復的腳本,寫對了能一致地救全世界,寫錯了也能一致地毀全世界——而且是用機器的速度、在你反應過來之前。所以 SRE 對自動化的態度不是「全自動最好」,而是能力越大、護欄要越厚:高風險動作要 dry-run 預演、要逐步生效(先一台、再一區)、要留人為確認的關卡。

發布工程:把「怎麼上線」當成一門專業

第二招是把「從程式碼到上線」這條路,當成一門獨立的專業來經營,而不是每個工程師各自手動兜。它的地基是四個原則,其中最關鍵的是 hermetic build(密封建置):

  • 自助式(self-service):團隊自己就能發布,不用排隊等某個人。
  • 高頻率、小步發:發得越頻繁,每次的差異越小、越好回滾——這跟 DevOps 的「逐步變更」是同一件事。
  • hermetic build(可重現):同樣的原始碼,今天 build、半年後 build、在誰的機器上 build,都吐出位元完全一樣的結果——不依賴「這台機器剛好裝了什麼」。
  • 政策內建(enforced):哪些能上線、要通過哪些檢查,寫成流程強制執行,不是靠人自律。

hermetic build 為什麼重要?因為它把「在我機器上明明可以」這句話從根上消滅了。build 的結果只由你簽入的東西決定,跟環境無關——於是「這版到底包含什麼」變得可稽核、可重現、可回滾。出事時你能精準地退回上一個已知好的版本,而不是對著一個「大概是這樣組出來的」神秘產物束手無策。

簡單性:可靠度真正的來源

前兩招都在讓「改變」這件事變安全,但第三章給了一個更釜底抽薪的答案:讓要改的東西本身變小。可靠度最深的來源不是更多防護,而是簡單——因為能壞的地方,跟系統的複雜度成正比。

放任複雜長大 一直加功能 · 特例 · 選項 出錯面變大、行為難預測 可靠度 ↓ 刻意保持簡單 最小 API · 砍特例 · 主動刪程式碼 出錯面小、行為可預測 可靠度 ↑ 「每一行程式都是負債」 能動的程式碼越少,能壞的地方越少——SRE 把「刪掉的行數」當成正面成就
功能會一直有引力把系統推向複雜,而複雜度直接換算成「更多能出錯的地方、更難預測的行為」。所以簡單不是自然發生的,是要刻意維護的紀律:最小的 API、拒絕不必要的選項、甚至主動刪掉用不到的程式碼。無聊、可預測,在可靠度工程裡是美德,不是缺點

這章有句話我很喜歡:軟體工程師常把「寫了多少行」當成產出,但 SRE 會把「刪掉多少行」當成成就。每一行活著的程式碼,都是一份要維護、可能出錯、會拖慢理解的負債。所以面對複雜,SRE 的直覺不是「再加一層來罩住它」,而是先問這複雜是不是必要的、能不能拿掉。可預測與無聊,在 Production 是最高的讚美。

反思

自動化真正的兩面刃,是它把「一致」也用在錯誤上

我以前寫自動化,腦子裡只有「幫我省時間」。但這章讓我換了個角度:自動化最強的地方是一致——而一致是中性的,它會一致地做對,也會一致地做錯。人手動操作雖然慢又煩,但人有個隱形的好處:做到一半覺得不對勁會停下來。自動化沒有這個直覺,它會用全速、對所有目標、把錯誤忠實地執行到底。所以我現在寫任何有破壞性的自動化(批次刪除、大量更新、一鍵部署),都會先問一句:「這如果跑錯,炸掉的範圍有多大?」 範圍越大,我就越捨得加那些看起來很囉唆的護欄——dry-run、先跑一小批看看、關鍵步驟留一個人為確認。能力越大,護欄要越厚,這是我從這章帶走最實用的一條。

hermetic build:把「在我機器上可以」從根上消滅

「在我電腦上明明就會動」大概是工程界最著名的一句廢話,而 hermetic build 是我看過對它最徹底的解法——不是叫大家「注意環境一致」,而是從架構上讓 build 不可能依賴環境。這也是為什麼我對 Docker、鎖版本的 lockfile、可重現建置這些東西越來越偏執:它們的價值不在「方便」,而在讓「這版到底是什麼」變成一個確定、可回滾的答案。出事的半夜,你最想要的不是猜,是能一秒退回上一個已知好的版本——而那個能力,是平常一點一滴的 hermetic 紀律換來的。這跟我在資料那邊講的冪等可重跑其實是同一種偏執:讓結果只由輸入決定,跟「什麼時候、在哪裡跑」無關。

簡單是最難的紀律,因為複雜總是偷偷長出來

「保持簡單」聽起來像廢話,但真正做過就知道它有多難——因為複雜從來不是一次長出來的,是每次「就多加一個小選項嘛」「這個特例先 hardcode 一下」慢慢堆出來的,每一步都合情合理,加總起來就是一團沒人敢動的東西。這章把「每一行程式都是負債」這句話釘進我腦裡之後,我 review code 的問題變了:以前問「這樣寫對不對」,現在會多問一句「這段有必要存在嗎?能不能不加、甚至刪掉?」。刪掉一個沒人用的功能、一個多餘的設定選項,帶來的可靠度紅利,常常比再寫一層防護還高。這跟整個 SRE 系列的精神是一致的:連鎖失效之所以可怕,連鎖的節點越多、系統越複雜,骨牌就倒得越遠——最好的防線,是一開始就別讓系統複雜到你自己都預測不了它。