IaC Part 5-將Infra Satck構建為代碼

本文結合了IaC part 3和4,描述使用代碼來管理基礎設施平台提供的基礎設施資源的方法。

概念是Infrastructure stack。 Stack是一起"定義與變更"的基礎設施資源的集合(Collection)。 使用stack management tool將stack中的資源一起配置以創建stack instance。 使用相同的工具對stack code進行更改並套用在insatnce。 本文將介紹對stack中的基礎設施資源進行分組的模式。

甚麼是Infrastructure Stack?

Infra Stack是我們作為一個Unit的"定義、配置和更新"的基礎設施資源的集合。(如下圖)

我們編寫source code來定義stack的元素,這些元素是基礎設施平台提供的資源和服務。 例如,我們的stack可能包括VM、disk volume和Subnet。我們運作stack management tool,該工具讀取stack source code並使用雲端平台的 API 來組合代碼中定義的元素以配置stack instance。stack management tools有:

  • HashiCorp Terraform
  • AWS CloudFormation
  • Azure Resource Manager
  • Google Cloud Deployment Manager
  • OpenStack Heat
  • Pulumi
  • Bosh

一些server configuration tool具有與infra stack配合使用的延伸。 例如 Ansible Cloud Modules、Chef Provisioning(現已停產)、Puppet Cloud Management 和 Salt Cloud。

Stack Code

每個stack都是由source code定義的,source code宣告了它應該包含哪些基礎設施元素。 Terraform code(.tf 檔案)和 CloudFormation template都是Infra stack code的範例。 Stack project包含定義infra stack的source code。 以下範例呈現了一個虛構的 Stackmaker 工具的stack source code proejct的檔案夾結構。

stack-project/
├── src/
│ ├── dns.infra
│ ├── load_balancers.infra
│ ├── networking.infra
│ └── webserver.infra
└── test/

Stack Instance

我們可以使用單一個stack project來配置多個stack instance。 當我們為project運作stack tool時,它會使用雲端平台的API 來確保stack instance存在,並使其與project code匹配。 如果stack instance不存在,則工具將創建它。 如果stack insatnce存在但與代碼不完全匹配,則該工具會修改該insatnce以使其匹配。

在Stack中配置伺服器

不是完全的container或serverless應用程式架構的系統的Infra codebase往往包含大量用於供啟用和配置Server的代碼。 即使基於container的系統也需要構建host server來運作container。 第一種主流IaC工具,如 CFEngine、Puppet 和 Chef,可用於配置server。

我們應該將構建server的代碼與構建stack的代碼分離。 這樣做可以使代碼更易於理解,通過decouple簡化變更,並支援重複使用和測試伺服器代碼。

Stack code通常指定要建立的server,並通過呼叫server configuration tool傳遞有關它們將運作的環境資訊。 以下範例是呼叫虛構的 servermaker 工具來配置服伺服器的stack definition。

virtual_machine:
name: webserver-waterworks-${environment}
source_image: jason-base-webserver
memory: 8GB
provision:
tool: servermaker
parameters:
maker_server: maker.jason.kao
role: webserverserver
environment: ${environment}

這個stack定義了一個web server instance,這個instance是從名為 jason-base-webserver的server image建立的,具有 8GB RAM。 該定義包含一個clause來觸發運行 Servermaker 的配置過程。 這個代碼還傳遞了幾個參數供 Servermaker 工具使用。 這些參數包括配置伺服器的地址,該伺服器託管configuration files; Servermaker 使用角色 webserver 來決定將哪些配置套用於該特定服伺服器。 它還傳遞環境名稱,配置可以使用該名稱來客製伺服器。

低階的Infrastructure Languages

大多數流行的stack management tool languages都是低階的基礎設施語言。 也就是說,該語言直接說明我們正在使用的基礎設施平台提供的資源。作為基礎設施IT人員,我們的工作就是編寫代碼,將這些資源連接在一起形成可以運作的東西,如下範例。

address_block:
name: application_network_tier
address_range: 10.5.0.0/24"
vlans:
- appserver_vlan_A
address_range: 10.5.0.0/16

virtual_machine:
name: jason_appserver_A
vlan: application_network_tier.appserver_vlan_A

gateway:
name: public_internet_gateway
address_block: application_network_tier

inbound_route:
gateway: public_internet_gateway
public_ip: 192.168.100.100
incoming_port: 443
destination:
virtual_machine: jason_appserver_A
port: 8443

這個上面這一段代碼範例定義了虛VM、address block和 VLAN 以及internet gateway。 然後,它將它們連結在一起並定義一個inbound connection,將進入 https://192.168.100.100 的連接路由到VM的8443 port。

平臺本身可以提供更高的抽象層; 例如,提供application hosting cluster。 平台提供的cluster element可以自動提供server instances與network routes。 但低階Infra code直接對映到平台 API 的資源和選項。

高階的Infrastructure Languages

高階的Infrastructure Languages的entitity不直接對映到底層平台提供的資源。 例如,上面的高階代碼版本可能宣告application server的基礎,如下所示。

application_server:
public_ip: 192.168.100.100

在這個範例中,套用代碼要嘛配置上一範例中的網路和伺服器資源,要嘛探索要使用的現有資源。 此代碼調呼叫的工具或library決定network port和 VLAN 使用哪些值,以及如何構建VM。

許多應用程序託管解決方案(例如 PaaS 平台)都提供此抽象層級。 我們為應用程式編寫deployment descriptor,平台會分配基礎架構資源以將其部署。 在其他情況下,我們可以通過編寫library或module來構建自己的抽象層。

結構化stack的模式和錯誤模式

基礎設施設計面臨的一項挑戰是決定如何決定stack的規模和結構。 我們可以建立一個stack code project來管理整個系統。 但隨著系統的增長,這會變得難以處理。 在本節中,我們將描述架構infrastructure stacks的模式和錯誤模式。

以下模式都描述了將系統的各個部分分組為一個或多個stack的方法。 我們可以將它們視為一個連續體:

  • Monolithic Stack將整個系統放入一個stack中。
  • Application group stack將系統的多個相關部分分組到stack中。
  • 將單一service stack的所有基礎設施放入單一個stack中。
  • Micro Stack將特定的應用程式或服務的基礎架構分解為多個stack。

錯誤模式: Monolithic Stack

這將所有的 infra stack全都放在一起,因此難以維護。monolithic stack與其他模式的區別在於stack內基礎設施元素的數量或關係難以很好地管理

動機
大家會建立monolithic stacks是因為向系統添加新元素的最簡單方法是將其加到現有專案中。 每個new stack都會添加更多移動部件,這些部件可能需要進行編排、整合和測試。 monolithic stacks更易於管理。 對於規模適中的基礎設施元素集合,monolithic stacks可能有意義。 但更常見的是,整monolithic stacks常常會成長到失去控制。

適用性
當我們的系統較小且簡單時,monolithic stack可能比較合適。 當我們的系統不斷增成長,需要更長的時間來配置和更新時,它就不合適了。

後果
更改大的stack比更改較小stack的風險更大。 更多的事情可能會出錯 — — 它的影響範圍更大。 失敗的變更的影響可能更廣,因為stack中存在更多的服務和應用程式。 較大的stack的配置和變更速度也較慢,這使得它們更難管理。

由於更改monolithic stack的速度和風險,大家往往不那麼頻繁地進行變更,並且需要更長的時間來進行變更。 這種增加的摩擦可能會導致更高等級的技術債。

實行
我們可以通過創建立infrastructure stack project然後不斷加入代碼來建立monolithic stack,而不是將其拆分為多個stack。

相關模式
與monolithic stack相反的是微micro stack,其目的是使stack保持較小,以便更容易維護和改進。 monolithic stack可能是已經失去控制的application group stack。

判斷stack是不是Monolith?

  • 很難理解stack的各個部分如何組合在一起(它們可能太混亂而難以理解,或者可能無法很好地組合在一起)。
  • 新人需要一段時間來學習stack的codebase。
  • 調整stack的問題是困難的。
  • 對stack的變更經常會導致問題。
  • 花費太多時間維護系統和流程,因為要管理stack的複雜性。

Stack是否變成monolithic的一個關鍵指標是在任何一定時間內有多少人正在對其進行變更。 多人同時在stack上工作的情況越常見,我們花在協調變更上的時間就越多。 多個團隊對同一個stack進行變更的情況甚至更糟。 如果在將變更部署到特定stack時經常出現失敗和衝突,則該堆stack已經太大了。

Feature branching是解決此問題的一種策略,但它會增加交付的摩擦和開銷(overhead)。 習慣性地使用Feature branching在stack上的作業表呈現stack已經變成monolithic.。

CI 是一種更可持續的方式,可以讓多人在單一stack上作業更安全。 然而,隨著stack變得往monolithic靠攏,CI 構建需要更長的時間來運行,並且維持良好的構建規則變得更加困難。 如果我們的團隊的 CI 很草率,這又呈現出我們的stack是一個monolith。

這些問題與在Infra stack上工作業的單一團隊有關。 多個團隊在共享stack上的作業是考慮將stack拆分清楚訊號。

模式: Application Group Stack

Application Group Stack包括多個相關應用程式或服務的基礎架構。 所有這些應用程式的基礎設施作為一個group進行配置和管理,如下圖所示。

例如,上面的產品的application stack包括用於瀏覽產品、搜索產品和管理購物籃的單獨服務。 所有這些的伺服器和其他基礎設施都組合在一個stack instance中。

動機
一起定義多個相關服務的基礎架構可以更輕易地將應用程式作為一個unit進行管理。

適用性
當單一團隊擁有應用程式所有部分的基礎架構和部署時,此模式可以很好地發揮作用。application group stack可以使stack的邊界與團隊的職責保持一致。 多個service stack有時可用作從monolithic stack到service stack的增量步驟。

後果
將多個應用程式的基礎架構grouping在一起同時也結合了"時間、風險和變更速度"這些因素。 團隊需要管理每次變更對整個stack的風險,即使只有一部分發生變化。 如果stack的某些部分比其他部分更頻繁地變更,則此模式效率低下配置、變更和測試stack的時間是基於整個stack。 再說一次,如果一次只變更堆棧的一部分是很常見的,那麼將其grouping會增加不必要的overhead和風險。

實行
要建立application group stack,我們需要定義一個Infra project,這個project為一組服務構建所有基礎架構。 我們可以使用一個命令配置和刪除應用程式的所有部分。

相關模式
這種模式有發展成為monolithic stack的風險。 另一方面,將application group stack中的每個服務分解為單獨的stack會變成service stack。

模式: Service Stack

Service stack在單獨的infra stack中管理每個可部署應用程式組件的基礎設施(如下圖)。

動機
Service stack將基礎設施的邊界還有在其中上運作的軟體保持一致。 這種對齊限制了一項服務變更的影響範圍,從而簡化了安排變更的流程。 服務團隊可以擁有與其軟體相關的基礎設施。

適用性
Service stack可以與微服務應用程式架構很好地搭配。 他們還幫助擁有自治團隊的組​​織確保每個團隊擁有自己的基礎設施。

後果
如果您有多個應用程式,每個應用程式都有一個infra stack,則可能會出現不必要的代碼重複。 例如,每個stack可以包括指定如何啟用application server的代碼。 重複可能會導致不一致,例如使用不同的OS或不同的網路配置。 我們可以通過使用module共享代碼來緩解這種情況。

實行
每個應用程式或服務都有一個單獨的infra code project。 建立新應用程式時,團隊可能會從另一個應用程式的基礎架構複製代碼。 或者團隊可以使用reference project,其中包含用於建立new stack的樣板代碼。 在某些情況下,每個stack可能是完整的,不與其他application stack共享任何基礎設施。 在其他情況下,團隊可能會使用能支援多個application stack的基礎架構來建立stack。

相關模式
Service stack模式介於application group stack和Micro stack之間,application group stack在單一stack中具有多個應用程式,Micro stack打破了跨多個stack的單一應用程式的基礎架構。

模式: Micro stack

Micro stack模式將單一服務的基礎架構劃分為多個stack(如下圖)。

動機
Service的基礎設施的不同部分可能會以不同的速度發生變化。 或者它們可能具有不同的特徵,使它們更容易單獨管理。 例如,一些管理server instance的方法涉及頻繁地刪除和重建它們。但是,一些服務使用數資料庫或disk volume中的持久性資料。 在單獨的stack中個別管理伺服器和資料意味著它們可以具有不同的生命週期,server stack的重建頻率比data stack高得多。

後果
儘管較小的stack本身更簡單,但擁有更多的移動部件會增加複雜性。

實行
加上新的Micro stack涉及建立新的stack project。 我們需要在堆stack之間的正確位置切出邊界,以保持它們適當的大小並易於管理。 相關模式包括對此的解決方案。 我們可能還需要整合不同的stack。

相關模式
Micro stack是與monolithic stack是光譜的兩端,monolithic stack包含系統的所有基礎設施。

結論

Infra stack是自動化基礎設施的基本building blocks。 本文中介紹的各種模式是思考將基礎設施組織成stack的起點。

--

--

運用"雲端服務"加速企業的數位轉型願景
運用"雲端服務"加速企業的數位轉型願景

Written by 運用"雲端服務"加速企業的數位轉型願景

我們協助您駕馭名為"雲端運算"的怪獸,馴服它為您所用。諮詢請來信jason.kao@suros.com.tw. https://facebook.com/jason.kao.for.cloud

No responses yet