Categories
程式開發

Chaos Mesh開源,打造雲原生的混沌測試平台


現實世界中,各類故障可能會隨時隨地的發生,其中有很多故障我們無法避免,例如磁盤突然寫壞,或者機房突然斷網斷電等等。這些故障可能會給公司造成巨大損失,因此提升系統對於故障的容忍度成為很多工程師努力的目標。

為了更方便地驗證系統對於各種故障的容忍能力,Netflix 創造了一隻名為 Chaos 的猴子,並且將它放到 AWS 雲上,用於向基礎設施以及業務系統中註入各類故障類型。這只 “猴子” 就是混沌工程起源。

在 PingCAP 我們也面臨同樣的問題,所以在很早的時候就開始探索混沌工程,並逐漸在公司內部實踐落地。

在最初的實踐中我們為 TiDB 定制了一套自動化測試平台,在平台中我們可以自己定義測試場景,並支持模擬各類錯誤情況。但是由於 TiDB 生態的不斷成熟,各類周邊工具 TiDB Binlog、TiDB Data Migration、TiDB Lightning 等的出現,測試需求也越來越多,逐漸出現了各個組件的的測試框架。但是混沌實驗的需求是共有的,通用化的混沌工具就變的尤為重要。最終我們將混沌相關實現從自動化測試平台中抽離出來,成為了 Chaos Mesh 的最初原型,並經過重新設計和完善,最終於 GitHub 上開源,項目地址: https://github.com/pingcap/chaos-mesh

Chaos Mesh 能做些什麼?

Chaos Mesh開源,打造雲原生的混沌測試平台 1

使用 Chaos Mesh 注入 TiKV 節點宕機後發現 QPS 恢復時間異常問題

這里以使用 Chaos Mesh 模擬在 TiKV 宕機的場景下觀測業務 QPS 變化的實驗為例。 TiKV 是 TiDB 的分佈式存儲引擎。根據我們預期,大多數情況下 TiKV 節點宕機時,QPS 可能會出現瞬時的抖動,但是當 TiKV 節點恢復後 QPS 可以在很短的時候恢復到故障發生前的水位。從監控曲線上可以看出,前兩次在TiKV 節點恢復後,QPS 能夠在短時間回到正常,但在最後一次實驗中,在TiKV 節點恢復後,業務的QPS 並未在短時間內恢復到正常狀態,這和預期不符。最後經過定位確認,當前版本(V3.0.1)的 TiDB 集群在處理 TiKV 宕機的情況下,的確存在問題,並且已經在新的版本里面修復,對應的 PR: tidb/11391, tidb/11344

上面描述的場景只是我們平時混沌實驗中的一類,Chaos Mesh 還支持許多其他的錯誤注入:

  • pod-kill:模擬 Kubernetes Pod 被 kill。
  • pod-failure:模擬 Kubernetes Pod 持續不可用,可以用來模擬節點宕機不可用場景。
  • network-delay:模擬網絡延遲。
  • network-loss:模擬網絡丟包。
  • network-duplication: 模擬網絡包重複。
  • network-corrupt: 模擬網絡包損壞。
  • network-partition:模擬網絡分區。
  • I/O delay : 模擬文件系統 I/O 延遲。
  • I/O errno:模擬文件系統 I/O 錯誤 。

背後的思考

從上面的介紹我們了解到,Chaos Mesh 的目標是要做一個通用的混沌測試工具,所以最開始我們就定下了幾個原則。

易用性

  • 無特殊依賴,可以在 Kubernetes 集群上面直接部署,包括 Minikube
  • 無需修改應用的部署邏輯,理想的情況是可以在生產環境上進行混沌實驗 。
  • 易於編排實驗的錯誤注入行為,易於查看實驗的狀態和結果,並能夠快速地對注入的故障進行回滾。
  • 隱藏底層的實現細節,用戶更聚焦於編排自己需要的實驗。

拓展性

  • 基於現有實現,易於擴展新的故障注入種類。
  • 方便集成到其他測試框架中。

作為一個通用的工具,易用性是必不可少的,一個工具不管功能如何多,如何強大,如果不夠易用,那麼這個工具最終也會失去用戶,也就失去了工具的本身的價值。另一方面在保證易用的前提下,拓展性也是必不可少。如今的分佈式系統越來越複雜,各種新的問題層出不窮,Chaos Mesh 的目標的是當有新的需求的時候,我們可以方便去在 Chaos Mesh 中實現,而不是重新再造個輪子。

來點硬核的

為什麼是 Kubernetes?

在容器圈,Kubernetes 可以說是絕對的主角,其增長速度遠超大家預期,毫無爭議地贏得了容器化管理和協調的戰爭。換一句話說目前 Kubernetes 更像是雲上的操作系統。

TiDB 作為一個真Cloud-Native 分佈式開源數據庫產品,一開始我們內部的自動化測試平台就是在Kubernetes 上構建的,在Kubernetes 上每天運行著數十上百的TiDB 集群,進行著各類實驗,有功能性測試,有性能測試,更有很大一部分是各種混沌測試,模擬各種現實中可能出現的情況。為了支持這些混沌實驗,Chaos 和 Kubernetes 結合就成為了必然。

Chaos Mesh開源,打造雲原生的混沌測試平台 2

CRD 的設計

Chaos Mesh 中使用 CRD 來定義 chaos 對象,在 Kubernetes 生態中 CRD 是用來實現自定義資源的成熟方案,又有非常成熟的實現案例和工具集供我們使用,這樣我們就可以藉助於生態的力量,避免重複造輪子。並且可以更好的融合到 Kubernetes 生態中。

最初的想法是把所有的錯誤注入類型定義到統一的CRD 對像中,但在實際設計的時候發現,這樣的設計行不通,因為不同的錯誤注入類型差別太大,你沒辦法預料到後面可能會增加什麼類型的錯誤注入,很難能有一個結構去很好的覆蓋到所有場景。又或者最後這個結構變得異常複雜和龐大,很容易引入潛在的 bug。

所以在 Chaos Mesh 中 CRD 的定義可以自由發揮,根據不同的錯誤注入類型,定義單獨的 CRD 對象。如果新添加的錯誤注入符合已有的 CRD 對象定義,就可以拓展這個 CRD 對象;如果是一個完全不同的錯誤注入類型,也可以自己重新增加一個 CRD 對象。這樣的設計可以將不同的錯誤注入類型的定義以及邏輯實現從最頂層就抽離開,讓代碼結構看起來更加清晰,並且降低了耦合度,降低出錯的機率。另一方面 controller-runtime 提供了很好的 controller 實現的封裝,不用去對每一個 CRD 對象去自己實現一套 controller 的邏輯,避免了大量的重複勞動。

目前在 Chaos Mesh 中設計了三個 CRD 對象,分別是 PodChaos、NetworkChaos 以及 IOChaos,從命名上就可以很容易的區分這幾個 CRD 對象分別對應的錯誤注入類型。

以 PodChaos 為例:

spec:
 action: pod-kill
 mode: one
 selector:
   namespaces:
     - tidb-cluster-demo
   labelSelectors:
     "app.kubernetes.io/component": "tikv"
 scheduler:
   cron: "@every 2m"

PodChaos 對像用來實現注入Pod 自身相關的錯誤,action 定義了具體錯誤,比如pod-kill 定義了隨機kill pod 的行為,在Kubernetes 中Pod 宕掉是非常常見的問題,很多原生的資源對象會自動處理這種錯誤,比如重新拉起一個新的Pod,但是我們的應用真的可以很好應對這樣的錯誤嗎?又或者 Pod 拉不起來怎麼辦?

PodChaos 可以很好模擬這樣的行為,通過 selector 選項劃定想要注入混沌實驗行為的範圍,通過 scheduler 定義想要注入混沌實驗的時間頻率等。更多的細節介紹可以參考 Chaos-mesh 的使用文檔 https://github.com/pingcap/chaos-mesh

接下來我們更深入一點,聊一下 Chaos Mesh 的工作原理。

原理解析

Chaos Mesh開源,打造雲原生的混沌測試平台 3

上圖是 Chaos Mesh 的基本工作流原理圖:

  • Controller-manager

    目前 controller-manager 可以分為兩部分,一部分 controllers 用於調度和管理 CRD 對象實例,另一部分為 admission-webhooks 動態的給 Pod 注入 sidecar 容器。

  • Chaos-daemon

    Chaos-daemon 以 daemonset 的方式運行,並具有 Privileged 權限,Chaos-daemon 可以操作具體 Node 節點上網絡設備以及 Cgroup 等。

  • Sidecar

    Sidecar contianer 是一類特殊的容器,由admission-webhooks 動態的注入到目標Pod 中,目前在Chaos Mesh 中實現了chaosfs sidecar 容器,chaosfs 容器內會運行fuse-daemon,用來劫持應用容器的I/O操作。

整體工作流如下:

  1. 用戶通過 YAML 文件或是 Kubernetes 客戶端往 Kubernetes API Server 創建或更新 Chaos 對象。
  2. Chaos-mesh 通過watch API Server 中的Chaos 對象創建更新或刪除事件,維護具體Chaos 實驗的運行以及生命週期,在這個過程中controller-manager、chaos-daemon 以及sidecar 容器協同工作,共同提供錯誤注入的能力。
  3. Admission-webhooks 是用來接收准入請求的 HTTP 回調服務,當收到 Pod 創建請求,會動態修改待創建的 Pod 對象,例如注入 sidecar 容器到 Pod 中。第 3 步也可以發生在第 2 步之前,在應用創建的時候運行。

說點實際的

上面部分介紹了 Chaos Mesh 的工作原理,這一部分聊點實際的,介紹一下 Chaos Mesh 具體該如何使用。

Chaos-mesh 需要運行在 Kubernetes v1.12 及以上版本。 Chaos Mesh 的部署和管理是通過 Kubernetes 平台上的包管理工具 Helm 實現的。運行 Chaos Mesh 前請確保 Helm 已經正確安裝在 Kubernetes 集群裡。

如果沒有 Kubernetes 集群,可以通過 Chaos Mesh 提供的腳本快速在本地啟動一個多節點的 Kubernetes 集群:

// 安装 kind
curl -Lo ./kind https://github.com/kubernetes-sigs/kind/releases/download/v0.6.1/kind-$(uname)-amd64
chmod +x ./kind
mv ./kind /some-dir-in-your-PATH/kind

// 获取脚本
git clone https://github.com/pingcap/chaos-mesh
cd chaos-mesh
// 启动集群
hack/kind-cluster-build.sh

本地啟動的 Kubernetes 集群,網絡相關的錯誤注入的功能會受到影響。等 Kubernetes 集群準備好,就可以通過 HelmKubectl 安裝部署 Chaos Mesh 了。

git clone https://github.com/pingcap/chaos-mesh.git
cd chaos-mesh
// 创建 CRD 资源
kubectl apply -f manifests/
// 安装 Chaos-mesh
helm install helm/chaos-mesh --name=chaos-mesh --namespace=chaos-testing
// 检查 Chaos-mesh 状态
kubectl get pods --namespace chaos-testing -l app.kubernetes.io/instance=chaos-mesh

等 Chaos Mesh 所有組件準備就緒後,就可以盡情的玩耍​​了!

目前支持兩種方式來使用 Chaos-mesh。

定義 Chaos YAML 文件

通過 YAML 文件方式定義自己的混沌實驗,YAML 文件方式非常方便在用戶的應用已經部署好前提下,以最快的速度進行混沌實驗。

例如我們已經部署一個叫做 chaos-demo-1 的 TiDB 集群(TiDB 可以使用 TiDB Operator 來部署),如果用戶想模擬 TiKV Pod 被頻繁刪除的場景,可以編寫如下定義:

apiVersion: pingcap.com/v1alpha1
kind: PodChaos
metadata:
  name: pod-kill-chaos-demo
  namespace: chaos-testing
spec:
  action: pod-kill
  mode: one
  selector:
    namespaces:
      - chaos-demo-1
    labelSelectors:
      "app.kubernetes.io/component": "tikv"
  scheduler:
    cron: "@every 1m"

創建包含上述內容的 YAML 文件 kill-tikv.yaml 後,執行 kubectl apply -f kill-tikv.yaml , 對應的錯誤就會被注入到 chaos-demo-1 集群中。

Chaos Mesh開源,打造雲原生的混沌測試平台 4

上圖 demo 中 sysbench 程序一直在對 TiDB 集群進行測試,當將錯誤注入到集群後,sysbench QPS 出現明顯抖動,觀察 Pod 發現,某一個 TiKV Pod 已經被刪除,並且 Kubernetes 為了 TiDB 集群重新創建了一個新的 TiKV Pod。

更多的 YAML 文件示例參考:https://github.com/pingcap/chaos-mesh/tree/master/examples

使用 Kubernetes API

Chaos Mesh 使用 CRD 來定義 chaos 對象,因此我們可以直接通過 Kubernetes API 操作我們的 CRD 對象。通過這種方式,可以非常方便將我們的 Chaos Mesh 應用到我們自己的程序中,去定制各類測試場景,讓混沌實驗自動化並持續運行。

例如在 test-infra 項目中我們使用 Chaos Mesh 來模擬 ETCD 集群在 Kubernetes 環境中可能出現的異常情況,比如模擬節點重啟、模擬網絡故障、模擬文件系統故障等等。

Kubernetes API 使用示例:

import (
        "context"

        "github.com/pingcap/chaos-mesh/api/v1alpha1"
        "sigs.k8s.io/controller-runtime/pkg/client"
)

func main() {
    ...
    delay := &chaosv1alpha1.NetworkChaos{
               Spec: chaosv1alpha1.NetworkChaosSpec{...},
       }
       k8sClient := client.New(conf, client.Options{ Scheme: scheme.Scheme })
    k8sClient.Create(context.TODO(), delay)
       k8sClient.Delete(context.TODO(), delay)
}

聊聊未來

說了這麼多,最後也是最重要的,Chaos Mesh 項目才剛剛開始,開源只是一個起點,需要大家共同參與,一起讓我們的應用與混沌在 Kubernetes 上共舞吧!

大家在使用過程發現 bug 或缺失什麼功能,都可以直接在 GitHub 上面提 issue 或 PR,一起參與討論。

Github 地址: https://github.com/pingcap/chaos-mesh

本文轉載自公眾號PingCAP(ID:pingcap2015)。

原文鏈接

https://mp.weixin.qq.com/s/LkxKJmpqOdEsOuHNxeR0KA