IaC Part 6-使用Stack構建環境
我們在 IaC Part 5中將Infra Satck定義為single unit來管理的基礎架構資源的集合。 環境(如生產或測試)也是基礎設施資源的集合。 那麼stack和環境是一樣的嗎? 本文將會解釋"也許是,但也許不是"。
環境是圍繞特定目的軟體和基礎設施資源的集合。 Stack(或Stack sets)是定義和管理基礎設施資源集合的一種方法。 因此,我們可以使用一個stack或多個stack來建立一個環境。 我們可以是一個stack是一個環境,也可以從多個stack組成一個環境。 我們甚至可以在一個stack中建立多個環境,雖然不應該這麼做。
什麼是環境?
環境的概念是我們在 IT 領域中理所當然的思維。 但當我們在不同的背景脈絡中使用該術語時,我們的含義通常會略有不同。 在本系列文章中,環境是與運作相關的基礎設施資源的集合。 也就是說,環境中的資源支援特定活動,例如測試或運作系統。 大多數情況下,都會存在多個環境,每個環境都運行同一個系統的一個insatnce。
讓多個環境運行同一個系統的instance有兩種典型的案例。 一是支持交付流程,二是運行系統的多個production instance。
交付環境
多個環境最熟悉的案例是支援漸進式軟體發布流程 — — 有時稱為path to production。 應用程式的給特定構建依次部署到每個環境,以支援不同的開發和測試作業,直到最終部署到生產環境(如下圖)。
我們會使用上圖這組環境來說明將環境定義為代碼的模式。
多個生產環境
我們有可能需要多個完整、獨立地且一模一樣的生產環境系統。 這樣做的原因包括:
- Fault tolerance
- Scalability(通常佈署於多個region,也能達到Fault tolerance)
- Segregation(針對不同的使用者,通常是為了當地的法規法令問題)
環境、一致性與配置(Configuration)
由於多個環境旨在運行同一系統的instance,因此每個環境中的基礎設施應該保持一致。 跨環境的一致性是IaC的主要驅動力之一。
環境之間的差異會帶來行為不一致的風險。 在一種環境中軟體測試可能無法發現在另一種環境中會發生的問題。 甚至有可能軟體在某些環境中部署成功,但在其他環境中部署卻失敗。
另一方面,我們通常需要環境之間存在一些特定的差異。 測試環境可能比生產環境規格要小。 不同的使用者在不同的環境中可能擁有不同的權限。 不同客戶的環境可能有不同的功能和特點。 至少,名稱和 ID 可能不同(server-test、server-stage、server-prod)。 因此,我們至少需要配置不同環境的不同面向。
環境的一個關鍵考量因素是我們的測試和交付策略。 當相同的基礎設施代碼應用於每個環境時,在一個環境中對其進行測試往往會讓我們確信它可以在其他環境中正常作業。 然而,如果instance之間的基礎設施差異很大,不確性就很大。
我們可以通過使用不同的配置值測試基礎架構代碼來加強信心。 然而,測試許多不同的值可能不切實際。 在這些情況下,我們可能需要額外的驗證,例如配置後的測試或監控生產環境。
構建環境的模式
正如我們之前提到的,環境是基礎設施元素的概念性集合(conceptual collection),Stack是基礎設施元素的具體集合(concrete collection)。 Stack project是用於建立一個或多個stack project的source code。 那麼應該如何使用stack project和instance來建立環境呢? 我們將描述使用Infra Satck實現環境的兩種錯誤模式和一種正確模式。 這些模式中的每一個都描述了一種使用Infra stack定義多個環境的方法。 有些系統由多個stack組成。
錯誤模式: 多環境Stack
這是將多個環境的基礎架構定義為單一stack instance並進行管理。例如,如果有三個環境用於測試和運作應用程式,則單一stack project包含所有三個環境的代碼(如下圖)。
動機
許多人在學習新的stack tool時都會建立這種類型的結構,因為將新環境加到到現有project中是很直覺的作法。
後果
當我們要更新stack instance時,潛在的變更範圍是stack中的所有內容。 如果我們的代碼中有錯誤或衝突,則insatnce中的所有內容都是有弱點的。
當我們的生產環境與另一個環境位於同一stack instance中時,更改其他環境可能會導致生產環境有問題。 當我們只想更改測試環境時,編碼錯誤、意外的依賴關係甚至工具中的錯誤都可能會破壞生產環境。
相關模式
我們可以通過將環境劃分為單獨的stack來限制變更的影響範圍。 一種明顯的方法是複製-貼上環境,其中每個環境都是一個單獨的stack project,儘管這被認為是一種錯誤模式。更好的方法是reuseable stack模式。 單一peoject用於定義環境的通用結構,然後用於管理每個環境的單獨stack instance。
錯誤模式: 複製-貼上環境
複製-貼上模式為每個Infra stack insatnce使用單獨的stack source code project。
在我們的名為test、staging和production的三個環境範例中,每個環境都有一個單獨的Infra project(如下圖)。 通過在其中一個環境中編輯代碼,然後將變更是依次複製到其他環境中。
動機
複製-貼上環境是維護多個環境的直觀方法。 它們避免了multiheaded stack模式的影響範圍問題。 我們還可以輕易的自定義每個stack insatnce。
適用性
如果我們想要維護和變更不同的isnatcne並且不考慮代碼重複或一致性,複複製-貼上環境可能是合適的。
後果
維護多個複製-貼上環境可能具有挑戰性。 當我們想要更改代碼時,需要將其複製到每個project中。 我們可能需要單獨測試每個instance,因為變更可能在一個insatnce中會動,但在另一個insatnce中不會動。
複製-貼上環境經常會出現configuration drift。 由於一個環境與下一個環境之間的不一致,使用複製-貼上環境作為交付環境會降低部署過程的可靠性和測試的有效性。 複製-貼上環境在首次設置時可能是一致的,但隨著時間的推移,差異會逐漸顯現。
實行
我們可以通過將project code從一個stack insatnce複製到new porject來建立複製-貼上環境。 然後,我們可以編輯代碼以針對new insatnce進行客製。 當我們對一個stack進行變更時,我們需要將其複製並貼上到所有其他stack project中,同時保留每個stack project中的自定義設置。
相關模式
Environment branches可以被認為是複製-貼上環境的一種形式。 每個brnach都有代碼的副本,通過合併在branch之間複製代碼。 持續套用代碼可以避免複製-貼上的陷阱,因為它保證代碼不會從一個環境修改到下一個環境。 編輯代碼作為將其合併到environment branch的一部分會產生複製-貼上模式的危險。
Wrapper stack 模式也類似於複製-貼上環境。 Wrapper stack為每個環境使用單獨的stack project來設定配置參數。 但是stack的代碼是在stack components中實現的,例如reusable module code。 該代碼本身並不是為每個環境複製-貼上的,而是像可重複使用stack一樣進行遞升。 但是,如果人們向wrapper stack projects加入的不僅僅是基本的stack instance parameters,它可能會演變成複製-貼上模式。在stack instance是相同stack的情況下,reusable stack模式通常更合適。
模式: Reusable Stack
這是是一種infrastructure source code project,用於建立stack的多個insatnce(如下圖)。
動機
我們建立reusable stack來維護基礎架構的多個一致性isnatnce。 當我們對stack code 進行變更時,我們可以在一個isnatcne中應用和測試它,然後使用相同的代碼版本來建立或更新多個其他isnatcne。 我們希望以最少的動作(甚至可能是自動的)來配置stack的new instance。
例如,公司有多個B2B客戶,我們團隊從每個使用application server的不同stack project中提取了通用代碼。 團隊成員將通用代碼放入每個stack project使用的module中。 後來,他們意識到客戶應用程式的stack project看起來仍然非常相似。 除了使用建立application server的mpdule,每個stack都有為每個客戶建立資料庫以及專用日誌記錄和報告服務的代碼。
在多個客戶之間變更和測試此代碼變得很麻煩,而且公司每個月都會註冊新客戶。 因此,團隊決定建立一個定義客戶application stack的單一stack project。 這個project仍然使用shared Java application server module,其他一些應用程式也是如此。 但該project還具有用於設置其他每個客戶基礎設施的代碼。
現在,當公司簽約新客戶時,團隊成員使用通用的customer stack project來建立new instance。 當他們修復或改進projetc codebase中的某些內容時,他們會將其應用於test insatnce以確保其正常,然後將其一一roll out到customer instance。
適用性
我們可以將reusable stack用於交付環境或多個生產環境。 當我們不需要環境之間有太多差異時,此模式非常有用。 當每個環境差異很大時,就不太適用。
後果
從同一project配置和更新多個stack的能力強化了scalability、reliability還有throughput。 我們可以以更少的作業管理更多instance,以更低的失敗風險進行變更,並更快地將變更推到更多系統。
我們通常需要針對不同的insatnce以不同的方式配置stack的某些面向,即使這只是名稱。 在將變更應用於關鍵業務基礎設施之前,我們應該測試stack project code。
實行
我們建立一個reusable stack作為Infra stack project,然後在每次要建立或更新stack instance時運行管理工具。 使用 stack 工具命令的語法告訴它我們要建立或更新哪個instance。 例如,使用 Terraform,我們可以為每個insatnce指定不同的state file或workspace。 使用 CloudFormation,可以為每個instance傳遞一個unique stack ID。
以下範例命令使用名為 stack 的虛構命令從單一project產出兩個stack instance。 該命令採用一個參數 env 來標識unique instances:
> stack up env=test --source mystack/src
SUCCESS: stack 'test' created
> stack up env=staging --source mystack/src
SUCCESS: stack 'staging' created
一般來說,我們應該使用簡單的參數來定義stack instance之間的差異 — strings、numbers,或者稍微複雜一點用list。 此外,由reusable stack建立的基礎設施在不同insatnce之間不應有太大差異。
相關模式
Reusable stack是對複製-貼上環境錯誤模式的改進,可以更輕易地保持多個insatnce的一致性。
Wrapper stack模式使用stack components來定義reusable stack,但使用不同的stack project來為每個實insatnce設置參數值。
使用multiple stack構建環境
Reusable stack模式描述了一種實現多個環境的方法。 在IaC part 5中,我們描述了跨多個堆stack構建系統基礎架構的不同方法。 可以通過多種方式來實現stack,以將環境和系統結構這兩個維度結合起來。
簡單的案例是將整個系統實現為單一個stack。 當我們配置stack的instance時,我們就有了一個完整的環境(如上圖)。
但我們應該將較大的系統分成多個stack。 例如,如果遵循service stack模式,則每個服service都有一個單獨的stack(如下圖)。
要建立多個環境,我們需要為每個環境配置每個service stack的instance(如下圖)。
我們可以使用以下命令來構建具有多個stack的完整環境:
> stack up env=staging --source product_browse_stack/src
SUCCESS: stack 'product_browse-staging' created
> stack up env=staging --source product_search_stack/src
SUCCESS: stack 'product_search-staging' created
> stack up env=staging --source shopping_basket_stack/src
SUCCESS: stack 'shopping_basket-staging' created
結論
對於大多數需要管理大型基礎設施的團隊來說,Reusable stack應該是主要模式。 Stack是用於測試和交付更改的有效的unit。 它確保環境的每個instance都以一致的方式定義和構建。 作為變更的unit的stack(而不是module)的全面性強化了快速、頻繁地交付變更的能力。