IaC Part 9 測試Infra Stacks

本文應用了持續測試和向基礎設施堆疊交付代碼的核心實踐。 它使用 JasonShop 範例來說明如何測試stack project。 這包括使用線上和線下測試階段以及利用test fixtures將stack與依賴項解耦。

Infra範例

團隊使用reusable stack projects為其每個客戶建立一致的應用程式基礎架構instance。 還可以使用這個project來建立pipeline中基礎設施的test instance。

這些範例的基礎設施是標準的three-tier系統。 每個tier的基礎設施包括:

Web server container cluster

團隊為每個region和每個測試環境運行一個 web server container cluster。 該Region或環境中的應用程式共用該叢集。 本文中的範例重點在於特定於每個客戶的基礎架構,而不是共享基礎架構。 因此,shared cluster是此處範例中的依賴項。

Application server

每個Application instance的基礎架構包括VM、persistent disk volume,和網路。 網路包括address block、gateway、Server的netwotk port以及access rule。

DataBase

JasonShop使用CSP的 DBaaS 為每個客戶的Application instance執行個別的DB instance。 JasonShop的基礎設施代碼還定義了address block、routing以及DB authentication和access rules。

Stack範例

首先,我們可以定義一個可重複使用的stack,其中包含除 Web 伺服器叢集之外的所有基礎設施。 project結構如以下所示。

stack-project/
└── src/
├── appserver_vm.infra
├── appserver_networking.infra
├── database.infra
└── database_networking.infra

在此專案中,檔案 appserver_vm.infra 包含與以下所示的代碼類似。

virtual_machine:
name: appserver-${customer}-${environment}
ram: 8GB
address_block: ADDRESS_BLOCK.appserver-${customer}-${environment}
storage_volume: STORAGE_VOLUME.app-storage-${customer}-${environment}
base_image: SERVER_IMAGE.jasonshop_server_image
provision:
tool: servermaker
parameters:
maker_server: maker.jasonshop.abc
role: appserver
customer: ${customer}
environment: ${environment}

storage_volume:
id: app-storage-${customer}-${environment}
size: 100GB
format: xfs

團隊成員或自動化流程可以透過執行IaC工具來建立或更新stack instance。 他們使用IaC part 7中的模式之一將Value傳遞給instance。如IaC part 8所述,團隊使用多個測試階段,在有順序的pipeline進行組織。

Stack的pipeline範例

JasonShop application infrastructure stack的simple pipeline具有兩個測試階段,然後是將代碼應用到每個客戶的生產環境的階段(如下圖)。

Pipeline的第一階段是Stack建置階段。 應用程式的建置階段通常是編譯代碼、執行Unit test並建置可部署的工件(artifact)。 由於pipeline中的早期階段應該運行得更快,因此第一階段通常用於執行離線測試。pipeline的第二階段為stack project執行線上測試。 每個pipeline stage可以運行多於一組的測試。

Stacks的離線測試階段

Offline stage在run該階段的服務的代理節點上「locally」運作,而不需要在基礎設施平台上配置基礎設施。 嚴格的離線測試完全在本機伺服器或容器執行個體內執行,無需連接到任何外部服務(例如資料庫)。Soft offline stage可能會連接到現有的service instance,甚至可能是雲端 API,但不使用任何真正的堆疊基礎設施。

一個離現階段應該是:

  • 快速運作,如果發生錯誤,快速回饋
  • 單獨驗證組件的正確性,增強對每個組件的信心,並簡化debugging failure
  • 證明組件完全解耦

我們可以在離線階段對stack code執行的一些測試包括語法檢查、離線靜態代碼分析、使用平台 API 進行靜態代碼分析以及使用模擬 API 進行測試。

語法檢查

使用大多數IaC工具,我們可以執行dry run command來解析代碼,而無需將其套用到基礎架構。 如果存在語法錯誤,該命令將跳出並顯示錯誤。 當我們在代碼變更中出現拼字錯誤時,該檢查會很快告訴我們,但會錯過許多其他錯誤。 可編寫腳本的語法檢查工具的範例包括 terraform validate 和 aws cloudformation validate-template。

語法檢查失敗的輸出可能如下所示:

$ stack validate
Error: Invalid resource type
on appserver_vm.infra line 1, in resource "virtual_mahcine":
stack does not support resource type "virtual_mahcine".

離線靜態代碼分析

有些工具可以解析和分析stack source code以解決更廣泛的問題,而不僅僅是語法問題,但仍然無需連接到基礎設施平台。 這種分析通常稱為 linting。 這種工具可能會尋找代碼錯誤、混亂或不良的編碼風格、對代碼風格策略的遵守情況或潛在的安全問題。 有些工具甚至可以修改代碼以匹配某種風格,例如 terraform fmt 命令。 可以分析基礎設施代碼的工具並不像應用程式語言那麼多。 例如 tflint、CloudFormation Linter、cfn_nag、tfsec 和 checkov。

以下是虛構分析工具的錯誤範例:

$ stacklint
1 issue(s) found:

Notice: Missing 'Name' tag (vms_must_have_standard_tags)

on appserver_vm.infra line 1, in resource "virtual_machine":

在上範例中,我們有一個名為 vms_must_have_standard_tags 的自訂規則,該規則要求所有VM都具有一組tags,其中包括一個名為 Name 的tag。

使用API進行離線靜態代碼分析

根據工具的不同,一些靜態程式碼分析檢查可能會連接到雲端平台 API,以檢查是否與平台支援的內容發生衝突。 例如,tflint 可以檢查 Terraform project code,以確保代碼中定義的任何執行個體類型(VM大小)或 AMI(server image)實際存在。 與pre-viewing change不同,這種類型的驗證通常會測試代碼,而不是針對平台上的特定stack instance。

以下範例產生一個失敗,因為宣告VM的代碼指定了平台上不存在的server image:

$ stacklint
1 issue(s) found:

Notice: base_image 'SERVER_IMAGE.jasonshop_server_image' doesn't
exist (validate_server_images)

on appserver_vm.infra line 5, in resource "virtual_machine":

用Mock API進行測試

我們也許能夠將stack code應用到基礎架構平台 API 的一個local且是mock instance。 用於模擬這些 API 的工具並不多。 目前可能只有 Localstack。 有些工具可以模擬平台的某些部分,例如 Azurite,它模擬 Azure blob 和queue storage。

將宣告式stack code應用於local mock可以揭示語法或代碼分析檢查可能無法發現的編碼錯誤。 在實踐中,使用基礎設施平台API 模擬測試宣告式代碼並不是很有價值。但是,這些模擬對於unit testing imperative code可能很有用,尤其是libraries。

Stacks的線上測試階段

線上階段是使用基礎設施平台建立stack instance並與之互動。 這種類型的階段速度較慢,但可以比線上測試進行更實際的測試。 delivery pipeline服務通常在其節點或代理程式上運作IaC工具,但它使用平台 API 與stack instance進行互動。 該服務需要向平台的API進行身份驗證。

儘管線上測試階段取決於基礎架構平台,但我們應該能夠使用最少的其他依賴項來測試stack。 特別是,我們應該設計基礎架構、stack和測tests,以便可以建立和測試stack的instance,而無需與其他stack的instance整合。

例如,JasonShop 的application infrastructure與shared web server cluster stack搭配使用。 然而,JasonShop 團隊成員使用允許他們在沒有 web server cluster instance的情況下測試application stack code的技術來實現其基礎架構和測試階段。

IaC part 15會介紹了拆分stack並保持它們鬆散耦合的技術。假設我們已經以這種方式構建了基礎設施,您可以使用test fixtures來單獨測試堆stack,例如“使用test fixtures來測試stack”中的「處理依賴關係」。

首先,考慮不同類型的線上stack測試如何運作。 線上階段可以運行的測試包括previewing changes、驗證變更是否正確應用以及證明結果。

Preview: 看看會發生什麼變化

一些IaC工具可以將stack code與stack instance進行比較,以列出它將進行的變更,而無需實際更改任何內容。 Terraform 的 plan 子subcommand就是一個眾所周知的例子。

大多數情況下,人們會預覽針對production instance的變更作為一種安全措施,因此有人可以檢視更變更清單以確保不會發生任何意外情況。 將變更應用到堆stack可以透過管pipeline中的兩步驟過程來完成。 第一步運行preview,一旦查看了結果,就會觸發第二步來套用變更。

人工檢查變更並不是很可靠。 人類可能會誤解或沒有注意到有問題的變更。 我們可以編寫自動化測試來檢查preview command的輸出。 此類測試可能會根據策政策檢查變更,例如,如果程代碼建立了已棄用的資源類型,則會失敗。 或者它可能會檢查破壞性變更 — 如果代碼將重建或破壞DB instance,則會失敗。

另一個問題是IaC工具的preview檢查通常不夠深入。 preview告訴我們此代碼將建立一個新伺服器:

virtual_machine:
name: myappserver
base_image: "server_image"

但是preview可能不會告訴我們「server_image」不存在,儘管 apply command將無法建立伺服器。

預覽堆stack變更對於在將程代碼變更套用至instance之前立即檢查一組有限的風險非常有用。 但對於測試打算跨多個insatnce重複使用的代碼(例如跨發布交付的測試環境),它的效用不大。 使用copy-past環境的團隊通常使用preview階段作為每個環境的最小測試。 但是使用reusable stacks的團隊可以使用test instance對其代碼進行更有意義的驗證。

驗證: 對基礎設施資源做出Assertions

給一個stack instance,我們可以在線上階段進行測試,對stack中的基礎設施做出assertion。 用於測試基礎設施資源的框架的一些範例包括:

本文前面範例stack code中的一組VM測試可能如下所示:

given virtual_machine(name: "appserver-testcustomerA-staging") {
it { exists }
it { is_running }
it { passes_healthcheck }
it { has_attached storage_volume(name: "app-storage-testcustomerA-staging") }
}

大多數IaC測試工具都提供函式庫來幫助編寫有關在IaC part 3中描述的基礎架構資源類型的assertions。此範例測試使用 virtual_machine 資源來識別暫存環境的stack instance中的 VM。 它對資源做出多個assertions,包括資源是否已創建(exists)、是否正在運行而不是已終止(is_running)以及基礎設施平台是否認為其正常(passes_healthcheck)。

簡單的assertion通常價值較低,因為它們只是重申了它們正在測試的基礎設施代碼。 一些基本assertion(例如exists)有助於健全性檢查代碼是否已成功套用。 這些可以快速識別pipeline stage configuration或測試設定腳本的基本問題。 is_running 和 Passs_healthcheck 等測試會告訴我們IaC工具何時成功建立VM。但它掛掉或存在其他一些基本問題,像這樣的簡單assertion可以節省排除故障的時間。

儘管我們可以建立回應stack code中每個VM的configuration items的assertion(例如 RAM 或分配給它的網路位址),但這些assertion的價值不大,而且會增加overhead。

範例中的第四個assertion has_attached storage_volume() 會檢查同一個堆stack中定義的storage volume是否已附加到 VM。 這樣做可以驗證多個宣告的組合是否正常運作。 根據我們的平台和工具,stack ocde可能會成功套用,讓伺服器和磁碟區正確綁定在一起。 或者我們可能在stack ocde中犯了一個錯誤,從而破壞了attachment。

assertion有用的另一種情況是stack code是動態的。 當向堆stack傳遞不同的參數可能會產生不同的結果時,我們可能需要對這些結果進行assertion。 例如,此代碼為對外或對內的application server建立基礎架構:

virtual_machine:
name: appserver-${customer}-${environment}
address_block:
if(${network_access} == "public")
ADDRESS_BLOCK.public-${customer}-${environment}
else
ADDRESS_BLOCK.internal-${customer}-${environment}
end

我們可以有一個測試階段來建立每種類型的instance並診斷每種情況下的網路配置都是正確的。 我們應該將更複雜的變體移至模組或libraries中,並與stack code分開測試這些模組。 這樣做可以簡化stackcode的測試。

診斷基礎設施資源是按預期創建的在某種程度上是有用的。 但最有價值的測試是證明它們做了它們應該做的事情。

Outcomes: 證明基礎設施正常運行

功能測試(Functional testing)是測試應用軟體的重要組成部分。 與基礎架構的類比證明我們可以按預期使用基礎架構。 我們可以使用Infra stack code測試的結果範例包括:

  • 我們能否在相關port上建立從 web server networking segment到application hosting network segment的網路連線?
  • 可以在container cluster stack的instance上部署和執行應用程式嗎?
  • 重建server instance時可以安全地reattach storage volume嗎?
  • load balancer在新增和刪除server instances時是否正確處理它們?

測試outcome比驗證東西是否存在更複雜。我們的測試不僅需要建立或更新stack instance,而且可能還需要配置test fixtures。 test fixtures是僅用於支援測試的基礎設施資源。

以下測試與伺服器建立連線以檢查port是否有通,並傳回預期的 HTTP 回應:

given stack_instance(stack: "jasonshop_networking",
instance: "online_test") {

can_connect(ip_address: stack_instance.appserver_ip_address,
port:443)

http_request(ip_address: stack_instance.appserver_ip_address,
port:443,
url: '/').response.code is('200')
}

測試框架和函式庫實作了 can_connect 和 http_request 等驗證的詳細資訊。 我們需要閱讀測試工具的文件以了解如何編寫實際測試。

使用Test Fixtures來處理依賴項

許多stack porject依賴stack外部建立的資源,例如在不同stack project中定義的共用網路。 Test fixtures是專門建立的基礎架構資源,旨在協助我們自行配置和測試stack instance,而無需擁有其他stack 的instance。 Test doubles是一種Test fixtures。

使用test fixtures可以更容易的管理測試、保持堆stack鬆散耦合並具有快速反饋循環。 如果沒有test fixture,我們可能需要建立和維護複雜的測試基礎架構集。

test fixture不是我們正在測試的stack的一部分。 它是為支援測試而建立的附加基礎架構。 我們可以使用test fixtures來呈現堆stack的依賴關係。

特定的依賴關係要嘛是上游的,這意味著我們正在測試的stack使用另一個stack提供的資源,要嘛是下游的,在這種情況下,其他stack使用我們正在測試的stack中的資源。 有時將具有下游相依性的stack稱為providers,因為它提供資源。 具有上游依賴性的堆疊稱為consumer(如下圖)。

我們的 JasonShop 範例有一個定義共享網路結構的provider stack。 這些結構由consumer stack使用,包括定義客戶應用程式基礎設施的stack。 application stack建立一個伺服器並將其指派給一個網路位址區塊。

特定的stack可以既是provider又是consumer,消耗來自另一個stack的資源並向其他stack提供資源。 我們可以使用test fixtures來取代stack的上游或下游整合點。

上游依賴項的Test Doubles

當我們需要測試依賴另一個stack時,可以建立test double。 對於stack來說,這通常意味著建立一些額外的基礎設施。 在我們的shared network stack與application stack的範例中,application stack需要在network stack定義的網路位址區塊中建立其伺服器。 測試設定也許能夠建立一個地址區塊作為test fixtures來單獨測試application stack。

建立位址區塊作為test fixtures可能比建立整個network stack的instance更好。 network stack可能包括測試不需要的額外基礎設施。 例如,它可能定義網路政策、路由、審核和其他生產資源,而這些資源對於測試來說是多餘的。

此外,在consumer stack project中建立依賴項作為test fixtures,可以將其與provider stack分離。 如果有人正在對network stack project進行變更,則不會影響應application stack上的作業。

這種類型的解耦的潛在效益是使stack更具可重複使用性和可組合性。 團隊可能會想要為不同的目的建立不同的network stack projects。 一個stack為具有更嚴格合規性需求的服務創建嚴格控制和審核的網路,例如遵守 PCI 標準的支付處理或客戶資料保護法規。 另一個stack建立不需要符合 PCI 的網路。 透過在不使用其中任何一個stack的情況下測試application stacks,團隊可以更輕易地將stack code與任一個stack code一起使用。

下游依賴項的Test Fixtures

我們也可以使用Test fixtures來應對相反的情況,以測試為其他stack提供資源。 下圖中,stack instance定義了 jasonShop 的網路結構,包括web server container cluster 與application servers的區段和路由。 network stack不配置web server container cluster與application servers,因此為了測試網路,設定在每個部分中配置一個test fixtures。

上面範例中的test fixtures是一對container instance,一個分配給stack中的每個網段。 通常可以使用與驗證測試相同的測試工具來進行結果測試。 這些範例測試使用虛構的stack testing DSL:

given stack_instance(stack: "jasonshop_networking",
instance: "online_test") {

can_connect(from: $HERE,
to: get_fixture("web_segment_instance").address,
port:443)

can_connect(from: get_fixture("web_segment_instance"),
to: get_fixture("app_segment_instance").address,
port: 8443)
}

can_connect 方法從 $HERE 執行,$HERE 是執行test code的agent,或從container instance執行。 它嘗試在指定連接埠上與 IP 位址建立 HTTPS 連線。 get_fixture() 方法取得作為test fixture建立的container instance的詳細資訊。 測試框架可能提供 can_connect 方法,也可能是團隊編寫的自訂方法。 下圖中看到範例測試代碼所建立的連線。

上圖顯示了兩個測試的路徑。 第一個測試從stack外部連接到網路區段中的fixtures。 第二個測試從 Web 網段中的 test fixtures連接到應用程式網段中的fixture。

重構組件讓它們是分離的

有時無法輕易隔離特定組件。 對其他組件的依賴可能是hardcode,或者只是太混亂而無法分解。 在設計和建立系統時(而不是事後)編寫測試的好處之一是,它迫使我們改進設計。 難以單獨測試的組件是設計問題的徵兆。 一個設計良好的系統應該具有鬆散耦合的組件。

因此,當我們遇到難以隔離的組件時,我們應該調整設計。 可能需要完全重寫組件,或取代libraries、工具或應用程式。 簡潔的設計和鬆散耦合的代碼是使系統可測試的副產品。

測試Stack instance的生命週期模式

在虛擬化和雲端出現之前,每個人都維護靜態、長期的測試環境。 儘管許多團隊仍然擁有這些環境,但On-dmeand的建立和刪除環境具有優勢。 以下模式描述了保留persistent stack instance、為每次測試運行建立ephemeral instance的權衡,以及組合這兩種方法的方法。 我們也可以將這些模式應用於應用程式和完整系統測試環境以及測試infra stack code。

模式: Persistent Test Stack(也是所謂的靜態環境)

測試階段可以使用持續運運作的persistent test stack instance。 此階段將每個代碼變更套用為現有stack instance的更新,運行測試,並將產生變更後的stack保留在適當的位置以供下次運行。

動機
將變更套用到現有stack instance通常比建立new instance要快得多。 因此,persistent test stack可以提供更快的回饋,不僅針對Stage本身,而且針對整個pipeline。

適用性
當我們能可靠地將stack code應用到instance時,persistent test stack非常有用。 如果我們發現自己花時間修復損壞的instance以使pipeline重新運行,則應該考慮本文中的其他模式。

後果
當變更失敗並使其處於任何套用stack code的再次嘗試也失敗的狀態時,stack instance變得「wedged(卡住)」的情況並不罕見。 通常,instance會嚴重卡住,以至於IaC工具甚至無法刪掉stack讓我們可以重新開始。 因此,團隊花了太多時間手動解除損壞的test instance。 我們通常可以透過更好的stack design來降低卡住stack的頻率。 將stack分解為更小、更簡單的stack,並簡化stack之間的依賴關係,可以降低卡住率。

實現
實作persistent test stack很容易。 pipeline stage運行IaC工具命令,以使用相關版本的stack code更新instance,執行測試,然後在完成後將stack instance保留在適當的位置。 我們可以將stack整個重建為臨時流程(ad hoc process),例如有人從本機電腦執行該工具,或在常規pipeline flow之外使用額外的階段或作業。

相關模式
後面會提到的「模式:定期堆疊重建」中討論的定期stack重建模式是對此模式的簡單調整,在工作日結束時刪除instance並每天早上建立一個new instance。

模式: Ephemeral Test Stack(快與髒加上慢而乾淨)

使用ephemeral test stack模式,測試階段每次運行時都會建立和刪除stack的new instance(如下圖)。

動機
ephemeral test stack為每次運行測試提供一個乾淨的環境。 不存在上一次運作留下的資料、fixtures或其他「殘骸」所帶來的風險。

適用性
我們可能希望使用ephemeral instances來快速從頭開始配置stack。 「快速」與我們所需的回饋循環相關。 對於更頻繁的變更,例如在快速開發階段提交application code,建立新環境的時間可能會比人們可以容忍的時間更長。 但不太頻繁的變更(例如作業系統修補更新)可能可以接受完整重建的測試。

後果
Stack通常需要很長時間才能從頭開始配置。 因此,使用ephemeral stack instances的stage會使回饋循環和交付週期變慢。

實行
若要實作ephemeral test instance,test stage應執行IaC工具命令,以在測試和報告完成後刪除stack instance。 如果測試失敗,可能需要將stage配置成在刪除instance之前停止,以便技術人員可以debug the failure。

相關模式
與continuous stack reset pattern類似,但在Stage之外運行stack建立和刪除命令,因此所花費的時間不會影響反饋循環。

反模式: Dual Persistent與Ephemeral Stack Stages

對於persistent與ephemeral stack stages,pipeline將對stack的每個變更傳送到兩個不同的階stage,一個是ephemeral stack instance,一個是persistent stack instance。 這結合了persisten和ephemeral兩種模式。

動機
團隊通常實作此作法是為了解決它所組合的兩種模式的缺點。 如果一切順利,「quick and dirty」的stage(使用persistent instance的stage)將提供快速回饋。 如果該階Stage因環境卡住而失敗,我們最終將從「slow and clean」的stage(使用ephemeral instance的stage)獲得回饋。

適用性
可能值得將這兩種類型的stages作為臨時解決方案實施,同時轉向更可靠的解決方案。

後果
在實踐中,使用這兩種類型的stack生命週期結合了兩者的缺點。 如果更新現有stack不可靠,那麼當該stage出現問題時,團隊仍然會花時間手動修復該stage。 可能會等到較慢的stage完跑後才確信是變更是沒問題的。 這種反模式也很昂貴,因為它使用雙倍的基礎設施資源,至少在測試運行期間是如此。

實行
我們可以透過建立兩個pipeline stage來實現sual stage,這兩個階stage均由stack project的stage前一個stage觸發,如下圖所示。 在將stack版本升級到下一個stage之前,可能需要兩個stage都通過,或者可以在任一stage通過時升級它。

模式: Periodic Stack Rebuild

定期stack重建在stack test stage使用persistent test stack instance,然後有一個outof-band運行的流程來按計劃(例如每晚)刪除和重建stack instance。

動機
會經常使用定期重建是因為要降低成本。 在工作日結束時刪除stack,並在第二天開始時提供新的stack。 定期重建可能有助於解決不可靠的stack update,這取決於update不可靠的原因。 在某些情況下,instance的資源使用量會隨著時間的推移而增加,例如在測試運行期間累積的記憶體或storage。 定期重置可以清除這些問題。

適用性
重建stack instance以解決資源消耗通常會掩蓋潛在問題或設計問題。 在這種情況下,這種模式充其量只是一種臨時駭客行為,而在最壞的情況下,則是一種讓問題不斷累積直至引發災難的方法。 在不使用stack instance時刪除stack instance以節省成本是明智的做法,尤其是在使用計量資源(例如公有雲)時。

後果
如果使用此模式來釋放空閒資源,則需要考量如何確保真的不需要它們。 例如,在上班時間以外或在其他時區工作的人員可能會在沒有測試環境的情況下無法進行測試。

實行
大多數pipeline orchestration tools可以很容易建立按計劃運行的作業以刪除和建置stack instance。 更複雜的解決方案將根據活動等級運行。 例如,如果test stage在過去一小時內未執行,可能有一個job會刪除instance。

在刪除前一個instance後,可以使用三個選項來觸發new instance的建置。 一是刪除後立即重建。 這種方法清理了資源,但並沒有節省成本

第二個選項是在計劃的時間點建立new environment instance。 但這可能會阻妨礙員工彈性的工作時間。

第三個選項是test stage配置一個新new instance(如果目前不存在)。 建立一個單獨的作業,按計畫或在一段時間不活動後刪除instance。 每次test stage運行時,它首先檢查instance是否已經在運行。 如果沒有,它首先提供一個new instance。 透過這種方法,人們有時需要比平常等待更長的時間才能獲得測試結果。 如果他們是早上第一個push change的人,他們需要等待系統配置stack。

相關模式
這種模式可以像persistent test stack 模式一樣發揮作用 — 如果stack update不可靠,技術人員就會花時間修復損壞的instance。

模式: Continuous Stack Reset

使用連continuous stack reset模式,每次stack測試階段完成時,out-of-band job都會刪除並重建stack instance(如下圖)。

動機
每次刪除並重建stack instance都可以為每次測試運行提供一個乾淨的環境。 它可以自動刪除損壞的instance,除非它損壞到IaC工具無法刪除。 並且它消除了反饋循環中建立和刪除stack instance所需的時間。 此模式的另一個效益是,它能可靠地測試生產中特定stack code版本將發生的更新流程。

適用性
如果stack project不會掛掉並且需要手動方式來修復,那麼在後台刪除stack instance可以很好地發揮作用。

後果
由於stack在pipeline的delivery flow之外被破壞和配置,因此問題可能看步道。 pipeline是良好的,但test instance可能會在後台掛掉。 當下一個變更到達test stage時,可能需要一段時間才能意識到它失敗是因為後台作業而不是變更本身。

實行
當test stage通過時,它將stack project code提升到下一stage。 它還會觸發刪除和重建stack instance的作業。 當有人向代碼推送新的變更時,test stage會將其作為update套用到instance。

我們需要決定在重建instance時使用哪個版本的stack code。 可以使用剛通過該stage的相同版本。 另一種方法是提取應用於production instance的stack code的最後一個版本。 這樣,每個版本的stack code都會作為目前生產版本的更新進行測試。 根據我們的基礎設施代碼通常如何流向生產,這可能是生產升級流程的更準確呈現。

相關模式
理想情況下,此模式類似於persistent test stack模式,提供回饋,同時具有ephemeral test stack模式的可靠性。

Test Orchestration

我們已經討論了testing stack中每個移動部分:可以應用的測試和驗證的類型、使用test fixtures來處理依賴關係以及測試stack instance的生命週期。 但是應該如何將它們組合在一起來設定和運行測試呢?

大多數團隊使用腳本來編排他們的測試。 通常,這些腳本與他們用來編排運行堆疊工具的腳本相同。 我們將在IaC Part 15中深入研究這些腳本,它們可以處理配置、協調跨多個stack的操作以及其他活動以及測試。

Test orchestration通常會有:

  • Creating test fixtures
  • Loading test data (通常是Application的測試比較需要)
  • Managing the life cycle of test stack instances
  • Providing parameters to the test tool
  • Running the test tool
  • Consolidating test results
  • Cleaning up test instances, fixtures, and data

編排測試需要考慮的兩個準則是支援local testing和避免與pipeline工具的緊密耦合。

支援local testing

處理infrastructure stack code的人應該能夠在將代碼推送到shared pipeline和環境之前自行執行測試。 我們在IaC part 20「Personal Infra instance」會討論了幫助技術人員在基礎設施平台上使用Personal Infra instance的方法。 這樣做可以讓我們在推送變更之前編碼並運行線上測試。

除了能夠使用堆instance的personal test instances之外,技術人員還需要擁有測試工具和在本地工作環境中執行測試所涉及的其他元素。 許多團隊使用code-driven development environments,它可以自動安裝和設定工具。 我們可以使用容器或VM來打包可在不同類型的桌面系統上運行的開發環境。 或者,團隊可以使用託管工作站(configured as code),儘管這些工作站可能會受到延遲的影響,尤其是對於分散式團隊而言。

讓技術人員輕很容易自己運行測試的關鍵是在本機工作和piepline stages使用相同的測試編排腳本。 這樣做可以確保測試在各處一致地設定和運行。

避免與Pipeline工具緊密耦合

許多 CI 和pipeline orchestration tools都具有用於測試編排的功能或插件,甚至可以配置和執行測試。 雖然這些功能看起來很方便,但它們使得在pipeline之外具有一致性的設定和運行測試變得困難。 混合"測試和pipeline configuration"也會使變更變得痛苦。

相反的,我們應該在單獨的腳本或工具中實施test orchestration。 test stage應呼叫此工具,傳遞最少的配置參數。 這種方法使pipeline orchestration與test orchestration的關注點保持鬆散耦合(loosely coupled)。

Test Orchestration Tools

許多團隊編寫自訂腳本來編排測試。 這些腳本與用於編排堆疊管理的腳本類似,甚至可能相同。 技術人員使用 Bash scripts、batch file、Ruby、Python、Make、Rake 以及其他一堆有的沒有的。

有一些專門設計用於協調基礎設施測試的工具。 像是Test Kitchen 和 Molecule。 Test Kitchen 是 Chef 的開源產品,最初旨在測試 Chef cookbooks。 Molecule 是一款開源工具,旨在測試 Ansible playbook。 我們可以使用任一工具來測試infrastructure stacks,例如使用 Kitchen-Terraform。

這些工具面臨的挑戰是,它們在設計時想到的是特定的工作流程,並且可能難以配置以適應我們自己所需的工作流程。 有些人調整和修改它們,而有些人則發現編寫自己的腳本更簡單。

--

--

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

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

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

No responses yet