IaC Part 12-針對Server的變更管理

許多企業和團隊聚焦於建立伺服器和其他基礎設施的流程和工具,但忽略了變更。 當需要進行變更(解決問題、應用安全性修補程式或升級軟體)時,他們通常會將其視為異常事件。 如果每次變更都是例外,那麼我們就無法將其自動化。 就是這種心態讓許多企業的系統"不一致、不穩定"的原因。 這就是為什麼我們中的許多人花時間在處理一堆無關緊要的ticket和救火之間切換。

我們的系統唯一不變的就是它們在改變。 如果我們將系統定義為代碼(system as code),在動態基礎設施平台上運行它們,並透過變更pipeline在系統中交付該代碼,那麼我們就可以讓變更變得像是例行公事且簡單。 如果系統僅透過代碼和pipeline建立和更改,那麼我們就可以確保它們的一致性,並確保它們符合我們需要的任何策略。

我們在Part 11中提到了伺服器上有什麼以及它們都來自哪裡。 特定伺服器上的所有內容都來自訂的來源,無論是OS安裝、系統套件儲存庫或伺服器配置代碼。 我們需要對伺服器進行的任何變更都是對其中一項內容的變更。

本文介紹如何透過更改定義事物來源的代碼並以某種方式套用它來更改伺服器上的東西。 透過為伺服器實施可靠、自動化的變更流程,我們可以確保能夠快速、可靠地在整個IT資產中實施變更。 可以毫不費力地使所有伺服器保持最新狀態,並使用最新批准的軟體包和配置。

將配置代碼(Configuration Code)套用到伺服器有多種模式,包括在發生每個變更時套用它、持續同步它以及重建伺服器以變更它們。 進行變更的另一個方面是如何運行工具以將變更套用到伺服器,無論是Push configuration還是pull。 最後,伺服器的生命週期中還有其他幾個事件,從暫停到重建再到刪除。

變更管理模式: 何時套用變更

有一種反模式和兩種模式用於決定何時將變更套用到Server instance。

反模式:Apply on Change(也稱為:臨時自動化)

使用「Apply on change」反模式,只有在需要套用特定變更時,配置代碼才會套用至伺服器。

例如,考慮一個運行多個 Tomcat 應用程式伺服器的團隊。 團隊成員在建立新的server instance時執行 Ansible playbook 來安裝和設定 Tomcat,但一旦伺服器運行,他們就不會運行 Ansible,直到有需要為止。 當 Tomcat 的新版本發佈時,他們會更新他們的 playbook 並將其套用到伺服器。

在這種反模式的最極端版本中,人員只將代碼套用到特別打算變更的伺服器上。

上面範例中的團隊注意到其中一台應用程式伺服器的流量要高得多,並且負載導致 Tomcat 不穩定。 團隊成員對其playbook進行了一些變更,以優化 Tomcat 配置來實現更高的負載,然後將其套用到不穩定的伺服器。 但他們不會將playbook套用到其他應用程式伺服器,因為這些伺服器不需要變更。

動機
系統和網路管理員傳統上都是用手動方式來管理伺服器。 當需要進行變更時,傳統上都是登入相關伺服器並進行更改。 為什麼我們會採取不同的做法? 即使使用腳本的人也傾向於編寫並運行腳本來進行特定的變更。 "Apply on change"反模式是這種工作方式的擴展,它恰好使用IaC工具而不是手動命令或on-off scripts。

適用性
對於單一臨時性的伺服器來說,只根據特定變更的需要套用代碼可能沒問題。 但這並不是可持續性管理一群伺服器的合適方法。

後果
如果只套用配置代碼來進行特定變更,則可能會出現long gap,其中代碼永遠不會套用到特定的server instance。 當我們最終套用代碼時,它可能會失敗,因為伺服器上的其他差異與您想要變更的差異不同。

當我們不注意時,伺服器上的東西往往會改變。 有人可能會手動進行變更,例如,作為系統掛掉的快速修復。 其他人可能已經使用較新版本的OS或應用程式包修補了系統。 這些屬於快速變更的類別,我們確信不會破壞任何東西。 然後一週後,我們就不記得做了什麼變更(因為這只是一個小變更),直到我們花了幾個小時調整它破壞的東西。

當我們只對某些伺服器而不是其他伺服器套用變更時,問題會變得更糟。 考慮前面的範例,其中團隊應用代碼來優化一台伺服器的效能。 稍後,團隊中的某人將需要對應用程式伺服器進行不同的變更。

當我們這樣做時,也會將先前的效能最佳化變更套用到尚未擁有它的伺服器,作為套用新變更的代碼的副作用。 早期的變更可能會對其他伺服器產生意想不到的衝擊。 更糟糕的是,應用程式代碼的人可能忘記了效能優化,因此他們需要更長的時間才能發現其產生的任何問題的原因。

實行
習慣於手動變更或使用一次性腳本的人傾向以相同的方式使用IaC code。 他們將 Ansible、Chef、Puppet 等工具視為語法笨拙的腳本​​工具。 大多數情況下,執行此操作的人會從本機電腦手動執行該工具,而不是讓pipeline或其他orchestration service套用代碼。

相關模式
人們傾向於將"Apply on change"反模式與pull configuration模式(後面會提到)結合使用,而不是使用pull。 此反模式的替代方案是連續同步或不可變伺服器。

模式 1:持續配置同步(也稱為:排程的伺服器配置更新)

持續配置同步涉及重複且頻繁地將配置代碼套用到伺服器,無論代碼是否已變更。 執行此操作會恢復或呈現出可能潛在的任何意外差異,無論是伺服器還是配置代碼使用的其他資源。

動機
Server configuration是可預測的,一旦我們將代碼套用到伺服器,在下次套用代碼之前,任何內容(應該)都不會改變。 如果我們沒有更改代碼,則無需套用它。 然而,如果管理不當伺服器和伺服器代碼都會在我們沒有認可的狀況下慢慢改變。

有時,伺服器會因明顯的原因而發生變化,例如有人登入並手動進行變更。 工程師們經常以這種方式進行很小幅的變更,因為他們認為這不會造成任何問題。 他們在這一點上經常犯錯。 在其他情況下,團隊使用不同的工具或流程來管理伺服器的某些面向。 例如,一些團隊使用專門的工具來更新和修補伺服器,尤其是安全性修補程式。

即使伺服器沒有變更,多次套用相同的伺服器代碼也可能會帶來差異。 例如,代碼可以使用來自central configuration registry的參數。 如果這些參數之一發生變化,代碼下次在伺服器上運行時可能會執行不同的操作。

Package是變更的另一個外在來源。 如果configuration code從儲存庫安裝Package,則它可能會在該Package可用時將其更新為較新的版本。 我們可以嘗試指定Package版本,但這會導致兩條可怕的結果之一。 一方面,系統最終會包含許多舊版本的Package,其中包括駭客熟知的具有安全漏洞的Package。 另一方面,團隊會花費大量精力手動更新伺服器代碼中的Package version。

透過按照自動計劃定期重新套用伺服器代碼,我們可以確保所有伺服器的配置保持一致。 也確保任何差異(無論來源為何)都宜早不宜遲。

適用性
與主要替代方案、immutable servers相比,它更容易實現持續同步。 大多數IaC工具(例如 Ansible、Chef 和 Puppet)在設計時都考慮到了這種模式。 透過更新現有Server instance來套用變更比建置new instance更快且破壞性更小。

後果
當自動化流程在整個資產中套用server configuration時,就會出現問題的風險。 正如前面「動機」部分所述,所有可能發生意外變更的事情都可能會破壞伺服器。 為了解決這個問題,我們應該有一個有效的監控系統,並在將變更套用於生產系統之前有一個良好的測試和交付代碼的流程。

實行
如前所述,大多數server configuration as code工具都設計為持續運行。 它們使用的具體機制我們稍後會在後面「模式:Push server configuration」和「模式:Pull server configuration」中進行描述。

大多數持續同步實作都按排程進行。 這些往往會以某種方式改變不同伺服器上的runtime,以便所有伺服器不會同時被喚醒並運作其配置。 但是,有時我們希望更快地套用代碼,也許是為了進行修復程序,或為了支援軟體部署。 不同的工具有不同的解決方案來執行此操作。

相關模式
連續同步是使用Push或Pull配置模式來實現的。 此模式的替代方案是Immutable Server。

模式2: Immutable Server

Immutable server是其configuration永遠不變的server instance。 我們可以透過使用變更後的配置來建立新的server instance並使用它來取代現有伺服器來交付變更。

動機
Immutable servers降低了變更的風險。 我們無需對正在運行的server instance套用變更,而是建立一個新的server instance。 我們有機會測試new instance,接著替換舊的instance。 然後,您可以在銷毀舊的instance之前檢查new instance是否正常運作,或者在出現問題時再換回來。

適用性
需要嚴格控制和伺服器配置一致性的組織可能會發現immutable servers很有用。 例如,運行數千個server images的電商可能決定不對正在運行的伺服器套用變更,而是更願意保證其配置的穩定性。

後果
實現immutable servers需要一個強大的自動化流程來建置、測試和更新server image。 我們的系統和應用程式設計必須支援在不中斷服務的情況下交換server instance。

儘管有immutable servers這個名稱,但它確實會發生變化。

Configuration drift可能會逐漸出現,特別是如果工程師可以登入伺服器並手動進行變更,而不是使用配置變更流程來建立新的server instance。 因此,使用immutable servers的團隊應該小心確保運行instance的更新度。 完全有可能將immutable servers與「Apply on Chnage」反模式結合起來,這可能會導致伺服器一個長時間運行而沒有變更,包括需要進行的補丁和改進。 團隊還應該考慮禁用直接登入伺服器的存取,或者使存取和手動更改服務的能力需要“break glass”程序。

PS:在緊急情況下,可以使用「break glass」程序暫時獲得權限。 該程序通常是高度可見的,以阻止三天兩頭被使用。 如果工程師們開始依賴break glass流程,團隊應該評估哪些作業迫其使用,並尋找在沒有流程的情況下支援這些任務的方法。 有關更多資訊,請參閱 Derek A. Smith 的網路研討會“Break Glass Theory”。

實行
大多數使用immutable servers的團隊在Server images中處理大部分的配置,傾向於baking images而不是frying instance。 因此,自動建置和更新server image的pileline或一組pipeline是immutable servers的基礎。

我們可以將Configuration frying到immutable server instances上,只要在建立Instance後不對其進行變更即可。 但是,更嚴格形式的immutable server可以避免在server instance中加入任何差異。 透過這種方法,我們可以建立並測試server image,然後將其從一個環境轉移到下一個環境。 由於每個server instance幾乎沒有變化,因此我們可以阻止問題從一個環境蔓延到下一個環境的風險。

相關模式
工程師們傾向於bake server來支援immutable servers。 持續同步則是相反的方法,定期將變更應用於正在運行的server instance。 immutable servers是immutable infrastructure的子集。

如何套用Server Configuration Code

在描述了管理何時將配置代碼套用到伺服器的模式之後,本節討論用於決定如何將代碼套用到server instance的模式。

這些模式與一直在變化的伺服器相關,特別是作為持續同步過程的一部分。 但它們也在建構新的server instance時使用,將Configuration fry 到instance上。 在建立server image時,我們還需要選擇一種模式來套用配置。

選定一個server instance,無論它是我們正在建置的new instance、用於建置image的臨時instance或現有instance,執行伺服器配置工具來套用代碼有兩種模式。 一是Push,二是Pull。

模式一: Push Server Configuration

透過push server configuration模式,new server instance之外運行的Process連接到伺服器並執行、下載和套用代碼。

動機
團隊使用Push來避免將"伺服器配置工具"預先安裝到Server Image上。

適用性
當需要對現有伺服器的設定更新時間進行更高度的控制時,Push模式非常有用。 例如,如果事件(例如軟體部署)具有跨多個伺服器的一系列活動,則可以使用編排該流程的Central Process來實現此目的。

後果
Push configuration模式需要能夠連接到Server Instance並透過網路執行configuration process。 此要求可能會產生安全漏洞,因為它打開了駭客可能用來連接我們的伺服器並對伺服器進行未經授權的更改的向量(vector)。

對平台自動建立的server instance推送configuration可能會有些麻煩; 例如,用於autoscaling 或automated recovery。 然而,這是可以做到的。

實行
Push server configuration的一種方法是讓某人從本機電腦運行server configuration tool。 然而,我們會在Part 20 的文章中「Applying Code from a Centralized Service」所討論的,最好是從中央伺服器或服務運行工具,以確保流程的一致性和控制性

某些server configuration tools包括管理與machine instances連接的server application,例如 Ansible Tower。 一些公司提供 SaaS 服務來遠端配置Server instance,儘管許多企業不願意讓第三方對其基礎設施進行這種等級的控制。

在其他情況下,我們自己實作一個central service來執行伺服器設定工具。 最常看到團隊使用 CI 或 CD 伺服器產品來建置它。 他們實作針對一組特定伺服器run configuration tool的 CI jobs或pipeline stages。 此作業會根據事件觸發,例如伺服器配置代碼的變更或新環境的建立。

Server configuration tool需要能夠連接到server instance。 儘管有些工具為此使用自訂的網路協議,但大多數工具使用 SSH。 每個Server instance必須接受來自伺服器工具的 SSH 連接,從而允許該工具以足夠的權限運行以應用其配置變更。

對這些連線進行strong authentication and secrets management至關重要。 否則,伺服器設定系統對組織來說就是一個巨大的安全漏洞。

建立和設定new server instance時,我們可以動態產生新的驗證金鑰,例如 SSH key。 大多數基礎設施平台都提供了一種在建立new instance時設定金鑰的方法。 然後,伺服器設定工具可以使用此金鑰,並可能在不再需要金鑰時停用並丟棄該金鑰。

如果需要將configuration change套用至現有server instances(與持續同步一樣),那麼需要一種長期方法來驗證來自設定工具的連線。 最簡單的方法是在所有Server instance上放一個金鑰。 但這個單一的金鑰是一個漏洞。 如果它被暴露,那麼駭客就有一把所有server的萬能金鑰了。

另一種方法是為每個server instance設定unique key。 必須以允許伺服器配置工具存取這些金鑰的方式管理對這些金鑰的存取,同時降低駭客獲得相同存取權限的風險(例如,透過破壞執行該工具的伺服器)。

許多組織使用的一種方法是擁有多個伺服器或服務來管理伺服器配置。 該資產被劃分為不同的安全領域,每個server configuration service instance只能存取其中之一。 這種劃分可以減少被攻擊的範圍。

相關模式
Pull模式的替代方案是Pull。

模式二: Pull Server Configuration

Pull server configuration模式涉及在server instance本身執行的process,用於下載和應用程式代碼。 當建立new server instance時會觸發此流程。 對於持續同步模式下的現有instance,該流程通常按schedule運行,定期喚醒並套用目前配置。

動機
Pull-based server configuration無需server instance接受來自中央伺服器的連線,因此有助於減少攻擊面。 此模式簡化了基礎架構平台自動建立的instance的配置,例如autoscaling 與automated recovery。

適用性
當我們可以建置或使用預先安裝了伺服器設定工具的server image時,我們可以實現pull-based server configuration。

實行
Pull configuration透過使用預先安裝了伺服器配置工具的Server image來運作。 如果我們要pulling new server instances的配置,配置Image以在首次啟動時執行該工具。

Cloud-init 是一種廣泛使用的自動運行此類流程的工具。 我們可以使用基礎架構平台的 API 將參數傳遞到new server instance,甚至包括要執行的命令以及要傳遞到伺服器設定工具的參數(如以下範例)。

server:
source_image: stock-linux-4.56
memory: 4GB
vnet: ${APPSERVER_VNET}

instance_data:
- server_tool: servermaker
- parameter: server_role=appserver
- parameter: code_repo=servermaker.shopspinner.jas

配置腳本以便從central repository下載配置代碼並在啟動時套用它。 如果我們使用持續同步來更新正在執行的伺服器,則setup process應該對此進行配置,無論是執行伺服器設定工具的background process,還是on schedule執行該工具的 cron job。

即使沒有建立自己的server imsage,大多數Public cloud提供的images都預先安裝了 cloud-init 和流行的伺服器設定工具。 其他一些工具,特別是 Saltstack,使用messaging和event-based的方法來觸發伺服器配置。 每個server instance都執行一個連線到shared service bus的agent,從這個Bus接收套用配置代碼的命令。

去中心化配置(Decentralized Configuration)

大多數伺服器設定工具都有central service,可以在電腦或cluster上執行該服務來集中控制配置代碼和參數的分發,並管理其他活動。 有些團隊喜歡在沒有central service的情況下運作。

團隊分散配置的主要原因是為了簡化基礎設施管理。 配置伺服器是另一組需要管理的部分,並且可能是單點故障。 如果配置伺服器掛了,我們就無法建置新機器,這使其成為災難復原的依賴項。這使其成為災難復原的依賴項。 配置伺服器也可能是效能瓶頸,需要擴展以處理來自(也可能是)數百或數千個Server instance的連線。

若要實現去中心化配置,在離線模式下安裝並執行伺服器設定工具,例如使用chef-solo而非chef-client。 可以從腳本執行該工具,該腳本檢查central file repository以下載最新版本的伺服器配置代碼。 代碼會本機儲存在server instance上,因此即使檔案儲存庫掛掉,該工具仍然可以運行。

Central file repository可能是單點故障或效能瓶頸,就像配置伺服器一樣。 但在實踐中,有許多簡單、高度可靠且高效能的選項可用於託管伺服器配置等靜態檔案。其中包括 Web server、NAS和 AWS S3 等物件儲存服務。

團隊實現分散模式的另一種方法是將伺服器配置代碼捆綁到系統套件(如 .rpm 或 .deb 檔案)中,並將其託管在其私人套件儲存庫中。 regular process運行 yum update 或 apt-get update,安裝或更新軟體包,將伺服器配置碼複製到本機目錄。

其他伺服器生命週期事件

建立、變更和刪除server instances構成了伺服器的基本生命週期。 但在延長的生命週期中還有其他階段,包括停止和重新啟動伺服器(如下圖所示 )、更換伺服器以及恢復故障伺服器。

停止與重啟Server instance

當我們的大多數伺服器都是插電的實體設備時,我們通常會關閉它們來升級硬體,或者在升級某些OS組件時重新啟動它們。

工程師們仍然會停止並重新啟動VM,有時出於相同的原因 — 重新配置VM硬體或升級OS。 我們有時會關閉伺服器以節省託管成本。 例如,如果沒有人使用,有些團隊會在晚上或週末關閉開發和測試伺服器。

然而,如果伺服器很容易重建,許多團隊就會在不使用伺服器時刪除它,並在再次需要時建立新伺服器。 他們這樣做的部分原因是這很容易,而且比簡單地關閉它們可能會節省更多的錢。

但是,刪除和重建伺服器而不是停止並保留伺服器也體現了將伺服器視為“牛群”而不是“寵物”的理念。 團隊可能會停止並重新啟動而不是重建,因為他們無法充滿信心地重建伺服器。 通常的挑戰是保留和恢復應用程式資料。因此,制定不停止和重新啟動伺服器的策略會迫使團隊實施可靠的流程和工具來重建伺服器並保持其正常運作。

停止伺服器也會使維護活動變得複雜。 配置更新和系統補丁不會應用於已停止的伺服器。 根據管理這些類型的更新的方式,伺服器可能會在重新啟動時收到它們,也可能會錯過它們。

替換Server instance

從實體伺服器遷移到VM的眾多好處之一是建置和替換server instance非常容易。 本系列文章中描述的許多模式和實踐,包括immutable servers和頻繁更新server image,都依賴透過建立新伺服器來替換正在運行的伺服器的能力(如下圖所示)。

替換server instance的基本流程是建立一個new instance,驗證其就緒情況,重新配置其他基礎設施和系統以使用new instance,測試它是否正常運作,然後刪除舊的。

根據使用server instance的應用程式和系統,可以在不停機或至少以最短停機時間的情況下執行替換。

一些基礎設施平台具有自動化伺服器更換流程的功能。 例如,可以對自動縮放伺服器叢集中的伺服器定義套用configuration change,指定它應使用包含安全性修補程式的new server image。 該平台會自動新增instance、檢查其運作狀況並刪除舊instance。

在其他情況下,我們可能需要自行更換伺服器。 在pipeline-based change delivery system中實現此目的的一種方法是擴展和收縮。 首先push新增伺服器的變更,然後推送刪除舊伺服器的變更。

回復故障的伺服器

雲端基礎設施不一定可靠。 包括 AWS 在內的一些Cloud Provider明確警告稱,他們可能會在沒有預警的情況下終止server instance,例如,當他們決定更換底層硬體時。 即使具有更強可用性保證的Provider也會出現影響託管系統的硬體故障。

恢復故障伺服器的過程與更換伺服器的過程類似。 一個區別是流程的順序 — 在銷毀舊伺服器之後而不是之前建立新伺服器(如下圖)。 另一個區別是,通常更換伺服器是有意的,而故障則不是。

與更換Server instance一樣,復原可能需要手動操作,或者可以設定平台和其他服務以自動偵測和復原故障。

總結

我們考量了一些何時將配置變更套用至伺服器的模式 — 進行變更時,透過連續將代碼套用至正在運作的伺服器,或透過建立new instance。 我們也討論了如何應用變更的模式 — Puch and Pull。 最後,我們討論了一些其他伺服器生命週期事件,包括停止、替換和回復伺服器。

本文結合Part 11在建立伺服器上,涵蓋了伺服器生命週期中的核心事件。 但是,我們討論的許多創建和更改伺服器的方法都是透過自訂server image來運作的,然後我們可以使用這些Image來建立或更新多個server instance。 因此,Part 13將探討定義、建置和更新server image的方法。

--

--

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

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

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

No responses yet