隨著微服務架構和容器化技術的普及,系統的複雜性不斷增加,對系統穩定性和可用性的要求也越來越高。本文介紹的自我修復系統,旨在透過自動化流程和工具,快速檢測和修復故障,確保服務的持續執行。系統的核心是 Jenkins Pipeline,它整合了 Ansible Playbook,用於自動化佈署和基礎設施修復。Consul 作為服務發現和組態中心,提供服務健康檢查和例項數量管理,實作動態擴充套件和縮減。透過預先定義的 playbook,系統可以自動嘗試修復 Swarm 和代理服務,而 try-catch 機制則避免了因節點故障導致的佈署中斷。此外,系統利用 Consul 的 KV 儲存功能,記錄服務例項數量,確保重新佈署後例項數量與之前保持一致。
自我修復系統的重新佈署流程
自我修復系統的一個關鍵方面是能夠快速重新佈署服務,以還原系統到正常運作狀態。重新佈署的Jenkinsfile(node("cd"))比之前的版本簡潔許多,這得益於將通用功能抽取到workflow-util.groovy指令碼中。
重新佈署指令碼解析
node("cd") {
def prodIp = "10.100.192.200"
def swarmIp = "10.100.192.200"
def proxyNode = "swarm-master"
def swarmPlaybook = "swarm-healing.yml"
def proxyPlaybook = "swarm-proxy.yml"
def flow = load "/data/scripts/workflow-util.groovy"
def currentColor = flow.getCurrentColor(serviceName, prodIp)
def instances = flow.getInstances(serviceName, swarmIp)
deleteDir()
git url: "https://github.com/vfarcic/${serviceName}.git"
try {
flow.provision(swarmPlaybook)
flow.provision(proxyPlaybook)
} catch (e) {}
flow.deploySwarm(serviceName, prodIp, currentColor, instances)
flow.updateBGProxy(serviceName, proxyNode, currentColor)
}
內容解密:
- 引數定義:首先定義了生產環境IP、Swarm IP、代理節點、以及兩個Ansible playbook的名稱。
- 載入通用函式:載入了
workflow-util.groovy指令碼,該指令碼包含了重新佈署所需的通用函式。 - 取得當前服務狀態:透過
getCurrentColor和getInstances函式取得當前服務的顏色和例項數量。 - 清理工作空間:刪除當前工作目錄下的所有檔案,以避免不同Git儲存函式庫之間的衝突。
- 克隆服務程式碼:從GitHub克隆指定服務的程式碼倉函式庫。
- 嘗試修復基礎設施:透過Ansible playbook嘗試修復Swarm和代理服務。這一步被包裹在try-catch塊中,以避免因節點故障導致的錯誤。
- 重新佈署服務:呼叫
deploySwarm函式重新佈署服務,並更新代理組態。
取得例項數量的函式
def getInstances(serviceName, swarmIp) {
return sendHttpRequest("http://${swarmIp}:8500/v1/kv/${serviceName}/instances?raw")
}
內容解密:
- 功能:該函式透過向Consul傳送HTTP請求,取得指定服務的例項數量。
- 目的:確保重新佈署的例項數量與之前保持一致,避免破壞其他人的組態。
重新佈署的關鍵點
- 快速還原:重新佈署的主要目標是快速還原服務,而不是重新構建和佈署新的版本。
- 避免重複測試:由於測試已經在佈署階段完成,重新佈署過程中不再重複執行。
- 基礎設施修復:透過Ansible playbook嘗試修復可能導致服務失敗的基礎設施問題。
自我修復系統的實踐與探索
在前面的章節中,我們探討瞭如何利用 Consul、Jenkins 和 Docker Swarm 來建立一個具自我修復能力的系統。本章節將進一步探討自我修復系統的概念,並介紹如何透過排程擴充套件和縮減來實作預防性修復。
自我修復系統的原理
自我修復系統的核心思想是透過自動檢測和修復故障來維持系統的穩定性和可用性。在我們的示例中,Consul 會定期向服務傳送 HTTP 請求,如果請求失敗,Consul 就會觸發 Jenkins 的重新佈署流程,從而還原服務的正常運作。
程式碼範例:Consul 檢查服務狀態
curl swarm-master/api/v1/books
內容解密:
此命令用於檢查 books-ms 服務是否正常運作。如果服務未運作,Consul 將檢測到此狀態並觸發重新佈署。
模擬故障與自我修復
為了驗證自我修復系統的有效性,我們模擬了兩種故障場景:停止基礎設施服務(nginx)和刪除服務容器。
停止 nginx 服務
- 進入
swarm-master節點並停止 nginx 容器。vagrant ssh swarm-master docker stop nginx exit - 使用
curl命令檢查服務狀態,預期會傳回連線失敗的錯誤。curl swarm-master/api/v1/books - Consul 將檢測到服務故障並觸發 Jenkins 重新佈署流程。
- 進入
刪除服務容器
- 刪除
books-ms服務容器。export DOCKER_HOST=tcp://swarm-master:2375 docker rm -f $(docker ps --filter name=booksms --format "{{.ID}}") - 檢視 Jenkins 控制檯,確認重新佈署流程是否啟動。
- 使用
docker ps命令檢查服務容器是否已重新建立。docker ps --filter name=books --format "table {{.Names}}"
- 刪除
程式碼範例:檢查服務容器狀態
docker ps --filter name=books --format "table {{.Names}}"
curl -I swarm-master/api/v1/books
內容解密:
- 第一條命令用於檢查
books-ms服務容器的狀態。 - 第二條命令用於檢查服務是否可存取,預期傳回 HTTP 200 OK 狀態碼,表示服務正常運作。
預防性修復:排程擴充套件與縮減
預防性修復是一種主動措施,透過預測系統負載變化來提前調整資源分配,從而避免系統過載。我們的示例場景是線上書店在新年期間推出折扣活動,預計會帶來巨大的流量。
場景分析
- 預測新年期間系統將面臨高負載。
- 利用排程工具(如 Jenkins)提前擴充套件服務例項,以應對預期的高流量。
實施步驟
- 評估歷史資料:分析過去的流量資料,預測新年期間的流量峰值。
- 排程擴充套件:利用 Jenkins 的排程功能,在預期流量高峰前自動擴充套件服務例項。
- 監控與調整:在活動期間持續監控系統狀態,根據需要調整資源分配。
自我修復系統的預防性維護:排程擴充套件與縮減實務
在現代化的系統維運中,自我修復能力(Self-Healing)不僅僅侷限於故障發生後的自動修復,更包含了預防性措施來避免系統在高負載下出現問題。本文將探討如何利用 Jenkins 實作服務的自動擴充套件與縮減,以確保系統在特定時間段內能夠承受更高的負載需求。
擴充套件與縮減的需求背景
假設我們的系統需要在跨年夜期間承受比平時更高的流量,我們需要提前對服務進行擴充套件以確保系統穩定性,而在活動結束後再進行縮減以節省資源。這樣的需求可以透過 Jenkins 的排程任務來實作自動化。
Jenkins 任務組態詳解
首先,我們來看一下 books-ms-scale 這個 Jenkins 任務的組態:
- 引數化構建:該任務有一個名為
scale的引數,預設值為 2,表示需要擴充套件的例項數量。 - 定時觸發:任務組態了定時構建,使用 cron 表示式
45 23 31 12 *,即在每年12月31日23點45分執行任務。 - 工作流程指令碼:該任務的核心是其工作流程指令碼,負責計算新的例項數量並更新至 Consul,然後觸發
service-redeploy任務進行實際的服務重新佈署。
工作流程指令碼解析
node("cd") {
def serviceName = "books-ms"
def swarmIp = "10.100.192.200"
def flow = load "/data/scripts/workflow-util.groovy"
def instances = flow.getInstances(serviceName, swarmIp).toInteger() + scale.toInteger()
flow.putInstances(serviceName, swarmIp, instances)
build job: "service-redeploy", parameters: [[$class: "StringParameterValue", name: "serviceName", value: serviceName]]
}
指令碼解密:
- 節點選擇:
node("cd")指定了執行該任務的節點。 - 變數定義:定義了服務名稱
serviceName和 Swarm 的 IP 地址swarmIp。 - 載入工具指令碼:透過
load命令載入了一個名為workflow-util.groovy的指令碼,該指令碼提供了一些輔助函式,如取得和設定例項數量。 - 計算新的例項數量:將當前例項數量與
scale引數相加,得到新的例項數量。 - 更新 Consul:將新的例項數量更新到 Consul 中。
- 觸發重新佈署:透過呼叫
service-redeploy任務並傳遞服務名稱,觸發服務的重新佈署。
手動驗證擴充套件與縮減
在組態完成後,我們可以手動執行 books-ms-scale 任務來驗證其是否能夠正確地將服務例項數量擴充套件。執行後,我們可以透過 Docker 命令和 Consul UI 來確認例項數量是否已經正確更新。
手動執行與驗證步驟
- 檢查當前例項數量:使用
docker ps命令過濾出books-ms相關的容器,並使用curl命令查詢 Consul 中的例項數量記錄。 - 執行
books-ms-scale任務:在 Jenkins 介面手動觸發該任務。 - 驗證擴充套件結果:再次使用
docker ps和curl命令檢查例項數量是否已經增加到預期值。
同樣的邏輯也適用於縮減例項數量的 books-ms-descale 任務,只不過其 scale 引數被設定為 -2,並且定時觸發時間設定在活動結束後。
自我修復系統的進階探討
自我修復系統(Self-Healing Systems)是現代雲端運算與容器化技術中的重要概念,旨在提升系統的穩定性與可靠性。在前面的章節中,我們已經探討了利用 Docker Swarm、Ansible、Consul 和 Jenkins 等工具來實作自我修復的基本方法。本章節將進一步深入討論自我修復系統的原理與實踐,特別是在預防性修復和反應性修復方面的應用。
預防性修復:根據歷史資料的最佳化
預防性修復的核心在於根據歷史資料預測並避免潛在的問題。在實際操作中,這意味著需要對系統的執行狀態進行持續監控和分析,以便在問題發生之前採取相應的措施。
實務案例:利用歷史資料進行擴充套件
在進行大規模促銷活動前,系統管理員可以根據歷史資料預測活動期間的流量負載,從而提前擴充套件相關服務的例項數量。這種做法可以有效避免因流量激增導致的服務中斷。
docker ps --filter name=books --format "table {{.Names}}"
curl swarm-master:8500/v1/kv/books-ms/instances?raw
上述命令用於檢查當前執行的容器例項,並從 Consul 中取得相關服務的組態資訊。根據這些資訊,管理員可以決定是否需要擴充套件服務例項。
公式與策略的選擇
在進行服務擴充套件時,可以採用不同的公式或策略。例如,可以簡單地將現有例項數量乘以一定的倍數,以應對預期的流量增長。當然,更複雜的策略可能需要根據具體的業務需求和系統架構進行設計。
此圖示展示了預防性修復的基本流程,從歷史資料分析到執行服務擴充套件,每一步都是為了確保系統在面對高負載時仍能保持穩定執行。
內容解密:
- 歷史資料分析:利用過去的資料來預測未來的流量和負載。
- 預測流量負載:根據歷史資料和業務計劃預測即將到來的流量。
- 決定擴充套件策略:根據預測結果決定是否以及如何擴充套件服務例項。
- 執行服務擴充套件:使用 Docker Swarm 等工具增加服務例項數量。
- 監控系統狀態:持續監控系統的執行狀態,確保擴充套件措施的有效性。
反應性修復:Docker 重啟策略的侷限性
反應性修復是指在問題發生後採取相應的措施來還原系統的正常執行。Docker 提供了重啟策略(Restart Policies)來自動重啟失敗的容器,但這種方法存在一定的侷限性。
Docker 重啟策略的使用
Docker 的重啟策略可以透過 --restart 引數在 docker run 命令中指定。例如:
docker run --restart=on-failure:3 mongo
這將使 mongo 容器在離開狀態為非零時最多重啟三次。
內容解密:
--restart=on-failure:3:指定重啟策略為on-failure,並限制最大重試次數為 3 次。mongo容器:這裡以mongo容器為例,實際應用中可以替換為任何需要的容器。
重啟策略的侷限性
儘管 Docker 的重啟策略可以在一定程度上還原失敗的容器,但它無法處理更複雜的故障場景。例如,如果一個服務依賴於外部資料函式庫或代理,而這些外部依賴出現故障,重啟容器並不能解決根本問題。
結合本地與雲端節點的自我修復系統
在討論是否使用本地伺服器或雲端託管時,我們不應該偏袒任何一方。兩者都有其優缺點,選擇取決於個人的需求。此外,這樣的討論更適合放在叢集和擴充套件的章節中。然而,有一個明顯的使用案例有利於雲端託管,至少適用於本章的一個場景。
當我們需要暫時增加叢集容量時,雲端託管表現出色。一個很好的例子是我們虛構的新年前夕促銷活動場景。我們需要在一天內提升容量。如果我們已經將所有伺服器託管在雲端,這個場景只需要建立更多的節點,然後在負載降低到原來的規模後銷毀它們。另一方面,如果我們使用本地託管,這將是一個機會,只為那些額外的節點簽約雲端託管。購買一套新的伺服器只在短時間內使用是非常昂貴的,尤其是當我們考慮到成本不僅包括硬體價格,還包括維護費用。如果在這種情況下,我們使用雲端節點,只需支付使用時間的費用(假設我們之後會銷毀它們)。由於我們擁有所有用於供應和佈署服務的指令碼,這些節點的設定將幾乎毫不費力。
自我修復系統的優勢
個人而言,我更喜歡結合本地和雲端託管。我的本地伺服器滿足了對最低容量的需求,而雲端託管節點則在需要暫時增加容量時被建立(和銷毀)。請注意,這種組合只是我的個人偏好,可能不適用於您的使用案例。
重要的是,您在本文中學到的所有內容都同樣適用於兩種情況(本地或雲端)。唯一的顯著差異是,您不應該在生產伺服器上使用Vagrant。我們只使用它來在您的筆記型電腦上快速建立虛擬機器。如果您正在尋找一種類別似於Vagrant的方式來建立生產虛擬機器,我建議您探索另一個名為Packer的HashiCorp產品。
自我修復系統的未來
到目前為止,我們所構建的系統在某些情況下接近Kubernetes和Mesos開箱即用的功能,而在其他方面則超出了它們的功能。我們正在開發的系統的真正優勢在於能夠根據您的需求進行微調。這並不是說不應該使用Kubernetes和Mesos。您至少應該熟悉它們。不要輕信任何人(甚至我)的話。嘗試它們並得出自己的結論。有和專案一樣多的使用案例,每個案例都與其他案例不同。在某些情況下,我們構建的系統提供了一個良好的基礎來構建,而在其他情況下,例如Kubernetes或Mesos可能更合適。我無法在單本文中詳細介紹所有可能的組合。那樣會使書籍變得難以管理。相反,我選擇探索如何構建具有高度擴充套件性的系統。到目前為止,我們使用的幾乎每個部分都可以擴充套件或替換。我覺得這種方法為您提供了更多可能性來使示例適應您的需求,同時不僅學習某件事情的工作原理,還學習為什麼我們選擇它。
銷毀虛擬機器
隨著自我修復主題的第一部分接近尾聲,讓我們銷毀我們的虛擬機器,並以嶄新的面貌開始新的一章。
您知道接下來會發生什麼。我們將銷毀我們所做的一切,並以嶄新的面貌開始下一章。
1 exit
2
3 vagrant halt
集中式日誌記錄和監控
我們的DevOps實踐和工具的探索使我們走向了叢集和擴充套件。因此,我們開發了一個系統,可以輕鬆高效地將服務佈署到叢集。結果是越來越多的容器執行在一個可能由許多伺服器組成的叢集上。監控一台伺服器很容易。在單台伺服器上監控多個服務會帶來一些困難。在多台伺服器上監控多個服務需要全新的思維方式和一套新的工具。當您開始採用微服務、容器和叢集時,佈署的容器數量將開始迅速增加。形成叢集的伺服器也是如此。我們不能再登入到一個節點並檢視日誌。那裡有太多日誌需要檢視。此外,它們分佈在許多伺服器上。雖然昨天我們在一台伺服器上佈署了兩個服務例項,但明天我們可能在六台伺服器上佈署了八個例項。監控也是如此。像Nagios這樣的舊工具不是為處理執行中的伺服器和服務的頻繁變化而設計的。我們已經使用了Consul,它提供了一種不同的、可以說是新的方法來管理近乎實時的監控和達到門檻值時的反應。然而,這還不夠。實時資訊對於檢測出了什麼問題很有價值,但它不能告訴我們為什麼會發生故障。我們可以知道一個服務沒有回應,但不知道為什麼。
集中式日誌記錄和監控的需求
我們需要關於系統的歷史資訊。這種資訊可以以日誌、硬體利用率、健康檢查等形式存在。儲存歷史資料的需求並不新鮮,已經存在很長時間了。然而,資訊傳遞的方向隨著時間而改變。在過去,大多數解決方案都根據集中式資料收集器。如今,由於服務和伺服器的動態性質,我們傾向於將資料收集器分散。如今,我們需要的是分散式資料收集器,它們將資訊傳送到集中式的解析服務和資料儲存。有很多專門設計用來滿足這一需求的產品,從本地解決方案到雲端解決方案,不一而足。FluentD、Loggly、GrayLog、Splunk和DataDog只是我們可以使用的幾種解決方案。我選擇透過ELK堆積疊向您展示這些概念。
ELK堆積疊簡介
ELK堆積疊是一個強大的工具,用於集中式日誌記錄和監控。它由Elasticsearch、Logstash和Kibana三個主要元件組成。
@startuml
skinparam backgroundColor #FEFEFE
title 自我修復系統重新佈署流程與實踐
|開發者|
start
:提交程式碼;
:推送到 Git;
|CI 系統|
:觸發建置;
:執行單元測試;
:程式碼品質檢查;
if (測試通過?) then (是)
:建置容器映像;
:推送到 Registry;
else (否)
:通知開發者;
stop
endif
|CD 系統|
:部署到測試環境;
:執行整合測試;
if (驗證通過?) then (是)
:部署到生產環境;
:健康檢查;
:完成部署;
else (否)
:回滾變更;
endif
stop
@enduml
此圖示展示了ELK堆積疊的基本架構。
內容解密:
- Logstash:負責收集和處理來自不同來源的日誌。
- Elasticsearch:一個強大的搜尋引擎,用於儲存和索引日誌資料。
- Kibana:提供了一個使用者友好的介面,用於視覺化Elasticsearch中的資料。
- Beats:輕量級的日誌收集器,可以將資料傳送到Logstash或Elasticsearch。
ELK堆積疊提供了一個完整的解決方案,用於集中式日誌記錄和監控,使我們能夠更好地理解系統的行為並快速定位問題。