突破混沌工程的限制:隨機破壞與系統監控

在本章中,我們將探索如何提升混沌工程實驗的破壞性、隨機性和不可預測性,超越單一應用程式的範疇,進而影響整個名稱空間,甚至叢集層級的資源。我們將發現,傳統混沌工具包中定義的探針和穩態假設可能不足以應付如此大規模的實驗。當我們嘗試對比單一應用程式更大範圍的狀態進行觀察時,如何才能確定我們期望觀察到的狀態是什麼?

為了在更大規模的系統中取得成功,我們需要引入額外的工具,並重新評估我們觀察系統狀態的方式,以及在執行完全隨機的破壞性操作後,如何獲得叢集中出現錯誤的通知。

建立叢集和佈署應用程式

進行實驗之前,我們需要一個 Kubernetes 叢集和一個佈署的應用程式。以下 Gist 提供了幾種建立叢集的選項,您可以根據自己的環境選擇:

佈署應用程式的步驟如下:

  1. 進入 go-demo-8 目錄並更新程式碼:

    cd go-demo-8
    git pull
    
  2. 建立名稱空間 go-demo-8 並設定 Istio 自動注入 sidecar:

    kubectl create namespace go-demo-8
    kubectl label namespace go-demo-8 istio-injection=enabled
    
  3. 佈署應用程式:

    kubectl --namespace go-demo-8 apply --filename k8s/app-full
    kubectl --namespace go-demo-8 rollout status deployment go-demo-8
    
  4. 驗證應用程式:

    curl -H "Host: repeater.acme.com" "http://$INGRESS_HOST?addr=http://go-demo-8"
    

佈署監控和視覺化工具

為了應對隨機破壞帶來的挑戰,我們需要一個強大的監控和告警系統。這裡我們將使用 Prometheus、Grafana 和 Kiali。

首先,我們需要產生一些流量來生成監控指標。在第二個終端視窗中,設定 INGRESS_HOST 環境變數,並執行以下迴圈命令:

export INGRESS_HOST=[...] # 替換為你的 Ingress Host
while true; do
  curl -i -H "Host: repeater.acme.com" "http://$INGRESS_HOST?addr=http://go-demo-8/demo/person"
  sleep 1
done

這個迴圈會不斷傳送請求到 demo 應用程式,產生流量和指標。

回到第一個終端視窗,我們將安裝 Grafana 和 Kiali:

istioctl manifest install \
  --set values.grafana.enabled=true \
  --set values.kiali.enabled=true \
  --skip-confirmation

檢查 Grafana 的 rollout 狀態,確保其正常執行。

內容解密: 以上步驟完成了叢集建立、應用程式佈署和監控工具的安裝。接下來,我們就可以開始進行混沌實驗,並透過 Grafana 和 Kiali 觀察系統的狀態變化。

(Mermaid 圖表)

  graph LR
    C[C]
    F[F]
    A[建立叢集] --> B(佈署應用程式);
    B --> C{驗證應用程式};
    C -- 成功 --> D[產生流量];
    D --> E[安裝監控工具];
    E --> F{驗證監控工具};

思考過程: 在設計大規模混沌實驗時,我發現僅僅依靠預先定義的穩態假設是不夠的。因為隨機破壞的影響範圍更廣,難以預測所有可能的結果。因此,一個全面的監控系統至關重要,它能幫助我們捕捉系統的異常狀態,並提供更豐富的資料來分析實驗結果。

**** 隨著雲原生應用的普及,混沌工程將扮演越來越重要的角色。未來的混沌工程工具需要更加智慧化,能夠自動分析系統狀態、識別潛在風險,並提供更精確的實驗結果。

洞悉服務網格:Grafana 與 Kiali 的監控實戰

在現代微服務架構中,服務網格的監控至關重要。本文將帶您深入瞭解如何利用 Grafana 和 Kiali 這兩大利器,有效監控服務網格的執行狀況,並結合 chaos 實驗,將監控提升到一個新的層次。

Grafana:全方位指標視覺化

Grafana 作為一個通用的儀錶板解決方案,能與多種指標來源協同工作,提供豐富的視覺化功能。在我們的案例中,我們將使用 Prometheus 作為指標來源,但 Grafana 也能支援其他來源,例如 Elasticsearch。

透過 istioctl dashboard grafana 命令,我們可以建立一個臨時通道來存取 Grafana UI。在 Istio Mesh Dashboard 中,我們可以概覽服務的關鍵指標,例如全域請求量、請求速率以及錯誤率。

istioctl dashboard grafana

內容解密: istioctl dashboard grafana 命令會建立一個從本地機器到 Kubernetes 叢集中 Grafana 服務的通道,方便使用者在本地瀏覽器中存取 Grafana 儀錶板。

下圖展示了 Grafana 儀錶板的基本結構:

  graph LR
    E[E]
    A[Global Request Volume] --> B(Overall Health)
    C[Global Request Rate] --> B
    D[Error Rate] --> B
    B --> E{Service Details}
    E --> F[go-demo-8]
    E --> G[repeater]

內容解密: 此流程圖展示了 Grafana Istio Mesh Dashboard 的資訊層級,從全域指標到個別服務的詳細資訊。

如果應用程式出現錯誤,我們可以在儀錶板上看到 4xx 和 5xx 錯誤的相關資料。此外,儀錶板還提供了服務的延遲和成功率等資訊,幫助我們快速診斷網路問題。

Kiali:服務網格流量拓撲圖

Kiali 專注於服務網格的流量視覺化,能清晰地展現服務間的通訊關係。透過 istioctl dashboard kiali 命令,我們可以存取 Kiali 儀錶板。

istioctl dashboard kiali

內容解密: 與 Grafana 類別似,istioctl dashboard kiali 命令也建立一個到 Kiali 服務的通道。Kiali 預設需要驗證,因此需要事先建立 Kubernetes Secret。

在 Kiali 儀錶板中,我們可以選擇特定的名稱空間,檢視其中所有應用程式的流量走向。這對於理解服務間的呼叫關係以及排查通訊問題非常有幫助。

  graph LR
    A[Gateway] --> B(repeater)
    B --> C[go-demo-8]
    C --> D((go-demo-8-db))

內容解密: 此圖展示了 Kiali 如何視覺化服務間的流量走向,清晰地呈現了服務呼叫關係。

Chaos 實驗與監控整合

結合 Grafana 和 Kiali,我們可以更有效地進行 chaos 實驗。例如,我們可以模擬服務中斷,然後觀察 Grafana 儀錶板上的錯誤率變化,以及 Kiali 儀錶板上的流量拓撲變化,從而驗證系統的容錯能力。

從儀錶板到告警

雖然儀錶板提供了豐富的資訊,但持續盯著螢幕並非長久之計。我們的最終目標是建立告警機制,以便在系統出現異常時及時收到通知。Prometheus 的 Alertmanager 是一個理想的選擇,它能與 Prometheus 無縫整合,提供靈活的告警規則組態。

透過觀察 Grafana 和 Kiali 儀錶板上的模式,我們可以定義告警規則,例如當錯誤率超過一定閾值時觸發告警。這樣,我們就能從被動監控轉為主動告警,更有效地保障系統的穩定性。

透過本文的介紹,我們瞭解瞭如何利用 Grafana 和 Kiali 監控服務網格,並結合 chaos 實驗,將監控提升到一個新的層次。最終,我們應該建立告警機制,以便在系統出現問題時及時採取行動,確保系統的可靠性。

隨機終止 Pod 的混沌工程實踐

在微服務架構中,確保系統的容錯性至關重要。混沌工程提供了一種有效的方法來驗證系統在面對意外故障時的彈性。本文將探討如何利用 Chaos Toolkit 在 Kubernetes 環境中隨機終止 Pod,並觀察系統的反應。

混沌實驗設計

我們的目標是模擬生產環境中 Pod 隨機失效的場景。實驗設計如下:

  1. 假設: 即使隨機終止一個 Pod,系統的整體服務不應受到顯著影響。所有應用程式應保持健康狀態。
  2. 方法: 在 go-demo-8 名稱空間中隨機選擇一個 Pod 並終止。
  3. 探針: 定期檢查 go-demo-8 名稱空間中所有應用程式的健康狀態。
  4. 觀察指標: 應用程式可用性、錯誤率、延遲。

實驗步驟

1. 建立混沌實驗名稱空間

為了避免實驗本身受到幹擾,我們將在一個專用的名稱空間 chaos 中執行混沌實驗。

kubectl create namespace chaos

2. 定義混沌實驗

我們使用 ConfigMap 定義混沌實驗的組態。

apiVersion: v1
kind: ConfigMap
metadata:
  name: chaostoolkit-experiments
data:
  health-instances.yaml: |
    version: 1.0.0
    title: 隨機 Pod 終止實驗
    description: 驗證系統在 Pod 隨機終止時的容錯性
    tags:
      - k8s
      - pod
      - resilience
    steady-state-hypothesis:
      title: 所有應用程式保持健康
      probes:
        - name: 應用程式健康狀態檢查
          type: probe
          tolerance: true
          provider:
            type: python
            func: all_microservices_healthy
            module: chaosk8s.probes
            arguments:
              ns: go-demo-8
    method:
      - type: action
        name: 終止 Pod
        provider:
          type: python
          module: chaosk8s.pod.actions
          func: terminate_pods
          arguments:
            rand: true
            ns: go-demo-8
    pauses:
      after: 10

內容解密:

這個 ConfigMap 定義了一個名為 health-instances.yaml 的混沌實驗。實驗的假設是所有應用程式保持健康。實驗方法是隨機終止 go-demo-8 名稱空間中的一個 Pod。實驗會在執行動作後暫停 10 分鐘,以便觀察系統的反應。

3. 應用 ConfigMap

kubectl --namespace chaos apply --filename k8s/chaos/experiments-any-pod.yaml

4. 定義 ServiceAccount

由於實驗需要操作其他名稱空間中的資源,我們需要建立一個具有足夠許可權的 ServiceAccount。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: chaostoolkit

---

apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: chaostoolkit
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: chaostoolkit
    namespace: chaos

內容解密:

這裡我們使用 ClusterRoleBinding 將 ServiceAccount 繫結到 cluster-admin ClusterRole,賦予其叢集範圍的管理許可權。

5. 應用 ServiceAccount

kubectl --namespace chaos apply --filename k8s/chaos/sa-cluster.yaml

6. 定義 CronJob

我們使用 CronJob 定期執行混沌實驗。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: health-instances-chaos
spec:
  # ... (其他組態與前一章節相同)
  schedule: "*/2 * * * *" # 每兩分鐘執行一次
  # ... (其他組態與前一章節相同)

內容解密:

這個 CronJob 每兩分鐘執行一次混沌實驗 health-instances.yaml

7. 應用 CronJob

kubectl --namespace chaos apply --filename k8s/chaos/periodic-fast.yaml

8. 觀察結果

kubectl --namespace chaos get cronjobs

觀察 CronJob 的執行狀態和 Pod 的變化。

Mermaid 圖表 - 系統架構

  graph LR
    subgraph[subgraph]
    subgraph chaos 名稱空間
        CronJob["health-instances-chaos"] --> ChaosToolkit["chaostoolkit Pod"]
    end
    ChaosToolkit --> Kubernetes["Kubernetes API Server"]
    Kubernetes --> subgraph go-demo-8 名稱空間
        A["應用程式 Pod 1"]
        B["應用程式 Pod 2"]
        C["應用程式 Pod 3"]
    end

圖表說明: Chaos Toolkit Pod 在 chaos 名稱空間中執行,透過 Kubernetes API Server 與 go-demo-8 名稱空間中的應用程式 Pod 互動,執行混沌實驗。

本文演示瞭如何使用 Chaos Toolkit 在 Kubernetes 中進行 Pod 隨機終止實驗。透過觀察系統在實驗中的表現,我們可以識別系統的薄弱環節,並採取相應的措施提高系統的容錯性和彈性。

混沌工程實踐:從意外發現系統弱點

在之前的實驗中,我們透過模擬各種故障場景,例如服務中斷和網路延遲,驗證了系統的彈性。這次,我們將採用隨機混沌注入的方式,觀察系統在不可預測的幹擾下的表現。

我使用了一個簡單的 Kubernetes CronJob,每兩分鐘執行一次混沌實驗。這個實驗會隨機終止 go-demo-8 名稱空間中的一個 Pod。

apiVersion: batch/v1
kind: CronJob
metadata:
  name: health-instances-chaos
spec:
  schedule: "*/2 * * * *" # 每兩分鐘執行一次
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: chaos-experiment
            image: chaos-toolkit/pod-killer
            args:
            - --namespace
            - go-demo-8
            - --labels
            - "app!=go-demo-8-db" # 排除資料函式庫 Pod
          restartPolicy: Never

這個 CronJob 使用 chaos-toolkit/pod-killer 映像檔,並設定 --labels 引數,避免終止資料函式庫 Pod,因為資料函式庫目前沒有備援機制。

起初,系統一切正常。Grafana 儀錶板顯示所有指標都在正常範圍內,服務成功率 100%。然而,經過一段時間後,我觀察到 Grafana 儀錶板上的 5xx 錯誤數量開始增加,repeatergo-demo-8 服務的成功率也下降了。

圖 1: Grafana 儀錶板顯示服務成功率下降

Kiali 儀錶板也顯示了類別似的問題:流量被阻塞,repeater 無法連線到 go-demo-8,而 go-demo-8 也無法連線到資料函式庫。

圖 2: Kiali 儀錶板顯示流量阻塞

檢查 Pod 狀態後,我發現所有 Pod 都在執行,包括幾分鐘前重新建立的資料函式庫 Pod。這讓我開始懷疑問題的根源並非 Pod 本身,而是應用程式本身的設計缺陷。

我推測,go-demo-8 在啟動時會連線到資料函式庫,但當資料函式庫連線中斷後,應用程式碼缺乏重新建立連線的邏輯。這導致即使資料函式庫 Pod 重新啟動,go-demo-8 也無法還原正常運作。

內容解密:

這段程式碼模擬了 go-demo-8 與資料函式庫的連線邏輯。如果連線失敗,應用程式會記錄錯誤,但不會嘗試重新連線。

package main

import (
	"database/sql"
	"log"
	// ... other imports
)

func main() {
	db, err := sql.Open("mysql", "user:password@tcp(db-service:3306)/dbname")
	if err != nil {
		log.Fatal("Failed to connect to database:", err)
	}
	// ... other code
}

這個問題的發現突顯了混沌工程的重要性。透過隨機注入故障,我們可以發現系統中潛藏的弱點,這些弱點在常規測試中可能難以察覺。

這個案例也提醒我們,應用程式碼的健壯性至關重要。在設計應用程式時,必須考慮各種可能的故障場景,並加入相應的錯誤處理和還原機制,以確保系統的穩定性和可靠性。 在之前的章節中,我們已經證明,當資料函式庫終止時,由於它沒有被複製,會產生短暫的停機時間。新的發現是應用程式本身(go-demo-8)的程式碼不知道如何重新建立連線。因此,即使我們讓資料函式庫容錯,即使 Kubernetes 重新建立失敗的資料函式庫副本,損壞也是永久性的,因為程式碼有缺陷。我們需要重新設計應用程式,以確保當與資料函式庫的連線斷開時,應用程式本身會嘗試重新建立連線。

更好的是,我們可以讓應用程式在與資料函式庫的連線斷開時失敗。這將導致執行它的容器終止,而 Kubernetes 將重新建立它。這個過程可能會重複幾次,但是一旦資料函式庫重新啟動並執行,容器的重新啟動將導致應用程式重新啟動,並能夠重新建立連線。或者,我們也可以選擇第三種解決方案。

我們也可以更改健康檢查。目前,該地址並未指向使用資料函式庫的端點。因此,健康檢查似乎工作正常,Kubernetes 沒有理由終止 go-demo-8 的容器。

無論我們採用哪種解決方案,需要注意的重要一點是,我們在系統中發現了另一個弱點。知道可能出錯的地方是最重要的。解決問題通常不是問題,只要我們知道問題是什麼。

我們不需要繼續終止隨機 Pod,因為現在我們知道有一個問題需要解決。因此,我們將刪除 CronJob。

kubectl --namespace chaos delete \
--filename k8s/chaos/periodic-fast.yaml

我把它留給你來思考你會採用哪種建議的解決方案(如果有的話)。把它當作另一個家庭作業。現在,我們將重新啟動 go-demo-8。這應該會重新建立與資料函式庫的連線並修復問題。更準確地說,這不會解決問題,而是作為一種解決方法,讓我們可以轉到下一個主題。「真正的」修復是我已經分配給你的任務。

kubectl --namespace go-demo-8 \
rollout restart deployment go-demo-8

中斷網路流量

我們一直在終止隨機的 Pod,無論它們屬於哪個應用程式。我們可以對網路做類別似的事情嗎?或者更準確地說,我們可以中斷隨機的網路或隨機的 Istio VirtualService 嗎?是的,我們可以,但不是使用 Chaos Toolkit 中的現成解決方案。在撰寫本文時(2020 年 4 月),Istio 外掛不允許我們對隨機 VirtualService 進行操作。因此,我們不能說中斷隨機網路。如果我們想這樣做,我們需要建立自己的實作,這應該相對簡單。我們可以編寫一個指令碼,例如,擷取所有 VirtualServices,選擇一個隨機的,然後中斷它。編寫這樣的指令碼應該不是什麼大問題。或者,更好的是,我們應該透過在 Chaos Toolkit Extension for Istio Fault Injection⁸⁵ 中實作這樣的功能來為專案做出貢獻。

如您所知,我會不時地給您一些任務讓您自己完成,而與我保證它們不會很簡單。

您的下一個任務是中斷隨機的 Istio VirtualService。您可以透過編寫一個指令碼來完成此操作,該指令碼首先列出名稱空間中的所有 VirtualServices,然後選擇一個隨機的,最後以某種方式中斷它。探索如何修改 Istio VirtualService 並對其進行一些惡意操作。如果您選擇接受挑戰,一旦完成,請嘗試在 Istio 外掛中實作相同的操作。發出 pull request 並回饋給社群。

如果您對 Istio VirtualServices 不是很有信心,您可能需要檢視 Udemy 上的課程 Canary Deployments To Kubernetes Using Istio and Friends⁸⁶。該課程沒有直接討論 Istio,但它確實更詳細地展示了我們現在正在嘗試做的事情。

無論如何,現在您有一個任務。建立一個指令碼或為外掛程式做出貢獻。在混沌實驗中使用它。完成後再回來,我們將探索更多內容。

準備終止節點

現在我們知道如何影響不僅僅是單個應用程式,還有在名稱空間中執行的隨機應用程式,甚至是整個叢集。接下來,我們將探討如何在節點級別上隨機化我們的實驗。

過去,我們會終止或中斷執行特定應用程式的節點。我們接下來要做的是嘗試找出如何銷毀一個完全隨機的節點。它將不帶有任何特定標準。我們只是做一些隨機的事情,看看這會如何影響我們的叢集。如果我們幸運的話,這樣的操作不會導致任何不良結果。或者也許會。我們很快就會發現。

我們現在可以這樣做,而以前不能這樣做的原因是,我們實驗的穩態假設還不夠。如果我們銷毀一些(幾乎)完全隨機的東西,那麼系統的任何部分都可能受到影響。我們不能使用 Chaos Toolkit 假設來預測初始狀態應該是什麼,也不能預測在一些具有破壞性的叢集範圍操作之後的狀態應該是什麼。更準確地說,我們可以這樣做,但這太複雜了,而與我們會試圖用錯誤的工具來解決問題。

現在我們知道可以使用 Prometheus 來儲存指標,並且可以透過 Grafana 和 Kiali 等儀錶板來監控我們的系統。我們可以,也應該更進一步,例如,建立警示,在系統的任何部分行為異常時通知我們。

現在我們準備好全力以赴,在叢集級別上執行我們的實驗。

讓我們看一下另一個 YAML 定義。

cat k8s/chaos/experiments-node.yaml

該定義不應該包含任何真正新的東西。儘管如此,還是有一些細節值得解釋。為了更簡單,我們將看一下它與先前定義的差異。這將幫助我們找出兩者之間的差異。

diff k8s/chaos/experiments-any-pod.yaml \
k8s/chaos/experiments-node.yaml

輸出如下:

40c40,68
---
+++
node.yaml: |
version: 1.0.0
title: "What happens if we drain a node"
description: All the instances are distributed among healthy nodes and the applications are healthy
tags:
- k8s
- node
method:
- type: action
name: drain-node
provider:
type: python
func: drain_nodes
module: chaosk8s.node.actions
arguments:
label_selector: beta.kubernetes.io/os=linux
count: 1
delete_pods_with_local_storage: true
pauses:
after: 180
rollbacks:
- type: action
name: uncordon-node
provider:
type: python
func: uncordon_node
module: chaosk8s.node.actions
arguments:
label_selector: beta.kubernetes.io/os=linux

我們可以看到,我們有一個全新的實驗叫做 node.yaml,其中包含標題、描述和我們通常在實驗中擁有的所有其他內容。它沒有任何穩態假設,因為我們真的不知道整個叢集的狀態應該是什麼。所以我們跳過了穩態,但我們使用了該方法。它將移除具有特定標籤選擇器的一個節點。

我們將 label_selector 設定為 beta.kubernetes.io/os=linux 的唯一原因是避免耗盡 Windows 節點(如果有的話)。我們在叢集中沒有它們(如果您使用了我提供的 Gist)。不過,由於您並非強制使用這些 Gist 來建立叢集,因此我無法確定您沒有將其與 Windows 伺服器混合使用。我們的重點僅限於 Linux。

為了安全起見,請描述您的其中一個節點,並確認該標籤確實存在。

視覺化節點移除流程

  graph LR
    A[選擇節點:beta.kubernetes.io/os=linux] --> B{確認節點狀態};
    B -- 正常 --> C[移除節點];
    B -- 異常 --> D[終止實驗];
    C --> E[Pod 重新排程];
    E --> F[服務還原];

圖表說明: 此流程圖展示了 experiments-node.yaml 實驗中移除節點的步驟。首先,根據標籤選擇器選擇一個節點。然後,確認節點狀態是否正常。如果正常,則移除節點,Kubernetes 會將 Pod 重新排程到其他健康節點,最終服務還原。如果節點狀態異常,則終止實驗。

程式碼解密:experiments-node.yaml

apiVersion: chaos-mesh.org/v1alpha1
kind: Workflow
metadata:
  name: node-chaos
  namespace: chaos-testing  # 使用 chaos-testing 名稱空間
spec:
  entry: drain-node
  templates:
  - name: drain-node
    type: PodChaos
    spec:
      mode: one
      selector:
        namespaces:
        - go-demo-8 # 指定名稱空間
      scheduler:
        cron: "@every 1m" # 每分鐘執行一次
      action: drain # 執行 drain 操作
      duration: "30s" # 持續 30 秒
      value: ""

內容解密: 這段 YAML 定義了一個 Chaos Mesh 工作流程,用於模擬節點故障。它使用 PodChaosgo-demo-8 名稱空間中每分鐘隨機選擇一個 Pod 並執行 drain 操作,持續 30 秒。 drain 操作會將節點上的 Pod 驅逐到其他節點,模擬節點不可用的情況。mode: one 表示每次只會影響一個 Pod。 這個設定可以幫助我們觀察應用程式在節點故障時的還原能力。

玄貓的思考:關於節點移除實驗的改進

這個實驗設計簡單直接,但可以進一步改進。例如,可以加入穩態檢查,確保應用程式在節點移除後仍然能夠正常服務。此外,可以調整 duration 引數來控制節點移除的時間,模擬不同程度的故障。更進一步,可以結合 Prometheus 和 Grafana 等監控工具,收集和視覺化實驗過程中的指標,以便更深入地分析系統的行為。 探討 Kubernetes 混沌工程實驗:節點排空策略與監控告警機制

在 Kubernetes 環境中進行混沌工程實驗時,節點排空是一項重要的測試手段。本文將探討如何安全地排空節點,觀察系統反應,並建立完善的監控告警機制。

設計節點排空實驗

設計實驗時,我們設定 delete_pods_with_local_storagetrue,確保使用本地儲存的 Pod 在節點排空前被刪除。由於 Kubernetes 不允許直接排空包含本地儲存的節點,這個設定至關重要。實驗流程如下:隨機選擇一個 Linux 節點進行排空,等待 180 秒後,解除節點的 cordon 狀態,使其還原正常。

需要注意的是,此實驗不適用於 Docker Desktop 或 Minikube,因為它們只有一個節點。排空單一節點會導致整個叢集,包括控制平面,都被排空。

以下 YAML 檔案定義了節點混沌實驗:

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: nodes-chaos
spec:
  concurrencyPolicy: Forbid
  schedule: "*/5 * * * *"
  jobTemplate:
    ...
    spec:
      activeDeadlineSeconds: 600
      backoffLimit: 0
      template:
        metadata:
          labels:
            app: health-instances-chaos
          annotations:
            sidecar.istio.io/inject: "false"
        spec:
          serviceAccountName: chaostoolkit
          restartPolicy: Never
          containers:
          - name: chaostoolkit
            image: vfarcic/chaostoolkit:1.4.1
            args:
            - --verbose
            - run
            - --journal-path
            - /results/node.json
            - /experiment/node.yaml
            env:
            - name: CHAOSTOOLKIT_IN_POD
              value: "true"
            volumeMounts:
            - name: experiments
              mountPath: /experiment
              readOnly: true
            - name: results
              mountPath: /results
              readOnly: false
            resources:
              limits:
                cpu: 20m
                memory: 64Mi
              requests:
                cpu: 20m
                memory: 64Mi
          volumes:
          - name: experiments
            configMap:
              name: chaostoolkit-experiments
          - name: results
            persistentVolumeClaim:
              claimName: chaos

---

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: chaos
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

內容解密:

這個 CronJob 定義與之前的類別似,主要區別在於排程和實驗檔案。排程設定為每五分鐘執行一次,因為節點排空和還原需要時間。實驗檔案使用了 node.yaml,其中定義了具體的混沌實驗引數。

執行與觀察

應用上述定義後,持續傳送請求以觀察 demo 應用程式的反應。透過 kubectl get cronjobskubectl get jobskubectl get pods 命令,可以監控 CronJob、Job 和 Pod 的狀態。

觀察 Grafana 和 Kiali 的監控指標,確認系統在節點排空期間的網路連通性和應用程式狀態。儘管節點被隨機排空,但由於系統的健壯性和容錯機制,應用程式和網路層面通常不會出現嚴重問題。

然而,單節點資料函式庫仍然是系統的潛在弱點。如果實驗期間資料函式庫所在節點被排空,可能會導致應用程式故障。

監控與告警

混沌工程實驗需要完善的監控和告警機制。Prometheus 可以收集指標,Grafana 提供視覺化儀錶板,但更重要的是建立主動的告警系統。將儀錶板的觀察結果轉化為告警規則,可以及時發現問題,無需持續監控螢幕。

後續文章將探討如何使用 Prometheus 和 Alertmanager 建立告警規則,以及如何根據實驗結果調整告警策略,持續提升系統的可靠性。

  graph LR
    B[B]
    C[C]
    A[定義 CronJob] --> B{執行實驗};
    B --> C{觀察系統狀態};
    C --> D[分析監控指標];
    D --> E[建立告警規則];

內容解密:

此流程圖展示了節點排空實驗的執行流程,從定義 CronJob 開始,到執行實驗、觀察系統狀態、分析監控指標,最後建立告警規則。

  graph LR
    subgraph 節點
        A[Node 1]
        B[Node 2]
        C[Node 3]
        D[Node 4]
    end
    A --> E[排空]
    E --> F[還原]

內容解密:

此圖表簡化了節點排空和還原的過程。一個節點被選中並排空,然後再還原到正常狀態。這突出了實驗的核心操作。 在混沌工程的實踐中,監控扮演著至關重要的角色。雖然本章的重點並非監控,但穩固的監控和警示機制是成功進行混沌實驗的根本。我個人偏好使用 AlertManager,但 DataDog 或其他符合需求的工具也同樣適用。如果您對監控議題感興趣,可以參考《The DevOps 2.5 Toolkit: Monitoring, Logging, and Auto-Scaling Kubernetes》一書,它能提供更深入的探討。

在本章節中,我們將拆解先前建立的實驗環境。首先,停止向 demo 應用程式傳送請求,然後刪除 go-demo-8chaos 兩個名稱空間。最後,您可以根據 Gist 中的指示刪除整個叢集。

本章至此告一段落,我希望透過一系列的練習和作業,您已經對混沌工程有了更深入的理解,並掌握了其優缺點、潛在陷阱以及實務應用。我們完成了設定的目標:終止應用程式例項、模擬網路中斷和延遲、模擬 DoS 攻擊、排出和刪除節點、產生報告和傳送通知,以及在 Kubernetes 叢集中執行實驗。

我們不僅終止了應用程式例項,還終止了其相依服務,甚至設計了隨機終止應用程式例項的實驗。透過 Istio VirtualServices,我們模擬了網路中斷,並藉此找出並修復了應用程式中的一些網路相關問題。此外,我們還利用 Istio 模擬了延遲和 DoS 攻擊,並調整了應用程式以應對這些情況。

我們也探討了節點的排出和刪除操作,並從中汲取了寶貴的經驗,用於改進叢集和應用程式的穩定性。在掌握了 demo 應用程式的實驗後,我們將實驗範圍擴充套件到名稱空間和叢集層級。我們還學習瞭如何產生報告和傳送 Slack 通知,您可以將這些知識應用到其他通知系統。

在 Kubernetes 中,我們定義了用於一次性實驗的 Jobs,並將其整合到持續交付流程中。此外,我們還學習瞭如何建立 CronJobs 以定期執行實驗。

本章並未涵蓋 Kubernetes 以外的環境,因為不同基礎設施供應商(如 AWS、GCP、Azure、VMware 等)之間存在巨大差異,每個供應商都值得專門撰寫一本章。不過,Chaos Toolkit 提供了針對特定基礎設施的外掛,您也可以透過執行自定義指令碼或指令來擴充套件外掛功能,甚至可以貢獻新的外掛。

重要的是,本章中的示例並非一成不變的範本。您應該根據自身需求調整實驗設計,因為每個系統都是獨特的。請務必從小規模實驗開始,逐步建立信心,然後再擴大範圍。不要一開始就使用 CronJobs,先以一次性執行方式驗證實驗的有效性。

混沌實驗的目標並非娛樂,而是幫助我們學習和改進系統。因此,您需要與團隊分享實驗結果,讓整個組織都能受益。

感謝您的閱讀,希望本章對您有所幫助。如果您有任何問題,歡迎透過 Slack、Twitter、電子郵件或其他方式與我聯絡。

流程圖如下:

  graph LR
    C[C]
A[規劃實驗] --> B(執行實驗);
B --> C{觀察結果};
C -- 發現問題 --> D[調整系統];
C -- 未發現問題 --> E[擴大實驗範圍];
D --> A;
E --> A;

狀態圖如下:

  stateDiagram
    [*] --> 規劃
    規劃 --> 執行 : 開始實驗
    執行 --> 觀察 : 完成實驗
    觀察 --> 調整 : 發現問題
    觀察 --> 規劃 : 未發現問題
    調整 --> 規劃 : 系統調整完成