本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
人人可用的 Kubernetes 端到端測試
越來越多的曾是 Kubernetes 一部分的元件,現在都在 Kubernetes 之外開發。例如,儲存驅動程式曾被編譯到 Kubernetes 二進位制檔案中,然後被移動到主機上的獨立 FlexVolume 二進位制檔案中,現在則以容器儲存介面 (CSI) 驅動程式的形式交付,部署在 Kubernetes 叢集內部的 Pod 中。
這給開發此類元件的開發者帶來了挑戰:如何對這些外部元件進行 Kubernetes 叢集上的端到端(E2E)測試?用於測試 Kubernetes 本身E2E框架具有所有必要的功能。然而,嘗試在 Kubernetes 之外使用它很困難,只有仔細選擇大量依賴項的正確版本才有可能。在 Kubernetes 1.13 中,E2E 測試已經變得簡單得多。
這篇博文總結了 Kubernetes 1.13 中所做的更改。對於 CSI 驅動開發者,它將涵蓋正在進行的努力,即如何使儲存測試也可用於測試第三方 CSI 驅動。如何使用它們將以兩個 Intel CSI 驅動為例進行演示。
測試這些驅動是這些改進的主要動機。
E2E 概述
端到端(E2E)測試包含幾個階段:
- 實現測試套件。這是本博文的重點。Kubernetes E2E 框架用 Go 編寫。它依賴 Ginkgo 進行測試管理,依賴 Gomega 進行斷言。這些工具支援“行為驅動開發”,它在“規格”中描述預期行為。在本博文中,“測試”用於指代單個
Ginkgo.It
規格。測試使用 client-go 與 Kubernetes 叢集互動。 - 啟動測試叢集。諸如 kubetest 等工具可以在這方面提供幫助。
- 針對該叢集執行 E2E 測試套件。Ginkgo 測試套件可以使用
ginkgo
工具執行,也可以作為常規 Go 測試使用go test
執行。不帶任何引數時,Kubernetes E2E 測試套件將根據 KUBECONFIG 等環境變數連線到預設叢集,就像 kubectl 一樣。Kubetest 也知道如何執行 Kubernetes E2E 套件。
Kubernetes 1.13 中的 E2E 框架增強
以下所有增強都遵循相同的基本模式:它們使 E2E 框架在 Kubernetes 之外更有用且更易於使用,同時不改變原始 Kubernetes e2e.test 二進位制檔案的行為。
拆分提供商支援
在 Kubernetes <= 1.12 中,使用 E2E 框架困難的主要原因是它依賴於特定於提供商的 SDK,這引入了大量的包。僅僅編譯它就非同小可。
其中許多包只在特定測試中需要。例如,測試預先配置的卷的掛載必須首先像管理員一樣配置這樣的卷,透過非 Kubernetes API 直接與特定的儲存後端通訊。
目前正在努力將雲提供商特定測試從核心 Kubernetes 中移除。在PR #68483中採取的方法可以看作是實現這一目標的一個增量步驟:所有云提供商特定程式碼都被移到test/e2e/framework/providers下的可選包中,而不是立即刪除程式碼並破壞所有依賴它的測試。E2E 框架然後透過由每個供應商包獨立實現的介面訪問它。
E2E 測試套件的作者決定將哪些包匯入到測試套件中。然後透過 --provider
命令列標誌啟用供應商支援。Kubernetes 1.13 和 1.14 中的 e2e.test 二進位制檔案仍然包含與 1.12 中相同的供應商支援。也可以不包含任何包,這意味著只有通用提供商可用:
- “骨架”:叢集透過 Kubernetes API 訪問,僅此而已。
- “本地”:類似於“骨架”,但此外,kubernetes/kubernetes/cluster 中的指令碼可以在測試套件執行後透過 ssh 檢索日誌。
外部檔案
測試可能需要在執行時讀取額外的檔案,例如 .yaml 清單。但是 Kubernetes e2e.test 二進位制檔案應該能夠獨立使用和執行,因為這簡化了分發和執行。Kubernetes 構建系統中的解決方案是使用 go-bindata 將 test/e2e/testing-manifests
下的所有檔案連結到二進位制檔案中。E2E 框架曾經對 go-bindata
的輸出有硬依賴,現在bindata 支援是可選的。透過 testfiles 包訪問檔案時,檔案將從不同的源檢索:
- 相對於用 `--repo-root` 引數指定的目錄。
- 零個或多個 bindata 塊
測試引數
e2e.test 二進位制檔案接受控制測試執行的額外引數。2016 年,曾開始努力用 Viper 配置檔案替換所有 E2E 命令列引數。但該工作停滯不前,導致開發者在如何處理特定於測試的引數方面缺乏明確的指導。
v1.12 中的方法是將所有標誌新增到中央 test/e2e/framework/test_context.go,但這不適用於獨立於框架開發的測試。自 PR #69105 以來,建議使用普通的 flag
包在其自己的原始碼中定義其引數。標誌名稱必須是分層的,用點分隔不同級別,例如 my.test.parameter
,並且必須是唯一的。唯一性由 flag
包強制執行,當第二次註冊標誌時會發生恐慌。新的 config 包簡化了多個選項的定義,這些選項儲存在單個結構體中。
總而言之,引數現在是這樣處理的:
- 測試包中的初始化程式碼定義了測試和引數。實際的引數*值*尚未可用,因此測試定義無法使用它們。
- 測試套件的初始化程式碼解析引數和(可選地)配置檔案。
- 測試執行,現在可以使用引數值。
然而,最近有人指出,不將測試設定作為命令列標誌公開,而只通過配置檔案設定它們是可取且可行的。關於這一點,有一個未解決的 bug 和一個待處理的 PR。
Viper 支援已得到增強。與提供者支援一樣,它是完全可選的。透過匯入 viperconfig
包並在解析常規命令列標誌後呼叫它,它被拉入 e2e.test 二進位制檔案。這樣實現,所有可以透過命令列標誌設定的變數,當該標誌出現在 Viper 配置檔案中時,也會被設定。例如,Kubernetes v1.13 e2e.test
二進位制檔案接受 --viper-config=/tmp/my-config.yaml
,當該檔案包含以下內容時,它將 my.test.parameter
設定為 value
: my: test: parameter: value
在較舊的 Kubernetes 版本中,該選項只能從當前目錄載入檔案,必須省略字尾,並且只有少數引數可以透過這種方式設定。請注意,Viper 的一個限制仍然存在:它透過將配置檔案條目與已知標誌匹配來工作,而不警告未知配置檔案條目,從而導致拼寫錯誤未被檢測到。一個更好的 Kubernetes 配置檔案解析器仍在開發中。
從 .yaml 清單建立專案
在 Kubernetes 1.12 中,雖然支援從 .yaml 檔案載入單個專案,但建立該專案必須透過手寫程式碼完成。現在,框架有了新方法,用於載入包含多個專案的 .yaml 檔案,修補這些專案(例如,為當前測試設定建立的名稱空間),並建立它們。目前,這用於為每個測試重新部署 CSI 驅動程式,使用的 .yaml 檔案與透過 kubectl 部署時完全相同。如果 CSI 驅動程式支援以不同名稱執行,那麼測試將完全獨立並可以並行執行。
然而,重新部署驅動程式會減慢測試執行速度,並且它不覆蓋針對驅動程式的併發操作。更真實的測試場景是在啟動測試叢集時部署一次驅動程式,然後針對該部署執行所有測試。最終,Kubernetes E2E 測試將轉向這種模式,一旦更清楚如何擴充套件測試叢集的啟動以包含安裝 CSI 驅動程式等附加實體。
Kubernetes 1.14 中即將推出的增強功能
複用儲存測試
能夠在 Kubernetes 之外使用框架,可以構建自定義測試套件。但一個沒有測試的測試套件仍然毫無用處。現有的一些測試,特別是針對儲存的測試,也可以應用於樹外元件。感謝 Masaki Kimura 所做的工作,Kubernetes 1.13 中的儲存測試被定義為可以針對不同的驅動程式多次例項化。
但歷史總是驚人的相似。和提供商一樣,定義這些測試的包也引入了所有樹記憶體儲後端的驅動定義,這反過來又引入了比所需更多的額外包。這個問題已在即將釋出的 Kubernetes 1.14 中修復。
跳過不支援的測試
一些儲存測試依賴於叢集的特性(例如在支援 XFS 的主機上執行)或驅動程式的特性(例如支援塊卷)。這些條件在測試執行時進行檢查,當它們不滿足時會導致跳過測試。好處是它記錄了測試未執行的原因。
啟動測試很慢,特別是當它必須首先部署 CSI 驅動程式時,以及在其他場景中。在快速叢集上,為一個測試建立名稱空間需要 5 秒,並且會產生大量嘈雜的測試輸出。本可以透過跳過不支援測試的定義來解決這個問題,但那樣報告測試為什麼甚至不是測試套件的一部分就變得棘手了。這種方法已被放棄,轉而重新組織儲存測試套件,使其在執行更昂貴的測試設定步驟之前首先檢查條件。
更具可讀性的測試定義
相同的 PR 也重寫了測試,使其像傳統的 Ginkgo 測試一樣執行,測試用例及其區域性變數位於單個函式中。
測試外部驅動
構建一個自定義的 E2E 測試套件仍然需要大量工作。在Kubernetes 1.14 測試存檔中分發的 e2e.test 二進位制檔案將能夠測試已安裝的儲存驅動程式,而無需重新構建測試套件。有關進一步說明,請參閱此README。
E2E 測試套件操作指南
測試套件初始化
第一步是設定定義測試套件所需的樣板程式碼。在Kubernetes E2E中,這是在e2e.go
和e2e_test.go
檔案中完成的。它也可以在一個單獨的e2e_test.go
檔案中完成。Kubernetes在e2e_test.go
中匯入了所有各種提供者、樹內測試、Viper配置支援和bindata檔案查詢。e2e.go
控制實際執行,包括一些叢集準備和指標收集。
一個更簡單的起點是 PMEM-CSI 中的 e2e_[test].go
檔案。它不使用任何提供商、Viper 和 bindata,只匯入儲存測試。
與 PMEM-CSI 一樣,OIM 也放棄了所有額外功能,但它稍微複雜一些,因為它將自定義叢集啟動直接整合到測試套件中,這在這種情況下很有用,因為一些附加元件必須在主機端執行。透過直接在 E2E 二進位制檔案中執行它們,使用 dlv
進行互動式除錯變得更容易。
這兩個 CSI 驅動都遵循 Kubernetes 的示例,使用 test/e2e
目錄作為其測試套件,但任何其他目錄和檔名也都適用。
新增 E2E 儲存測試
測試由匯入到測試套件中的包定義。E2E 測試的唯一特殊之處在於它們使用 framework.NewDefaultFramework
例項化一個 framework.Framework
指標(通常稱為 f
)。此變數在每個測試的 BeforeEach
中重新初始化,並在 AfterEach
中釋放。它在執行時(且僅在執行時!)具有 f.ClientSet
和 f.Namespace
,可供測試使用。
PMEM-CSI 儲存測試匯入 Kubernetes 儲存測試套件,併為已安裝在測試叢集中的 PMEM-CSI 驅動程式設定一個 Provisioning 測試例項。儲存測試套件更改儲存類以使用不同的檔案系統型別執行測試。由於此要求,儲存類是從 .yaml 檔案建立的。
解釋框架中所有可用的實用方法超出了本部落格文章的範圍。閱讀現有測試和框架的原始碼是入門的好方法。
供應商化
即使在消除了許多不必要的依賴之後,將 Kubernetes 程式碼供應商化仍然並非易事。k8s.io/kubernetes
不應該包含在其他專案中,並且沒有以 dep
等工具理解的方式定義其依賴項。其他 k8s.io
包應該包含在內,但尚未遵循語義版本控制,或者沒有標記任何釋出(k8s.io/kube-openapi
、k8s.io/utils
)。
PMEM-CSI 使用 dep。它的 Gopkg.toml 檔案是一個很好的起點。它啟用了修剪(dep 預設不啟用)並將某些專案鎖定到與所使用的 Kubernetes 版本相容的版本。當 dep
未選擇相容版本時,檢查 Kubernetes 的 Godeps.json 有助於確定哪個修訂版可能是正確的。
編譯並執行測試套件
go test ./test/e2e -args -help
是測試測試套件是否編譯的最快方法。
一旦它編譯完成並且叢集已經設定好,命令 go test -timeout=0 -v ./test/e2e -ginkgo.v
將執行所有測試。為了並行執行測試,請改用 ginkgo -p ./test/e2e
命令。
參與進來
Kubernetes E2E 框架由 SIG-testing 中的 testing-commons 子專案擁有。有關聯絡資訊,請參閱該頁面。
有各種任務可以完成,包括但不限於:
- 將 test/e2e/framework 移入一個 staging 倉庫,並對其進行重構,使其更具模組化(#74352)。
- 透過將更多程式碼移到
test/e2e/framework
中來簡化e2e.go
(#74353)。 - 從 Kubernetes E2E 測試套件中移除特定於提供商的程式碼 (#70194)。
特別感謝本文的審閱者:
- Olev Kartau (https://github.com/okartau)
- Mary Camp (https://github.com/MCamp859)