在現今 DevOps 環境中,自動化佈署是提升軟體交付速度和可靠性的關鍵。本文將探討如何利用作業系統套件管理工具(如 YUM)簡化佈署流程,並透過驗證機制確保佈署的正確性。同時,文章也將探討自動化回復機制的重要性,以及如何透過持續改進和事後檢討來降低風險並提升佈署效率。自動化佈署的核心目標是減少人為錯誤,並確保每次佈署的一致性和可預測性。透過 YUM 等工具,可以有效管理軟體包的安裝、升級和移除,並執行預定義的指令。佈署後的驗證步驟,從簡單的服務可用性檢查到複雜的整合測試,都是確保佈署成功的關鍵。此外,自動化回復機制能快速還原到先前穩定版本,降低佈署失敗的影響。持續改進和增量式自動化則鼓勵團隊根據實際情況逐步最佳化佈署流程,而非一次性完成所有變更。
自動化佈署流程的風險管理與持續改進
在現代化的軟體開發與維運(DevOps)實踐中,自動化佈署流程是實作快速且可靠發布的關鍵要素。透過適當的自動化技術,不僅能降低佈署過程中的風險,還能提高整體的發布效率。
使用作業系統套件管理進行佈署
在佈署自動化的過程中,使用作業系統的套件管理系統(如 YUM)能夠簡化程式碼的安裝與更新流程。透過套件管理,可以實作以下目標:
- 移除舊版本程式碼:確保系統中不再存在舊版本的殘留檔案或設定。
- 安裝新版本程式碼:自動完成新版本的佈署,並執行必要的安裝指令。
- 執行預定義的安裝與解除安裝指令:根據套件中的定義,完成額外的設定或清理工作。
內容解密:
- 使用 YUM 進行佈署自動化的好處在於,它能夠統一管理軟體包的安裝、升級和移除,降低手動操作的錯誤率。
- 透過定義完善的套件,可以確保每次佈署的一致性和可預測性。
驗證佈署結果
完成套件安裝後,進行驗證是確保佈署成功的關鍵步驟。驗證過程可以簡單到使用 curl 命令檢查特定節點的服務是否正常運作,或是驗證登入頁面是否能夠正確載入。
內容解密:
- 簡單的驗證步驟(如檢查登入頁面)雖然基礎,但卻能有效確認服務的基本可用性。
- 隨著時間的推移,可以逐步增加更複雜的驗證邏輯,以提升整體的測試覆寫率。
自動化佈署與回復機制
在自動化佈署的過程中,將節點從負載平衡器池中移除、更新、驗證,然後重新加入,是常見的做法。整個過程應該被自動化,以避免人為錯誤。
若在佈署過程中發現問題,自動化指令碼應能夠停止並進行必要的回復操作。使用 yum downgrade 命令,可以方便地將應用程式還原到先前的版本。
內容解密:
- 自動化回復機制能夠顯著降低佈署失敗帶來的風險。
- 透過
yum downgrade,可以快速還原到穩定版本,減少對業務的影響。
持續改進與增量式自動化
自動化佈署是一個逐步改進的過程。可以先從自動化測試開始,接著改進套件管理,最後實作佈署過程的全面自動化。
內容解密:
- 增量式改進允許團隊根據現狀逐步最佳化,而不必一次性完成所有變更。
- 持續改進是 DevOps 文化的重要組成部分,它鼓勵團隊不斷學習和最佳化流程。
重點整理
- 降低發布頻率的主要原因是恐懼:恐懼源於未知的風險和還原的困難度。
- 降低風險是減少恐懼的關鍵:透過完善的自動化測試和佈署流程,可以有效降低風險。
- 模擬環境永遠無法完全等同於生產環境:需要根據實際情況進行調整和規劃。
- 使用作業系統套件管理建立佈署成品:簡化佈署流程,提高一致性。
- 資料函式庫變更應採用增量式修改:例如,先新增欄位,待下一次發布時再移除舊欄位,以確保相容性。
- 逐步實作佈署流程自動化:持續改進,逐步最佳化現有的工作流程。
事件處理與事後檢討的重要性
當系統發生意外事件(Incident)時,如何處理和學習是 DevOps 文化中的重要一環。透過無責備的事後檢討(Blameless Postmortem),團隊能夠從錯誤中學習,不斷改進系統和流程。
無責備事後檢討的重要性
- 鼓勵學習與改進:無責備的事後檢討能夠讓團隊成員無所顧忌地分享經驗和教訓。
- 最佳化系統和流程:透過對事件的深入分析,可以找出根本原因並進行最佳化。
內容解密:
- 無責備文化鼓勵團隊成員積極參與事件分析,而不是將責任歸咎於個人。
- 這種文化有助於建立信任和開放的溝通環境,從而促進團隊的持續成長。
浪費一個完美的事故機會
學習的最佳來源之一並不是當事情順利進行時,而是當事情出錯時。當系統運作正常時,你對系統的理解和系統的實際狀況未必會產生衝突。想像你有一輛油箱容量為15加侖的汽車。出於某些原因,你以為油箱容量是30加侖,但你有在消耗約10加侖汽油後就加滿油的習慣。如果你堅持這樣做,你對油箱容量的理解永遠不會與實際容量只有15加侖的事實相衝突。你可能會開著車進行數百次的行程,卻從未學到任何東西。但當你決定進行那次長途旅行時,在消耗了16加侖汽油後,你就會遇到問題。很快,你就會意識到自己的錯誤,並開始採取適當的預防措施,因為你已經獲得了這項新資訊。
現在,有幾件事情你可以做。你可以深入研究為什麼你的汽車在第15加侖時就沒油了,或者你可以說:“好吧,我以後每5加侖就加滿油,這樣比較保險。”令人驚訝的是,許多組織選擇了後者。
許多組織不去進行深入的思考,以瞭解系統為什麼會以某種方式運作以及如何改進。事故是驗證你對系統的理解是否與現實相符的一種明確方式。如果不進行這種思考,就是在浪費事故中最有價值的部分。未能從這樣的事件中學習可能會對未來的努力造成損害。
從系統故障中吸取的教訓並不總是自然而然地出現。它們往往需要透過有組織、有結構的方式,從系統和團隊成員那裡引匯出來。這個過程被稱為事後檢討報告、事故報告和回顧等不同的名稱。但我使用“事後分析”這個術語。
事後分析的組成要素
每當發生足夠大的事故時,人們就會開始進行指責遊戲。人們試圖與問題保持距離,設定資訊屏障,並且通常只在為自己撇清責任的範圍內提供幫助。如果你看到這種情況發生在你的組織中,那麼你很可能生活在一個充滿指責和懲罰的文化中:對事故的反應是找出“錯誤”的責任人,並確保他們受到適當的懲罰、羞辱和邊緣化。
指責遊戲的無效性
指責遊戲之所以無效,是因為它將問題歸咎於人。如果人們接受了更好的培訓。如果更多的人瞭解了變更。如果有人遵循了協定。如果有人沒有錯誤地輸入那個命令。這些都是事情可能出錯的有效原因,但它們並沒有觸及到為什麼那個活動(或缺乏活動)會造成如此災難性的失敗的根本原因。
讓我們以培訓失敗為例。如果工程師沒有接受適當的培訓並且犯了錯誤,你應該問自己:“為什麼他沒有接受培訓?”工程師應該從哪裡獲得那種培訓?是因為工程師沒有足夠的時間嗎?如果他們沒有接受培訓,為什麼他們被允許存取系統來執行他們尚未準備好的操作?
這種思維模式的不同之處在於,你正在討論系統中的問題,而不是個人問題。如果你的培訓計劃設計得很差,那麼責備這位工程師並不能解決問題,因為下一批新員工可能會遇到同樣的問題。允許可能沒有資格的人執行危險操作,可能會凸顯出你的組織中缺乏系統和安全控制。任其發展,你的系統將繼續產生處於能夠犯下同樣錯誤的位置的員工。
從指責遊戲轉變為系統性思維
要擺脫指責遊戲,你必須開始思考你的系統、流程、檔案和對系統的理解如何促成了事故狀態。如果你的事後分析變成了報復練習,那麼沒有人會參與,你將失去持續學習和成長的機會。
指責文化另一個副作用是缺乏透明度。沒有人願意為自己所犯的錯誤而受到懲罰。很可能他們已經在為此自責,但現在你再加上經常伴隨指責性事後分析的公開羞辱,這樣你就為人們隱瞞事故或事故具體細節的資訊創造了誘因。
想像一下,一個由操作員輸入命令錯誤而引起的事故。操作員知道,如果他承認這個錯誤,將會有某種懲罰在等待著他。如果他有能力保持沉默,不透露這個資訊,他很可能會保持沉默,而團隊則會花費大量的時間來嘗試排除故障。
一個充滿報復和指責的文化創造了員工不誠實的誘因。缺乏坦率會阻礙你從事故中學習的能力,同時也會模糊事故的事實。無指責文化讓員工免於受到報復,創造了一個更有利於協作和學習的環境。在無指責文化中,大家的注意力從相互指責轉移到了解決問題和改進系統上。
如何進行有效的事後分析
有效的事後分析需要團隊成員之間的開放、誠實和合作。它需要一個無指責的文化,讓團隊成員能夠自由地分享資訊和見解。透過這樣的過程,團隊可以深入瞭解系統的運作方式,並找出需要改進的地方。這不僅有助於防止類別似事故在未來再次發生,也促進了團隊的學習和成長。
無責文化與事後檢討的重要性
在處理系統故障或意外事件時,建立無責文化是至關重要的。這種文化鼓勵團隊成員在事件發生後,進行開放和誠實的討論,而不必擔心受到懲罰或責備。這種做法有助於找出事件的根本原因,並改善系統的韌性和可靠性。
建立心理模型
瞭解人們如何看待系統和流程對於理解故障的發生至關重要。當你參與或負責一個系統時,你會在腦海中建立一個心理模型,以反映你對系統行為和運作的理解。
定義心理模型
心理模型是指某人對某事物運作方式的思考過程的解釋。它可能詳細描述了某人對元件之間關係和互動的認知,以及一個元件的行為如何影響其他元件。個人的心理模型往往可能是不正確或不完整的。
除非你是該系統的專家,否則你的心理模型很可能存在缺陷。例如,一位軟體工程師可能對生產環境的實際情況不完全瞭解。他們知道有網頁伺服器、資料函式庫伺服器和快取伺服器,因為這些是他們經常接觸和互動的元件。但是,他們可能不知道生產環境中存在的其他基礎設施元件,如負載平衡器和防火牆。
心理模型的差距
圖9.1展示了工程師的心理模型與系統的實際情況之間的差異。這種差異不僅存在於電腦系統,也存在於流程中。期望與現實之間的差距是事件和故障的溫床。事後檢討為更新所有人對參與故障的系統的心理模型提供了機會。
遵循24小時規則
24小時規則很簡單:如果你的環境中發生了事件,你應該在24小時內進行事後檢討。原因有兩個:
- 記憶衰退:隨著事件發生和記錄之間時間的流逝,事件的細節會逐漸消失。記憶會褪色,細節會丟失。在事件發生後盡快進行事後檢討,可以保留更多的細節。
- 利用事件的能量:在事件發生後,團隊成員通常會感到緊張和警覺。這種能量可以被利用來推動改進和變更。如果拖延太久,這種能量就會消退。
為什麼要在24小時內進行事後檢討?
- 保留事件細節:事件發生的細節對於瞭解事件的經過和學習至關重要。
- 利用事件後的能量:事件發生後的緊張和警覺可以被用來推動改進。
- 建立檔案:事後檢討檔案可以被廣泛傳閱,讓其他人瞭解故障的原因,並作為未來工程師的教學工具。
設定事後檢討的規則
為了確保事後檢討會議的成功,需要事先設定一些指導方針。這些規則旨在創造一個開放和協作的氛圍,讓參與者感到舒適地分享他們的知識或理解中的缺陷。
創造開放的氛圍
- 消除恐懼:公司文化可能對表現出知識缺陷的人抱有負面態度。需要消除這種恐懼,讓團隊成員感到舒適地分享他們的不確定性。
- 鼓勵學習:透過建立無責文化,鼓勵團隊成員從錯誤中學習,並共同改善系統。
圖表說明
@startuml
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle
title 自動化佈署風險管理與持續改進
package "系統架構" {
package "前端層" {
component [使用者介面] as ui
component [API 客戶端] as client
}
package "後端層" {
component [API 服務] as api
component [業務邏輯] as logic
component [資料存取] as dao
}
package "資料層" {
database [主資料庫] as db
database [快取] as cache
}
}
ui --> client : 使用者操作
client --> api : HTTP 請求
api --> logic : 處理邏輯
logic --> dao : 資料操作
dao --> db : 持久化
dao --> cache : 快取
note right of api
RESTful API
或 GraphQL
end note
@enduml此圖示說明瞭工程師對系統的理解與實際系統之間的差異。左側表示工程師認為系統包含網頁伺服器、資料函式庫伺服器和快取伺服器。右側則顯示了實際系統,除了上述元件外,還包括負載平衡器和防火牆,用於分配負載和提供安全防護。
重點回顧
- 建立無責文化對於從故障中學習至關重要。
- 心理模型的差距可能導致故障,事後檢討有助於更新這些模型。
- 在事件發生後24小時內進行事後檢討,可以保留事件細節,利用事件後的能量,並建立有價值的檔案。
- 設定事後檢討的規則,可以創造一個開放和協作的氛圍,鼓勵團隊成員分享他們的知識或理解中的缺陷。
內容解密:
此段落強調了在技術領域中,建立無責文化和進行有效事後檢討的重要性。首先,無責文化鼓勵團隊成員在事件發生後開放討論,而不擔心受到懲罰。其次,透過瞭解個人對系統的心理模型,可以找出知識或理解中的缺陷。最後,遵循24小時規則和設定事後檢討的規則,可以確保檢討的有效性和團隊成員的參與度。
事件回顧與檢討的重要性
在處理技術事故或事件時,進行詳細的回顧與檢討是至關重要的。這不僅能夠幫助我們瞭解事件的起因和經過,還能夠讓我們從中吸取教訓,改進系統,避免類別似事件在未來再次發生。
事件處理的基本原則
在進行事件回顧時,應遵循以下基本原則:
- 不直接批評個人,聚焦於行為和行動。
- 假設每個人在當時情況下已經盡了最大努力。
- 認識到某些事實在當時可能被混淆或不清楚。
- 將責任歸咎於系統而非個人。
- 目標是全面瞭解事件的所有相關因素。
這些原則有助於將討論焦點放在系統改進上,避免陷入指責遊戲的陷阱。
事件案例分析
某天凌晨1:29,監控系統檢測到一個後台工作佇列超過了設定的閾值。值班工程師Shawn在1:30左右收到警示,並在檢視後決定稍後再處理。30分鐘後,警示再次響起,此時佇列規模更大。Shawn嘗試重啟相關的工作,但問題仍未解決。隨後,他決定聯絡值班開發工程師,但由於資訊不全和聯絡方式不明確,導致處理延遲。最終,在經理和首席工程師的介入下,問題得以解決,原來是consumer_daemon程式停止運作導致佇列無法被處理。
程式碼範例與解析
import threading
import time
import queue
# 模擬 consumer_daemon 程式
def consumer(queue):
while True:
try:
item = queue.get(timeout=1)
# 處理佇列中的專案
print(f"Processing item: {item}")
queue.task_done()
except queue.Empty:
# 若佇列為空,則略過
pass
except Exception as e:
# 紀錄例外狀況
print(f"Error occurred: {e}")
# 初始化佇列和 consumer_daemon 程式
q = queue.Queue()
consumer_thread = threading.Thread(target=consumer, args=(q,))
consumer_thread.daemon = True # 設定為 daemon 程式
consumer_thread.start()
# 模擬生產者向佇列新增專案
for i in range(10):
q.put(i)
# 等待佇列中的專案被處理完畢
q.join()
內容解密:
- 程式初始化:首先,我們初始化了一個佇列
q和一個consumer函式,該函式負責不斷地從佇列中取出專案並進行處理。 - Daemon程式:
consumer_thread被設定為daemon程式,這意味著當主程式結束時,該執行緒也會自動結束。 - 佇列處理邏輯:在
consumer函式中,我們使用了一個無限迴圈來不斷檢查佇列中是否有專案。如果佇列為空,則略過;如果發生例外,則進行紀錄。 - 生產者邏輯:我們模擬了一個生產者,向佇列中增加了10個專案。
q.join()的作用:主程式會等待直到佇列中的所有專案都被處理完畢才繼續執行。
事件回顧會議的必要性
事件回顧會議(Postmortem)對於瞭解事件的發生過程、影響以及如何改進至關重要。參與者應包括所有與事件處理相關的人員,以及可能受事件影響的專案經理和業務利益相關者。
邀請參與事件回顧會議的人員
除了技術人員外,專案經理和業務利益相關者也應被邀請參加。他們可以提供不同的視角,瞭解事件對專案和業務的影響,並幫助制定未來的改進措施。
事件檢討會議的最佳實踐
在進行事件檢討(postmortem)時,參與人員的多樣性對於完整理解事件至關重要。邀請不同部門的代表,如技術團隊、業務相關人員甚至人力資源代表,可以提供多角度的洞察。
業務相關人員的參與
邀請業務相關人員參與事件檢討會議可以提供上下文和透明度。他們可以幫助技術團隊理解事件對業務營運的影響。例如,如果某個關鍵系統在不合適的時間宕機,可能會延遲賬單傳送,進而影回應收賬款和現金流。
人力資源代表的參與
在某些情況下,邀請人力資源代表參加事件檢討會議也是有益的,特別是當事件與資源分配或人員配備有關時。他們可以見證事件的展開過程和相關的痛點,從而更好地理解問題的根源。
事件時間軸的建立
事件時間軸是事件檢討會議的核心內容。它記錄了事件發生期間的一系列事件。建立時間軸有助於所有參與者對事件的發生順序和時間達成共識。
時間軸的詳細記錄
在建立時間軸時,每個事件都應包含以下資訊:
- 發生了什麼動作或事件?
- 誰執行了該動作或事件?
- 動作或事件發生的時間?
描述應簡潔明瞭,避免新增個人評論或動機,保持事實的客觀性。例如,「透過服務控制台重新啟動支付服務」是一個清晰的事實陳述。
使用角色或職位而非個人姓名可以避免將錯誤歸咎於特定個人,同時保持檔案的長期有效性。未來的工程師可能不知道特定的人,但知道某個角色負責某項操作,可以提供必要的上下文。
時間軸的驗證與討論
在會議上逐步檢視時間軸,確認團隊成員對事件的具體內容和順序沒有異議。提前分發時間軸草稿給與會者,可以節省會議時間,讓大家有機會事先審閱並提出修改意見。
例子:事件時間軸的記錄
以下是一個記錄事件時間軸的例子:
事件:支付服務透過服務控制台重新啟動。
- 執行者:系統工程師1。
- 時間:2023年3月10日 14:00。
事件:網頁伺服器記憶體耗盡並當機。
- 執行者:付款網頁伺服器主機10.0.2.55。
- 時間:2023年3月10日 14:05。
詳細解說
每個事件都按照「#### 內容解密:」的方式進行詳細解說,這有助於團隊成員理解事件的來龍去脈和技術細節。
內容解密:
事件「支付服務透過服務控制台重新啟動」表明了操作人員試圖透過重新啟動服務來解決當前的問題。這一操作的目的是希望能夠還原服務的正常運作,但同時也可能引入新的變數影響後續的系統表現。
事件「網頁伺服器記憶體耗盡並當機」則指出了系統在處理請求時遇到的技術問題。這一問題可能是由於伺服器組態不當、負載過高或程式碼效率不佳等多種原因引起的。明確指出具體的主機(10.0.2.55),有助於後續針對該節點進行檢查和最佳化。