隨著系統規模的增長,維護系統的穩定性和可用性變得越來越具有挑戰性。本文介紹的自我修復系統,旨在透過自動化監控和修復機制,提高系統的容錯能力和穩定性。系統的核心元件包括 Consul、Jenkins 和 Ansible。Consul 負責服務發現和健康檢查,Jenkins 負責 CI/CD 流程,而 Ansible 則負責自動化組態管理。透過整合這些工具,我們可以實作對硬體資源和服務的全面監控,並在出現問題時自動觸發修復程式,例如重新佈署服務或傳送告警通知。

自我修復系統的設定與硬體監控

環境設定

首先,我們需要建立四個虛擬機器(VMs),並使用Vagrant來管理它們。我們將建立一個名為cd的節點,並使用Ansible來組態其他節點。同時,cd節點也將託管Jenkins,這將是自我修復過程中的重要部分。其他三個虛擬機器將形成Swarm叢集。

vagrant up cd swarm-master swarm-node-1 swarm-node-2

啟動所有虛擬機器後,我們可以透過SSH連線到cd節點,並使用Ansible來設定Swarm叢集。

vagrant ssh cd
ansible-playbook /vagrant/ansible/swarm.yml -i /vagrant/ansible/hosts/prod

接下來,我們需要組態cd伺服器上的Jenkins。

ansible-playbook /vagrant/ansible/jenkins-node-swarm.yml -i /vagrant/ansible/hosts/prod
ansible-playbook /vagrant/ansible/jenkins.yml --extra-vars "main_job_src=service-healing-config.xml" -c local

使用Consul進行健康檢查和監控

Consul允許我們傳送指令來執行週期性的服務檢查或整個節點的檢查。它不帶有預定義的檢查,而是執行指令碼、執行HTTP請求或等待TTL訊號。我們將建立一些指令碼來執行硬體檢查,例如檢查磁碟使用率。

df -h

內容解密:

  • df -h命令用於顯示檔案系統的磁碟使用情況,-h選項使其以人類可讀的格式輸出。
  • 輸出結果包含了檔案系統的大小、已用空間、可用空間、使用百分比和掛載點等資訊。

我們需要過濾df命令的輸出,以提取根目錄(/)的使用情況,包括磁碟大小、已用空間和使用百分比。

set -- $(df -h | awk '$NF=="/"{print $2" "$3" "$5}')
total=$1
used=$2
used_percent=${3::-1}
printf "Disk Usage: %s/%s (%s%%)\n" $used $total $used_percent

內容解密:

  • awk '$NF=="/"{print $2" "$3" "$5}'用於過濾出根目錄(/)的行,並列印出第二、第三和第五列(分別代表磁碟大小、已用空間和使用百分比)。
  • 將提取的值賦給totalusedused_percent變數。
  • used_percent=${3::-1}移除使用百分比後的百分號(%)。
  • printf陳述式用於格式化輸出磁碟使用情況。

建立Consul檢查指令碼

swarm-master節點上建立一個指令碼,用於檢查磁碟使用率並根據閾值傳回相應的離開碼。

echo '#!/usr/bin/env bash
set -- $(df -h | awk '"'"'$NF=="/"{print $2" "$3" "$5}'"'"')
total=$1
used=$2
used_percent=${3::-1}
printf "Disk Usage: %s/%s (%s%%)\n" $used $total $used_percent
if [ $used_percent -gt 95 ]; then
    exit 2
elif [ $used_percent -gt 80 ]; then
    exit 1
else
    exit 0
fi' | sudo tee /data/consul/scripts/disk.sh
sudo chmod +x /data/consul/scripts/disk.sh

內容解密:

  • 指令碼首先提取根目錄的磁碟使用資訊。
  • 根據使用百分比與設定的閾值(95%和80%)比較,傳回不同的離開碼(2表示錯誤,1表示警告,0表示正常)。
  • 將指令碼寫入/data/consul/scripts/disk.sh並賦予執行許可權。

組態Consul檢查

建立一個JSON檔案來定義Consul檢查,該檢查將執行我們剛建立的指令碼。

echo '{
    "checks": [
        {
            "id": "disk",
            "name": "Disk utilization",
            "notes": "Critical 95% util, warning 80% util",
            "script": "/data/consul/scripts/disk.sh",
            "interval": "10s"
        }
    ]
}' | sudo tee /data/consul/config/consul_check.json
sudo killall -HUP consul

內容解密:

  • JSON檔案定義了一個名為“Disk utilization”的檢查,指令碼路徑為/data/consul/scripts/disk.sh,並設定每10秒執行一次。
  • 使用sudo killall -HUP consul重新載入Consul組態,使新的檢查生效。

結果驗證

存取Consul的UI(http://10.100.192.200:8500/ui/),導航到節點頁面並選擇swarm-master節點,可以看到我們建立的“Disk utilization”檢查的狀態。

自我修復系統中的 Consul Watcher 機制實作

在前面的章節中,我們已經瞭解如何在 Consul 中新增檢查機制。現在,我們需要定義當檢查失敗時應該執行的動作。這可以透過 Consul Watches 來實作。Consul Watches 提供了一種機制,讓我們能夠根據不同的事件型別建立相應的處理方案。

Consul Watches 的型別

Consul 支援七種不同型別的 Watches:

  • key:監控特定的 KV 對
  • keyprefix:監控 KV 儲存中的字首
  • services:監控可用的服務列表
  • nodes:監控節點列表
  • service:監控特定服務的例項
  • checks:監控健康檢查的值
  • event:監控自定義的使用者事件

這些 Watch 型別在不同的情況下非常有用,並且共同提供了一個非常全面的框架,用於建立自我修復和容錯的系統。

建立 Consul Watcher 指令碼

我們將專注於 checks 型別,因為它允許我們利用之前建立的硬碟檢查。讓我們先建立一個指令碼,該指令碼將由 Consul Watcher 執行。

#!/usr/bin/env bash

RED="\033[0;31m"
NC="\033[0;0m"

read -r JSON
echo "Consul watch request:"
echo "$JSON"

STATUS_ARRAY=($(echo "$JSON" | jq -r ".[].Status"))
CHECK_ID_ARRAY=($(echo "$JSON" | jq -r ".[].CheckID"))
LENGTH=${#STATUS_ARRAY[*]}

for (( i=0; i<=$(( $LENGTH -1 )); i++ ))
do
    CHECK_ID=${CHECK_ID_ARRAY[$i]}
    STATUS=${STATUS_ARRAY[$i]}
    echo -e "${RED}Triggering Jenkins job http://10.100.198.200:8080/job/hardware-notification/build${NC}"
    curl -X POST http://10.100.198.200:8080/job/hardware-notification/build \
    --data-urlencode json="{\"parameter\": [{\"name\":\"checkId\", \"value\":\"$CHECK_ID\"}, {\"name\":\"status\", \"value\":\"$STATUS\"}]}"
done

內容解密:

  1. 指令碼初始設定:定義了 REDNC 變數,用於在輸出中以紅色顯示關鍵資訊。
  2. 讀取 Consul 輸入:讀取 Consul 傳入的 JSON 資料並儲存到 JSON 變數中。
  3. 解析 JSON 資料:使用 jq 工具解析 JSON 資料,提取 StatusCheckID 值,並分別儲存到 STATUS_ARRAYCHECK_ID_ARRAY 陣列中。
  4. 迴圈處理檢查結果:遍歷陣列中的每個元素,根據 CheckIDStatus 的值,向 Jenkins 傳送 POST 請求,觸發 hardware-notification 作業的構建。

建立 Watcher 指令碼檔案

echo '#!/usr/bin/env bash
# ... (指令碼內容與上述相同)
' | sudo tee /data/consul/scripts/manage_watches.sh
sudo chmod +x /data/consul/scripts/manage_watches.sh

定義 Consul Watches 設定

{
    "watches": [
        {
            "type": "checks",
            "state": "warning",
            "handler": "/data/consul/scripts/manage_watches.sh >>/data/consul/logs/watches.log"
        },
        {
            "type": "checks",
            "state": "critical",
            "handler": "/data/consul/scripts/manage_watches.sh >>/data/consul/logs/watches.log"
        }
    ]
}

內容解密:

  1. Watches 設定結構:定義了一個包含兩個 Watch 的設定,分別用於監控 warningcritical 狀態的檢查。
  2. 處理指令碼:當檢查狀態符合設定的條件時,執行 manage_watches.sh 指令碼,並將輸出記錄到 watches.log 檔案中。

建立 Watches 設定檔案

echo '{
    "watches": [
        {
            "type": "checks",
            "state": "warning",
            "handler": "/data/consul/scripts/manage_watches.sh >>/data/consul/logs/watches.log"
        },
        {
            "type": "checks",
            "state": "critical",
            "handler": "/data/consul/scripts/manage_watches.sh >>/data/consul/logs/watches.log"
        }
    ]
}' | sudo tee /data/consul/config/watches.json

修改硬碟檢查門檻值並重新載入 Consul

sudo sed -i "s/80/2/" /data/consul/scripts/disk.sh
sudo killall -HUP consul

練習:修改 Jenkins 作業以刪除日誌檔案

修改 hardware-notification Jenkins 作業,使其在 checkId 值為 disk 時刪除日誌檔案。在伺服器上建立模擬日誌檔案並手動執行該作業。完成後,確認日誌檔案是否已被刪除。

自動修復系統的硬體與服務監控實作

在前面的章節中,我們已經成功地在 swarm-master 節點上設定了 Consul 健康檢查與監控硬體資源。然而,這種手動設定的方式不僅耗時,而且難以擴充套件到整個叢集。因此,本章節將介紹如何使用 Ansible 自動化設定 Consul 健康檢查與監控硬體資源,並進一步擴充套件到服務監控。

使用 Ansible 自動化設定 Consul 健康檢查

首先,我們需要執行 Ansible playbook 來自動化設定 Consul 健康檢查。相關的 playbook 是 swarm-healing.yml,它與之前的 swarm.yml playbook 類別似,但額外使用了 consul-healing 角色。

vagrant ssh cd
ansible-playbook /vagrant/ansible/swarm-healing.yml -i /vagrant/ansible/hosts/prod

內容解密:

  1. vagrant ssh cd:登入 Vagrant 虛擬機器。
  2. ansible-playbook 命令用於執行 Ansible playbook。
  3. /vagrant/ansible/swarm-healing.yml 是 playbook 的路徑。
  4. -i /vagrant/ansible/hosts/prod 指定了 inventory 檔案的路徑,用於定義目標主機。

swarm-healing.yml playbook 的內容如下:

- hosts: swarm
  remote_user: vagrant
  serial: 1
  sudo: yes
  vars:
    - debian_version: vivid
    - docker_cfg_dest: /lib/systemd/system/docker.service
    - is_systemd: true
  roles:
    - common
    - docker
    - consul-healing
    - swarm
    - registrator

內容解密:

  1. hosts: swarm 指定了目標主機群組。
  2. remote_user: vagrant 指定了遠端使用者名稱。
  3. serial: 1 表示 Ansible 將逐一執行任務,而不是平行執行。
  4. sudo: yes 允許 Ansible 使用 sudo 許可權執行任務。
  5. vars 部分定義了變數,例如 Debian 版本和 Docker 設定檔的路徑。
  6. roles 部分列出了將要執行的角色,包括 consul-healing

Consul 健康檢查的運作

在執行完 Ansible playbook 後,我們可以檢查 Consul UI 以確認健康檢查是否已經設定成功。請開啟 http://10.100.192.200:8500/ui/#/dc1/nodes,並點選任意節點。你將會看到每個節點都有 Disk utilization 和 Memory utilization 的監控專案。

從硬體監控到服務監控

雖然監控硬體資源是有用的,但真正的價值在於監控服務。在本章節中,我們將介紹如何使用 Consul 監控服務。首先,我們需要佈署 books-ms 容器。請開啟 Jenkins job books-ms,點選 Branch Indexing 連結,並執行 Run Now。Jenkins 將會偵測到 swarm 分支,並執行第一次建置。

@startuml
skinparam backgroundColor #FEFEFE

title 自我修復系統Consul監控與自動化佈署

|開發者|
start
:提交程式碼;
:推送到 Git;

|CI 系統|
:觸發建置;
:執行單元測試;
:程式碼品質檢查;

if (測試通過?) then (是)
    :建置容器映像;
    :推送到 Registry;
else (否)
    :通知開發者;
    stop
endif

|CD 系統|
:部署到測試環境;
:執行整合測試;

if (驗證通過?) then (是)
    :部署到生產環境;
    :健康檢查;
    :完成部署;
else (否)
    :回滾變更;
endif

stop

@enduml

此圖示說明瞭從 Jenkins 建置 books-ms 到 Consul 監控服務的流程。

在服務監控方面,我們可以使用 HTTP 檢查代替指令碼檢查。Consul 將會定期傳送請求到我們的服務,並將失敗的結果傳送到 watches。

自我修復系統中的服務檢查與自動化佈署

在自我修復系統中,服務檢查與自動化佈署是確保系統高用性的關鍵環節。本文將探討如何透過Consul、Jenkins和Ansible實作服務檢查和自動化佈署。

服務檢查的定義與重要性

服務檢查是監控系統健康狀態的重要手段。與硬體檢查不同,服務檢查的定義可能因服務而異,因此將檢查定義儲存在服務程式碼倉函式庫中可以提高靈活性。這樣,服務團隊可以自由定義適合其服務的檢查專案。

使用Consul Template定義服務檢查

Consul Template是一種用於生成Consul組態檔案的範本語言。透過Consul Template,可以定義服務檢查的詳細資訊,包括檢查的ID、名稱、HTTP檢查地址、檢查間隔和超時時間等。

{
  "service": {
    "name": "books-ms",
    "tags": ["service"],
    "port": 80,
    "address": "{{key "proxy/ip"}}",
    "checks": [{
      "id": "api",
      "name": "HTTP on port 80",
      "http": "http://{{key "proxy/ip"}}/api/v1/books",
      "interval": "10s",
      "timeout": "1s"
    }]
  }
}

內容解密:

  • "service"定義了服務的基本資訊,包括名稱、標籤、埠和地址。
  • "checks"定義了對服務的檢查,包括檢查ID、名稱、HTTP檢查地址、檢查間隔和超時時間。
  • 使用Consul Template的{{key "proxy/ip"}}動態取得代理伺服器的IP地址。

Jenkinsfile中的自動化佈署流程

Jenkinsfile定義了自動化佈署的流程,包括構建、測試、佈署和更新Consul檢查組態等步驟。其中,updateChecks函式負責更新Consul的檢查組態。

node("cd") {
  def serviceName = "books-ms"
  // ...
  def flow = load "/data/scripts/workflow-util.groovy"
  // ...
  flow.updateChecks(serviceName, swarmNode)
}

內容解密:

  • node("cd")指定了執行Jenkins任務的節點。
  • load "/data/scripts/workflow-util.groovy"載入了包含自動化流程的Groovy指令碼。
  • flow.updateChecks(serviceName, swarmNode)呼叫了更新Consul檢查組態的函式。

updateChecks函式的實作

updateChecks函式負責將Consul Template檔案複製到Swarm Master節點,並執行Consul Template命令生成Consul組態。

def updateChecks(serviceName, swarmNode) {
  stage "Update checks"
  stash includes: 'consul_check.ctmpl', name: 'consul-check'
  node(swarmNode) {
    unstash 'consul-check'
    sh "sudo consul-template -consul localhost:8500 \
        -template 'consul_check.ctmpl:/data/consul/config/${serviceName}.json:killall -HUP consul' \
        -once"
  }
}

內容解密:

  • stashunstash用於在不同節點之間傳遞檔案。
  • consul-template命令根據範本生成Consul組態檔案,並在完成後傳送HUP訊號給Consul程式以使其重新載入組態。

Consul檢查觸發的自動化回應

當Consul檢測到服務失敗時,會觸發相應的Jenkins任務進行自動化回應。對於硬體故障,會觸發hardware-notification任務;對於服務故障,則會觸發service-redeploy任務。

if [[ "$CHECK_ID" == "mem" || "$CHECK_ID" == "disk" ]]; then
  curl -X POST http://{{ jenkins_ip }}:8080/job/hardware-notification/build \
       --data-urlencode json="{\"parameter\": [{\"name\":\"checkId\", \"value\":\"$CHECK_ID\"}, {\"name\":\"status\", \"value\":\"$STATUS\"}]}"
else
  curl -X POST http://{{ jenkins_ip }}:8080/job/service-redeploy/buildWithParameters?serviceName=${SERVICE_ID}
fi

內容解密:

  • 根據檢查ID的不同,決定觸發不同的Jenkins任務。
  • 使用curl命令向Jenkins傳送POST請求以觸發任務。