Kubernetes e2e test and test framework


前言

Kubernetes的成功少不了大量工程師的共同參與,而他們之間如何高效的協作,非常值得我們探究。最近研究和使用了他們的e2e測試和框架,還是挺有啟發的。

怎樣才是好的e2e測試?

不同的人寫出的測試用例千差萬別,尤其在用例,可能由開發人員編寫的情形下,其情形可想而知。要知道,絕大多數開發人員,可能並沒有經歷過大量測試用例場景的熏陶。所以如何持續輸出高質量的e2e測試用例,確實是一個挑戰。不過,Kubernetes社區非常聰明,他們抽象出來了一些共性的東西,來希望大家遵守。比如說

  1. 拒絕“flaky”測試 - 也就是那些偶爾會失敗,但是又非常難定位的問題。
  2. 錯誤輸出要詳細,尤其是做斷言時,相關信息要有。不過也不要打印太多無效信息,尤其是在case並未失敗的情況。
  3. make case run in anywhere。這一點很重要,因為你的case是提交到社區,可能在各種環境下,各種時間段內運行。面對着各種cloud provider,各種系統負載情況。所以你的case要盡可能穩定,比如APICall,能異步的,就不要假設是同步; 比如多用retry機制等。
  4. 測試用例要執行的足夠快。超過兩分鍾,就需要給這種測試打上[SLOW]標簽。而有這種標簽的測試用例,可以運行的場景就比較有限制了。誰又不希望自己寫的用例都被盡可能的執行呢?很有激勵性的一條規則。

另外,社區不過定下規則,還開發和維護了一系列的基礎設施,來輔助上面規則的落地。我們接下來要講的e2e框架就是其中之一。

e2e 驗收測試

搞過測試的應該都知道,在面對復雜系統測試時,我們通常有多套測試環境,但是測試代碼通常只有一份。所以為了能更好的區分測試用例,通常采取打標簽的方式來給用例分類。這在Kubernetes的e2e里,這也不例外。

Kubernetes默認將測試用例分為下面幾類,需要開發者在實際開發用例時,合適的使用。

  • 沒標簽的,默認測試用例是穩定的,支持並發,且運行足夠快的
  • [Slow] 執行比較慢的用例.(對於具體的時間閾值,Kubernetes不同的文檔表示不一致,此處需要修復)
  • [Serial] 不支持並發的測試用例,比如占用太多資源,還比如需要重啟Node的
  • [Disruptive] 會導致其他測試用例失敗或者具有破壞性的測試用例
  • [Flaky] 不穩定的用例,且很難修復。使用它要非常慎重,因為常規CI jobs並不會運行這些測試用例
  • [Feature:.+] 圍繞特定非默認Kubernetes集群功能或者非核心功能的測試用例,方便開發以及專項功能適配

當然除了以上標簽,還有個比較重要的標簽就是[Conformance], 此標簽用於驗收Kubernetes集群最小功能集,也就是我們常說的MAT測試。所以如果你有個私有部署的k8s集群,就可以通過這套用例來搞驗收。方法也很簡單,通過下面幾步就可以執行:

# under kubernetes folder, compile test cases and ginkgo tool
make WHAT=test/e2e/e2e.test && make ginkgo

# setup for conformance tests
export KUBECONFIG=/path/to/kubeconfig
export KUBERNETES_CONFORMANCE_TEST=y
export KUBERNETES_PROVIDER=skeleton

# run all conformance tests
go run hack/e2e.go -v --test --test_args="--ginkgo.focus=\[Conformance\]"

注意,kubernetes的測試使用的鏡像都放在GCR上了,如果你的集群在國內,且還不帶翻牆功能,那可能會發現pod會因為下載不了鏡像而啟動失敗。

Kubernetes e2e test framework

研究Kubernetes的e2e測試框架,然后類比我們以往的經驗,個人覺得,下面幾點特性還是值得借鑒的:

All e2e compiled into one binary, 單一獨立二進制

在對服務端程序進行API測試時,我們經常會針對每個服務都創建一個ginkgo suite來框定測試用例的范圍,這樣做的好處是用例目標非常清晰,但是隨着服務數量的增多,這樣的suite會越來越來多。從組織上,看起來就稍顯雜亂,而且不利於測試服務的輸出。

比如,我們考慮這么一個場景,QA需要對新機房部署,或者私有機房進行服務驗證。這時候,就通常需要copy所有代碼到指定集群在運行了,非常的不方便,而且也容易造成代碼泄露。

kubernetes顯然也會有這個需求,所以他們改變寫法,將所有的測試用例都編譯進一個e2e.test的二進制,這樣針對上面場景時,就可以直接使用這個可執行文件來操作,非常的方便。

當然可執行文件的方便少不了外部參數的自由注入,以及整體測試用例的精心標記。否則,測試代碼寫的不規范,需要頻繁的針對特定環境修改,也是拒不方便的。

Each case has a uniqe namespace, 每個case擁有唯一的空間

為每條測試用例創建一個獨立的空間,是kubernetes e2e framework的一大精華。每條測試用例獨享一個空間,彼此不沖突,從而根本上避免並發困擾,借助ginkgo的CLI來運行,會極大的提高執行效率。

而且這處代碼的方式也非常優美,很有借鑒價值:

func NewFramework(baseName string, options FrameworkOptions, client clientset.Interface) *Framework {
   f := &Framework{
      BaseName:                 baseName,
      AddonResourceConstraints: make(map[string]ResourceConstraint),
      Options:                  options,
      ClientSet:                client,
   }

   BeforeEach(f.BeforeEach)
   AfterEach(f.AfterEach)

   return f
}

利用ginkgo 的BeforeEach的嵌套特定,雖然在Describe下就定義framework的初始化(如下),但是在每個It執行前,上面的BeforeEach才會真正執行,所以並不會有沖突:

var _ = framework.KubeDescribe("GKE local SSD [Feature:GKELocalSSD]", func() {
   f := framework.NewDefaultFramework("localssd")
   It("should write and read from node local SSD [Feature:GKELocalSSD]", func() {
   ...
   })
})

當然e2e框架還負責case執行完的環境清理,並且是按需靈活配置。比如你希望,case失敗保留現場,不刪除namespace,那么就可以設置flag 參數 delete-namespace-on-failure為false來實現。

Asynchronous wait,異步等待

幾乎所有的Kubernetes操作都是異步的,所以不管是產品代碼還是測試用例,都廣泛的使用了這個異步等待庫:kubernetes/vendor/k8s.io/apimachinery/pkg/util/wait。這個庫,實現簡單,精悍,非常值得學習。

另外,針對測試的異步驗證,其實ginkgo(gomega)本身提供的Eventualy,也是非常好用的。

Suitable logs,打印合適的log

Kubernetes e2e 主要使用兩種方式輸出log,一個是使用glog庫,另一個則是framework.Logf方法。glog本身是golang官方提供的log庫,使用比較靈活。但是這里主要推薦的還是Framework.Logf。因為使用此方法的log會輸出到GinkgoWriter里面,這樣當我們使用ginkgo.RunSpecsWithDefaultAndCustomReporters方法時,log不光輸出到控制台,也會保存在junit格式的xml文件里,非常方便在jenkins里展示測試結果。

Clean code, 測試代碼也可以很干凈,優美

很多時候大家會覺得測試代碼比較low,其實卻不然。代碼無所謂優劣,好壞還是依賴寫代碼的人。而且我想說,測試代碼也是可以,並且應該寫的很優美的,不然如何提升逼格?!。

我們從Kubernetes e2e能看到很多好的借鑒,比如:

  • 抽取主干方法,以突出測試用例主體
  • 采用數據驅動方式書寫共性測試用例
  • 注釋工整,多少適宜
  • 不輸出低級別log
  • 代碼行長短適宜
  • 方法名定義清晰,可讀性強

Kubernetes環境普適性的e2e測試框架

現實中,如果需要圍繞k8s工作,你可能需要一套,自己的測試框架。不管是測試各種自定義的controller or watcher,還是測試運行在k8s里運行的私有服務。這套框架都適用於你:

https://github.com/CarlJi/golearn/tree/master/src/carlji.com/experiments/k8s_e2e_mat_framework

邏輯改動很小,只是在原有kubernetes e2e 框架基礎上抽取了最小集合。以方便快速使用。

是不是很貼心?

童鞋,點個贊吧(⊙o⊙)?

參考文檔

Contact me ?

Email: jinsdu@outlook.com

Blog: http://www.cnblogs.com/jinsdu/

Github: https://github.com/CarlJi



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM