一個系統只有在能夠安全地被摧毀和重建時才能自我修復。這是不可變基礎設施背後的原則:不是原地修補、配置和修改服務器,而是將基礎設施視為可拋棄的。有一個服務器有問題?刪除它。從已知良好的映像開始一個新的。

這不是新想法。它甚至不是尖端想法。但對於自主運維至關重要。Layer 0-2(可觀測性、運行手冊自動化、SLO 控制)讓你能夠偵測問題並決定修復它們。Layer 3——不可變基礎設施——讓你能夠安全地修復它們。

沒有不可變基礎設施,自動化修復是危險的。你無法可靠地替換失敗的組件,因為你不知道它處於什麼狀態。你無法有信心回滾更改,因為先前的狀態可能會丟失。你無法快速擴展,因為每個新實例可能略有不同。可變基礎設施使自主運維變得脆弱。

可變 vs 不可變:根本區別

在可變基礎設施中,服務器是寵物。你給它們命名。你更新它們。你修補它們。你記得你在星期四凌晨 3 點手動修復配置文件的那一次。

經過多年的修補、更新和手動干預,每台服務器都是獨特的。你無法可靠地預測重啟其中一個會發生什麼。你無法快速替換它,因為你不知道它處於什麼確切的狀態。當出現問題時,修復它需要調查:「這台服務器經歷過什麼?什麼被修補過?什麼被配置錯誤?」

在不可變基礎設施中,服務器是牲畜。你不給它們命名。如果一個死亡,你不哀悼它——你替換它。每台服務器都是從相同的不可變映像創建的。配置在創建時從代碼確定,之後不修改。當出現問題時,你不修復它;你替換它。

對自主運維的含義是深遠的:

  • 可預測性。 每個實例都是相同的。自動化操作有可預測的結果。
  • 安全性。 重啟一個不可變實例,你知道它會以相同的狀態返回。沒有意外配置,沒有補丁副作用。
  • 速度。 推出新版本或從故障中恢復只是「啟動新的,終止舊的」。沒有手動步驟。沒有狀態遷移。
  • 可審計性。 每個實例都是從代碼確定地創建的。你可以追蹤回定義其狀態的確切提交。

不可變基礎設施的三層

Layer 3a:容器映像(不可變應用交付)

不可變基礎設施的基礎是容器映像。Docker 映像是你的應用和其運行時環境的完整、版本化快照:

FROM python:3.11
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY src/ /app/
ENTRYPOINT ["python", "/app/main.py"]

# 構建發生一次。映像是不可變的。

關鍵紀律:永遠不要修補正在運行的容器。永遠不要 docker exec 進容器手動修復某些東西。如果容器是錯誤的,殺死它並啟動一個新的。

Layer 3b:基礎設施即代碼(可重現的基礎設施)

應用只是第一層。你的基礎設施——Kubernetes 集群、資料庫、網絡、存儲——也必須定義為代碼。

Layer 3c:GitOps(Git 中的聲明狀態)

GitOps 更進一步:你的期望基礎設施狀態儲存在 Git 中,自動化控制器連續協調實際狀態以匹配。

常見陷阱

不可變容器中的可變狀態。 如果它存儲數據本地,你無法重啟容器。如果你的容器寫到 /data/app.db 而那個目錄不由卷支持,重啟容器會丟失數據。解決方案:外化狀態。

GitOps 沒有適當的 RBAC。 如果有集群訪問權限的任何人都可以合併到主分支,你放棄了可審計性。使用適當的 Git 訪問控制。

實際上是可變的不可變基礎設施。 如果你的 Dockerfile 包括 apt-get update && apt-get upgrade,你的映像不是真正不可變的——它每次構建時都會改變。顯式固定版本。

不可變基礎設施啟用整個堆棧

沒有不可變基礎設施,前面的層受到約束。有了它:

  • 修復是安全的(用已知良好映像替換組件)
  • 回滾很簡單(Git revert,重新部署)
  • 擴展是可靠的(所有新實例與現有實例相同)
  • 自我修復實際上有效(沒有隱藏狀態需要擔心)

系列中的下一個

隨著可觀測性、自動化、控制迴圈和不可變基礎設施到位,最後一層是人類監督:為一個主要自我控制的系統重新設計人的角色。閱讀 Layer 4

在 AIDARIS,我們幫助組織構建實際有效的不可變基礎設施,並獲得在其之上自動化修復的信心。如果你從可變轉向不可變並對前進的道路不確定,我們很想幫助