在設計現代基礎設施時,模組化思維已成為不可或缺的核心理念。隨著系統規模擴大,單一龐大的基礎設施堆積積疊往往會變得難以維護和更新。透過將基礎設施分解為小型、簡單的元件,我們能夠大幅提升系統的可維護性、可測試性和變更靈活度。
堆積積疊模組與程式函式庫的雙面性
堆積積疊模組和程式函式庫確實能夠促程式式碼重用,但它們在簡化堆積積疊變更方面的效果卻相對有限。在實務中,我曾見過許多團隊試圖透過將程式碼拆分為模組來改善單體堆積積疊架構。雖然這種做法確實使程式碼更易於理解,但每個堆積積疊例項的規模和複雜度卻沒有實質性的減少。
當我們將程式碼分離為獨立模組時,這些模組最終仍會被合併到堆積積疊例項中,如下圖所示:
graph TD A[模組 A] --> D[堆積積疊例項] B[模組 B] --> D C[模組 C] --> D style D fill:#f96,stroke:#333,stroke-width:2px
這種模組化方法存在兩個主要問題:
- 複雜度累加:每個模組都會為堆積積疊例項增加元素,使整體複雜度持續增長
- 跨堆積積疊耦合:當一個模組被多個堆積積疊使用時,會在這些堆積積疊之間建立耦合關係。為了滿足一個堆積積疊的需求而修改模組,可能會影響使用該模組的其他堆積積疊,增加變更的摩擦成本
更有效的方法是將大型堆積積疊拆分為多個獨立的小型堆積積疊,每個堆積積疊都可以獨立佈建、管理和變更。這種微型堆積積疊(Micro Stack)的設計理念將在後續章節中詳細探討。
在堆積積疊中使用伺服器是基礎設施堆積積疊中最常見的元件型別之一。堆積積疊程式碼通常透過伺服器映像和伺服器設定模組來整合伺服器,通常是透過指定角色來實作。
以下是一個使用伺服器映像作為堆積積疊元件的例項。假設我們有一個名為 cluster_of_host_nodes
的堆積積疊,用於建立一個作為容器主機節點的伺服器叢集:
graph LR A[伺服器映像] -->|提供者| B[伺服器叢集堆積積疊] style A fill:#bbf,stroke:#333,stroke-width:1px style B fill:#fbf,stroke:#333,stroke-width:1px
定義伺服器叢集的程式碼指定了伺服器映像的名稱 host_node_image
:
server_cluster:
name: "cluster_of_host_nodes"
min_size: 1
max_size: 3
each_server_node:
source_image: host_node_image
memory: 8GB
這段 YAML 定義了一個名為 cluster_of_host_nodes
的伺服器叢集,設定了最小節點數為 1,最大節點數為 3。每個節點都使用 host_node_image
作為基礎映像,並設定了 8GB 的記憶體。這種設定允許叢集根據負載自動擴充套件或縮減節點數量。
團隊使用一個管道來建置和測試伺服器映像的變更,另一個管道則測試 cluster_of_host_nodes
的變更,將其與透過測試的最新版本 host_node_image
整合:
graph LR A[伺服器映像管道] -->|測試透過的映像| B[叢集堆積積疊管道] B -->|整合測試| C[佈署] style A fill:#bbf,stroke:#333,stroke-width:1px style B fill:#fbf,stroke:#333,stroke-width:1px style C fill:#bfb,stroke:#333,stroke-width:1px
然而,這個設計存在一個小問題:cluster_of_host_nodes
堆積積疊的第一個管道階段實際上並不使用 host_node_image
。但堆積積疊程式碼中包含了伺服器映像的名稱,因此無法作為線上測試階段執行。在不佈建完整主機節點伺服器的情況下測試堆積積疊程式碼可能很有用,這樣團隊可以在不需要佈建資源密集型伺服器的情況下發現堆積積疊程式碼的問題。
解決方案是將硬編碼的 host_node_image
從堆積積疊程式碼中提取出來,改用堆積積疊引數:
server_cluster:
name: "cluster_of_host_nodes"
min_size: 1
max_size: 3
each_server_node:
source_image: ${HOST_NODE_SERVER_IMAGE}
memory: 8GB
這個改進版本使用了引數化的方式定義伺服器映像,透過 ${HOST_NODE_SERVER_IMAGE}
變數參照映像名稱,而非硬編碼。這種方法大提高了程式碼的可測試性和靈活性,允許在不同環境或測試場景中使用不同的伺服器映像。
cluster_of_host_nodes
堆積積疊的線上測試階段可以設定 HOST_NODE_SERVER_IMAGE
引數,使用精簡版的伺服器映像 ID。團隊可以在這個階段執行測試,驗證伺服器叢集是否正常工作,包括擴充套件和還原失敗例項的能力。精簡版的伺服器映像是測試替身的一個例子。
這個簡單的變更—將硬編碼的伺服器映像參照替換為引數—減少了耦合度,同時遵循了組合規則。團隊可以輕鬆地使用不同的伺服器映像建立 cluster_of_host_nodes
的例項,這在團隊想要測試和逐步推出不同作業系統的叢集時特別有用。
無分享基礎設施
在分散式運算領域,無分享架構(shared-nothing architecture)透過確保新節點可以被增加到系統中而不會增加對節點外部資源的爭用,從而實作擴充套件。
典型的反例是處理器分享單一磁碟的系統架構。對分享磁碟的爭用限制了系統在增加更多處理器時的擴充套件性。從設計中移除分享磁碟意味著系統可以透過增加處理器實作接近線性的擴充套件。
在基礎設施程式碼中實作無分享設計,意味著將資源從分享堆積積疊移動到每個需要這些資源的堆積積疊中,消除提供者-消費者關係。例如,團隊可以將應用程式基礎設施堆積積疊和分享網路堆積積疊合併為單一堆積積疊。
每個應用程式基礎設施例項都有自己完整的網路結構集。這雖然複製了網路結構,但保持了每個應用程式例項的獨立性。與分散式系統架構一樣,這消除了擴充套件限制。例如,團隊可以根據需要增加任意數量的應用程式基礎設施例項,而不會耗盡單一分享網路堆積積疊分配的地址空間。
但使用無分享基礎設施程式碼設計的更常見動機是使修改、重建和還原應用程式堆積積疊的網路資源變得更容易。分享網路堆積積疊設計增加了使用網路的爆炸半徑和管理開銷。
無分享基礎設施也支援零信任安全模型,因為每個堆積積疊可以單獨進行安全設定。
無分享設計不要求將所有內容放入單一堆積積疊例項。對於團隊來説,將網路和應用程式基礎設施合併到單一堆積積疊的替代方案是像以前一樣在不同堆積積疊中定義網路和應用程式基礎設施,但為每個應用程式堆積積疊例項建立一個單獨的網路堆積積疊例項:
graph TD subgraph "應用A" A1[網路堆積積疊A] --> B1[應用堆積積疊A] end subgraph "應用B" A2[網路堆積積疊B] --> B2[應用堆積積疊B] end subgraph "應用C" A3[網路堆積積疊C] --> B3[應用堆積積疊C] end style A1 fill:#bbf,stroke:#333,stroke-width:1px style A2 fill:#bbf,stroke:#333,stroke-width:1px style A3 fill:#bbf,stroke:#333,stroke-width:1px style B1 fill:#fbf,stroke:#333,stroke-width:1px style B2 fill:#fbf,stroke:#333,stroke-width:1px style B3 fill:#fbf,stroke:#333,stroke-width:1px
使用這種方法,應用程式堆積積疊例項不與其他堆積積疊分享網路,但兩個部分可以獨立管理。這樣做的限制是所有網路堆積積疊例項仍由相同的程式碼定義,因此對程式碼的任何變更都需要額外的工作來確保不會破壞任何例項。
在元件之間劃分邊界
要劃分基礎設施(如同任何系統),應該尋找接縫(seams)。接縫是一個地方,你可以在不編輯該處的情況下改變系統中的行為。這個概念是尋找自然的地方來劃分系統部分之間的邊界,在那裡你可以建立簡單、乾淨的整合點。
以下策略根據特定關注點對基礎設施元素進行分組:變更模式、組織結構、安全與治理,以及彈性與擴充套件。這些策略,如同大多數架構原則和實踐,歸結為最佳化變更。這是一種設計元件的追求,使你能夠更容易、更安全、更快速地對系統進行變更。
根據自然變更模式調整邊界
最佳化元件邊界以適應變更的最基本方法是瞭解它們的自然變更模式。這就是尋找接縫的理念—接縫是一個自然的邊界。
對於現有系統,你可以透過檢查歷史變更來瞭解哪些元素通常一起變更。更細粒度的變更,如程式碼提交,提供最有用的洞察。最有效的團隊最佳化頻繁提交,完全整合和測試每一個提交。透過瞭解哪些元件傾向於作為單一提交的一部分一起變更,或者跨元件的密切相關提交,你可以找到建議如何重構程式碼以提高內聚性和減少耦合的模式。
檢查更高層次的工作,如工單、故事或專案,可以幫助你瞭解系統的哪些部分經常涉及一組變更。但你應該最佳化小型、頻繁的變更。因此,確保深入瞭解哪些變更可以獨立於其他變更進行,以便在更大的變更計劃背景下實作增量變更。
根據元件生命週期調整邊界
基礎設施的不同部分可能有不同的生命週期。例如,叢集中的伺服器每天可能被建立和銷毀多次。而資料函式庫儲存卷的變更頻率則較低。
根據生命週期將基礎設施資源組織成可佈署的元件,特別是基礎設施堆積積疊,可以簡化管理。考慮一個由網路由、伺服器叢集和資料函式庫例項組成的應用程式伺服器基礎設施堆積積疊。
這個堆積積疊中的伺服器至少每週更新一次,使用具有最新作業系統補丁的新伺服器映像重建。資料函式庫儲存裝置很少變更,儘管可能會建立新例項以還原或複製應用程式例項。團隊偶爾會變更其他堆積積疊中的網路,這需要更新此堆積積疊中的應用程式特定路由。
將這些元素定義在單一堆積積疊中可能會帶來一些風險。對應用程式伺服器映像的更新可能會失敗。修復問題可能需要重建整個堆積積疊,包括資料函式庫儲存裝置,這反過來需要備份資料以還原到新例項。雖然可以在單一堆積積疊中管理這一點,但如果資料函式庫儲存定義在單獨的堆積積疊中會更簡單:
graph TD A[網路路由堆積積疊] --> D[應用程式] B[伺服器叢集堆積積疊] --> D C[資料函式庫儲存堆積積疊] --> D style A fill:#bbf,stroke:#333,stroke-width:1px style B fill:#fbf,stroke:#333,stroke-width:1px style C fill:#fbb,stroke:#333,stroke-width:1px style D fill:#bfb,stroke:#333,stroke-width:1px
對這些微型堆積積疊中的任何一個進行變更,不會直接影響其他堆積積疊。這種方法可以啟用堆積積疊特定的管理事件。例如,對資料函式庫儲存堆積積疊的任何變更可能會觸發資料備份,這對於第一個組合堆積積疊的每次變更來説可能成本太高。
根據生命週期最佳化堆積積疊邊界對於管道中的自動化測試特別有用。管道階段通常在人們處理基礎設施變更時每天執行多次,因此需要最佳化以提供快速反饋並保持良好的工作節奏。根據生命週期將基礎設施元素組織到單獨的堆積積疊中可以減少應用變更進行測試所需的時間。
例如,在處理應用程式伺服器的基礎設施程式碼時,一些管道階段可能會每次重建堆積積疊。重建網路結構或大型資料儲存裝置可能很慢,並且對於涉及工作的許多變更可能不需要。在這種情況下,前面顯示的微型堆積積疊設計可以簡化測試和交付過程。
根據生命週期分離堆積積疊的第三個使用案例是成本管理。在安靜期間關閉或銷毀和重建不需要的基礎設施是管理公共雲成本的常見方式。但某些元素,如資料儲存,可能更難重建。你可以將這些分割到自己的堆積積疊中,並在其他堆積積疊被銷毀以降低成本時保持它們執行。
根據組織結構調整邊界
康威定律(Conway’s Law)表明,系統往往反映建立它的組織的結構。一個團隊通常發現整合它完全擁有的軟體和基礎設施更容易,而團隊自然會與其他團隊擁有的系統部分建立更硬的邊界。
康威定律對設計包括基礎設施在內的系統有兩個一般含義。一個是避免設計多個團隊需要進行變更的元件。另一個是考慮根據「逆康威操作」(Inverse Conway Maneuver)構建團隊以反映你想要的架構邊界。
對於基礎設施,特別值得考慮如何將設計與使用基礎設施的團隊結構保持一致。在大多陣列織中,這些是產品或服務線和應用程式。即使是多個團隊使用的基礎設施,如 DBaaS 服務,你也可以設計你的基礎設施,以便可以為每個團隊管理單獨的例項。
將基礎設施例項與使用它們的團隊保持一致使變更不那麼具有破壞性。與其需要與所有使用分享例項的團隊協商單一變更視窗,你可以與每個團隊協商單獨的視窗。
建立支援彈性的邊界
當系統中的某些東西失敗時,你可以重建像基礎設施堆積積疊這樣的獨立可佈署元件。你可以手動修復或重建堆積積疊內的元素,進行基礎設施手術。基礎設施手術需要對基礎設施有深入瞭解的人謹慎干預。一個簡單的錯誤可能會使情況變得更糟。
有些人以基礎設施手術為榮,但這是一種退而求其次的方法,用來彌補基礎設施管理系統中的差距。
基礎設施手術的替代方案是使用明確定義的流程和工具重建元件。你應該能夠透過觸發與應用變更和更新相同的自動化流程來重建任何堆積積疊例項。如果你能做到這一點,當半夜某些東西失敗時,你不需要喚醒你最聰明的基礎設施外科醫生。在許多情況下,你可以自動觸發還原。
基礎設施元件需要設計成能夠快速重建和還原。如果你根據生命週期將資源組織到元件中,那麼你也可以考慮重建和還原使用案例。
前面包含持久資料的基礎設施分割範例就做到了這一點。重建資料儲存的過程應該包括自動儲存和載入資料的步驟,這在災難還原場景中會派上用場。
將基礎設施劃分為根據其重建過程的元件有助於簡化和最佳化還原。另一種彈性方法是執行基礎設施部分的多個例項。冗餘策略也可以幫助擴充套件。
建立支援擴充套件的邊界
擴充套件系統的常見策略是建立其某些元件的額外例項。你可能會在需求較高的時期增加例項,你也可能考慮在不同的地理區域佈署例項。
大多數人都知道,大多數雲平台可以隨著負載變化自動擴充套件伺服器叢集。FaaS 無伺服器的一個關鍵好處是它只在需要時執行程式碼例項。
然而,基礎設施的其他元素,如資料函式庫、訊息佇列和儲存裝置,在計算擴充套件時可能成為瓶頸。而與,軟體系統的不同部分可能成為瓶頸,即使撇開基礎設施不談。
例如,團隊可以佈署產品瀏覽服務堆積積疊的多個例項來應對更高的負載,因為大多數使用者流量在高峰時間會命中系統的那部分。團隊保持其前端流量路由堆積積疊的單一例項,以及應用程式伺服器例項連線的資料函式庫堆積積疊的單一例項:
graph TD A[前端流量路由堆積積疊] --> B1[產品瀏覽服務堆積積疊 1] A --> B2[產品瀏覽服務堆積積疊 2] A --> B3[產品瀏覽服務堆積積疊 3] B1 --> C[資料函式庫堆積積疊] B2 --> C B3 --> C style A fill:#bbf,stroke:#333,stroke-width:1px style B1 fill:#fbf,stroke:#333,stroke-width:1px style B2 fill:#fbf,stroke:#333,stroke-width:1px style B3 fill:#fbf,stroke:#333,stroke-width:1px style C fill:#fbb,stroke:#333,stroke-width:1px
系統的其他部分,如訂單結帳和客戶資料管理服務,可能不需要與產品瀏覽服務一起擴充套件。將這些服務分割成不同的堆積積疊有助於團隊更快地擴充套件它們。它減少了複製所有內容會產生的浪費。
優先考慮垂直分組而非水平分組
傳統上,許多架構師按功能組織系統。網路相關的東西放在一起,資料函式庫相關的東西放在一起,作業系統相關的東西放在一起。這通常是組織設計的結果,正如康威定律所預測的那樣—當團隊圍繞這些技術、功能專業組織時,他們會根據他們管理的內容劃分基礎設施。
這種方法的陷阱是,提供給使用者的服務橫跨許多功能。這通常被顯示為垂直服務穿越水平功能層,如下圖所示:
graph TD subgraph "服務 A" A1[網路] --> A2[資料函式庫] --> A3[應用伺服器] end subgraph "服務 B" B1[網路] --> B2[資料函式庫] --> B3[應用伺服器] end subgraph "服務 C" C1[網路] --> C2[資料函式庫] --> C3[應用伺服器] end style A1 fill:#bbf,stroke:#333,stroke-width:1px style A2 fill:#fbf,stroke:#333,stroke-width:1px style A3 fill:#fbb,stroke:#333,stroke-width:1px style B1 fill:#bbf,stroke:#333,stroke-width:1px style B2 fill:#fbf,stroke:#333,stroke-width:1px style B3 fill:#fbb,stroke:#333,stroke-width:1px style C1 fill:#bbf,stroke:#333,stroke-width:1px style C2 fill:#fbf,stroke:#333,stroke-width:1px style C3 fill:#fbb,stroke:#333,stroke-width:1px
將系統元素組織成跨切功能的基礎設施堆積積疊有兩個缺點。一個是對一個服務的基礎設施的變更可能涉及對多個堆積積疊進行變更。這些變更需要仔細協調,以確保在提供者堆積積疊中出現依賴關係之前,不會在消費者堆積積疊中引入依賴關係。
將單一服務的基礎設施所有權分散到多個功能團隊中,為任何一個服務的變更增加了相當大的溝通開銷和流程。
功能堆積積疊的第二個缺點在於它們跨服務分享時出現。在下圖中,伺服器團隊管理一個具有多個服務伺服器的單一堆積積疊例項:
graph TD subgraph "伺服器團隊堆積積疊" A1[服務A伺服器] A2[服務B伺服器] A3[服務C伺服器] end A1 --> B1[服務A] A2 --> B2[服務B] A3 --> B3[服務C] style A1 fill:#bbf,stroke:#333,stroke-width:1px style A2 fill:#bbf,stroke:#333,stroke-width:1px style A3 fill:#bbf,stroke:#333,stroke-width:1px style B1 fill:#fbf,stroke:#333,stroke-width:1px style B2 fill:#fbf,stroke:#333,stroke-width:1px style B3 fill:#fbf,stroke:#333,stroke-width:1px
當團隊變更其中一個服務的伺服器時,存在破壞其他服務的風險,因為堆積積疊邊界代表變更的爆炸半徑。
根據安全和治理關注點調整邊界
安全、合規和治理保護資料、交易和服務可用性。系統的不同部分將有不同的規則。例如,PCI 安全標準對處理信用卡號碼或支付處理的系統部分施加要求。客戶和員工的個人資料通常需要更嚴格的控制。
許多組織根據適用於其託管的服務和資料的法規和政企劃分其基礎設施。這樣做可以清楚地評估需要對給定的基礎設施元件採取哪些措施。交付變更的流程可以根據治理要求量身定製。例如,流程可以強制執行和記錄審查和批准,並生成簡化稽核的變更報告。
在設計基礎設施時,將系統分解為小型、簡單的元件是提高可維護性和變更靈活度的關鍵。我們探討了多種劃分基礎設施邊界的策略,包括根據自然變更模式、元件生命週期、組織結構、彈性需求和擴充套件需求。
無分享基礎設施設計提供了更高的獨立性和彈性,允許團隊獨立管理和擴充套件系統的不同部分。透過優先考慮垂直分組而非水平分組,我們可以減少變更的協調開銷和爆炸半徑。
最終,基礎設施設計的目標是最佳化變更—使系統更容易、更安全、更快速地演進。透過仔細考慮元件邊界,我們可以建立更具彈性、更易於維護的基礎設施系統,更好地支援業務需求。
在實踐中,沒有一種完美的方法適用於所有情況。最佳的基礎設施設計將根據特定組織的需求、團隊結構和技術堆積積疊進行調整。關鍵是理解不同設計決策的權衡,並選擇最適合你特定情境的方法。
模組化基礎設施:提升重用性與變更速度
基礎設施系統的設計品質直接影響其變更速度與安全性。精心設計的元件能讓基礎設施系統更容易與更安全地進行變更,這支援了持續改進系統品質的理念,同時高品質的系統也能實作更快速的變更。本文將探討基礎設施堆積積疊的模組化策略,以及如何透過拆分程式碼來提升系統的彈性與可維護性。
模組化基礎設施堆積積疊的核心優勢
模組化基礎設施堆積積疊,即將堆積積疊拆分為較小的程式碼單元,能為團隊帶來多方面的優勢:
知識重用與標準化
將特定基礎設施結構的實作知識封裝到元件中,使其能在不同堆積積疊間重複使用,是模組化的首要優勢。當玄貓在設計雲端資源管理系統時,發現將常用的網路安全組態或資料函式庫叢集設定抽象為可重用元件,不僅減少了重複工作,更確保了組織內的一致性標準。
這種重用機制使團隊能夠:
- 建立組織內的最佳實踐函式庫
- 確保安全與合規要求的一致性
- 減少因重複實作而產生的錯誤
靈活的組合能力
模組化設計的另一個關鍵優勢是組合能力。透過建立概念的不同實作版本,團隊可以在建構堆積積疊時擁有更大的靈活性。例如,一個資料儲存元件可以有多種實作方式:
module "storage" {
source = "./modules/s3-storage"
# 引數設定
}
// 或者在需要關聯式資料函式庫時
module "storage" {
source = "./modules/rds-storage"
# 引數設定
}
這段程式碼展示了 Terraform 中模組化的實際應用。透過定義不同的儲存模組(S3 物件儲存和 RDS 關聯式資料函式庫),團隊可以根據需求選擇適合的實作方式,而不需修改依賴這些儲存服務的其他程式碼。這種抽象層次讓系統更容易適應需求變化,同時保持介面一致性。
提升測試效率
將堆積積疊拆分為可獨立測試的元件,能顯著提升測試的速度和專注度。在實際工作中,玄貓發現模組化的基礎設施程式碼可以實作更精確的測試策略:
- 隔離測試:每個元件可以獨立測試,不受其他元件影響
- 測試替身:可組合的元件可以用測試替身(test doubles)替換,進一步提高測試的隔離性和速度
- 快速反饋:小型元件的測試執行更快,提供更快的開發反饋迴圈
跨團隊分享與協作
可組合、可重用與經過良好測試的元件可以在團隊間分享,使人們能夠更快地構建更好的系統。這種分享機制促進了:
- 組織知識的擴散
- 減少重複工作
- 標準化實踐的採用
- 提高整體系統品質
模組化的潛在陷阱
雖然模組化帶來諸多好處,但也存在一些需要注意的陷阱。正如在基礎設施管理中常見的情況,將堆積積疊拆分為模組和程式函式庫確實簡化了程式碼,但這並不會使堆積積疊例項變得更小或更簡單。
抽象層的隱藏複雜性
堆積積疊元件有可能透過掩蓋它們增加到堆積積疊例項中的基礎設施資源數量和複雜性,使情況變得更糟。例如,一個看似簡單的「網路模組」可能在背後建立了數十個相互關聯的資源:
module "network" {
source = "./modules/network"
vpc_cidr = "10.0.0.0/16"
environment = "production"
}
這個看似簡單的網路模組呼叫可能在背後建立了 VPC、多個子網路、路由表、網路 ACL、NAT 閘道、網際網路閘道等多個資源。如果工程師不瞭解這些隱藏的複雜性,可能會在故障排除或成本管理時遇到困難。模組化雖然簡化了使用,但不應該成為理解系統實作的障礙。
理解抽象層之下的實作
因此,理解你所使用的抽象、程式函式庫和平台背後的實作至關重要。這些工具是一種便利,可以讓你專注於更高層次的任務,但它們不應該成為完全理解系統實作方式的替代品。
在玄貓的實踐中,發現以下策略有助於平衡抽象與理解:
- 定期檢視生成的資源:使用基礎設施即程式碼工具的計劃(plan)功能,檢視模組將建立哪些實際資源
- 檔案化元件行為:為每個元件提供清晰的檔案,説明它建立的資源及其關係
- 視覺化依賴關係:使用圖表工具展示元件之間以及元件與底層資源之間的關係
graph TD A[應用堆積積疊] --> B[網路模組] A --> C[計算模組] A --> D[資料函式庫模組] B --> E[VPC] B --> F[子網路] B --> G[安全群組] C --> H[EC2 例項] C --> I[自動擴充套件群組] D --> J[RDS 例項] D --> K[備份政策]
基礎設施元件的語言選擇
隨著工具供應商快速發展其策略,基礎設施即程式碼的語言選擇也在不斷演進。在選擇用於堆積積疊元件的基礎設施語言時,需要考慮以下因素:
- 表達能力:語言是否能夠清晰地表達基礎設施的意圖和關係
- 型別安全:強型別系統可以在編譯時捕捉錯誤,減少執行時問題
- 測試支援:語言和相關工具對測試的支援程度
- 生態系統:可用的程式函式庫、元件和社群支援
在實際應用中,玄貓發現不同的語言和工具適合不同的場景:
- 宣告式語言(如 HCL、YAML)適合描述資源的期望狀態
- 通用程式語言(如 Python、TypeScript)在需要複雜邏輯和條件處理時更有優勢
- 特定領域語言(如 CDK)結合了兩者的優點,但可能增加學習曲線
模組化策略的實際應用
在實施基礎設施模組化時,玄貓建議採用以下策略:
由小到大的漸進式方法
從識別常用模式開始,將其抽象為小型、專注的元件。隨著時間推移,這些元件可以組合成更大的功能單元。例如,從網路安全規則開始,然後擴充套件到完整的網路設定。
明確的介面設計
為元件定義清晰的輸入和輸出介面,使其易於理解和使用:
variable "vpc_cidr" {
description = "CIDR block for the VPC"
type = string
validation {
condition = can(cidrnetmask(var.vpc_cidr))
error_message = "Must be a valid CIDR block."
}
}
output "subnet_ids" {
description = "IDs of all subnets created within the VPC"
value = aws_subnet.this[*].id
}
這段程式碼展示了良好的元件介面設計。輸入變數(variable)包含描述、型別定義和驗證規則,確保使用者提供有效的 CIDR 區塊。輸出(output)清晰地説明瞭它提供的內容,使元件的使用者知道可以取得哪些資訊。這種明確的介面設計使元件更容易理解和正確使用。
版本控制與變更管理
對分享元件實施嚴格的版本控制和變更管理,確保向後相容性或提供清晰的升級路徑:
module "network" {
source = "company/network/aws"
version = "~> 2.0.0" # 只接受 2.0.x 版本的更新
# 模組引數
}
這段程式碼示範瞭如何在 Terraform 中使用版本約束來控制模組的版本。~> 2.0.0
表示只接受 2.0.x 系列的更新(例如 2.0.1、2.0.2 等),但不會自動升級到 2.1.0 或更高版本。這種版本控制策略可以確保系統穩定性,同時允許接收安全修補和小型改進。
結合速度與品質的模組化實踐
模組化基礎設施堆積積疊是實作變更速度與系統品質相互促進的關鍵策略。透過將基礎設施程式碼拆分為可重用、可組合和可測試的元件,團隊可以更快地構建高品質系統,同時保持對底層實作的理解。
在實施模組化策略時,重要的是平衡抽象的便利性與系統透明度,確保團隊既能快速工作,又能完全理解和控制其基礎設施。隨著工具和語言的不斷發展,基礎設施元件化將繼續成熟,為組織提供更強大的基礎設施管理能力。
模組化不僅是一種技術實踐,更是一種思維方式,它鼓勵我們將複雜系統分解為可理解、可管理的部分,從而在保持系統品質的同時,加速變更和創新的步伐。