前言
Kubernetes的成功少不了大量工程師的共同參與,而他們之間如何高效的協作,非常值得我們探究。最近研究和使用了他們的e2e測試和框架,還是挺有啟發的。
怎樣才是好的e2e測試?
不同的人寫出的測試用例千差萬別,尤其在用例,可能由開發人員編寫的情形下,其情形可想而知。要知道,絕大多數開發人員,可能並沒有經歷過大量測試用例場景的熏陶。所以如何持續輸出高質量的e2e測試用例,確實是一個挑戰。不過,Kubernetes社區非常聰明,他們抽象出來了一些共性的東西,來希望大家遵守。比如說
- 拒絕“flaky”測試 - 也就是那些偶爾會失敗,但是又非常難定位的問題。
- 錯誤輸出要詳細,尤其是做斷言時,相關信息要有。不過也不要打印太多無效信息,尤其是在case並未失敗的情況。
- make case run in anywhere。這一點很重要,因為你的case是提交到社區,可能在各種環境下,各種時間段內運行。面對着各種cloud provider,各種系統負載情況。所以你的case要盡可能穩定,比如APICall,能異步的,就不要假設是同步; 比如多用retry機制等。
- 測試用例要執行的足夠快。超過兩分鍾,就需要給這種測試打上[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⊙)?
參考文檔
- https://github.com/thtanaka/kubernetes/blob/master/docs/devel/writing-good-e2e-tests.md
- https://github.com/thtanaka/kubernetes/blob/master/docs/devel/e2e-tests.md
Contact me ?
Email: jinsdu@outlook.com
Blog: http://www.cnblogs.com/jinsdu/
Github: https://github.com/CarlJi