本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

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 e2e.test 二進制檔案在 1.13 和 1.14 中仍然包含與 1.12 中相同的供應商支援。也可以不包含任何套件,這意味著只有通用供應商可用

  • “skeleton”:叢集透過 Kubernetes API 訪問,沒有其他
  • “local”:像“skeleton”一樣,但此外,kubernetes/kubernetes/cluster 中的腳本可以在測試套件運行後透過 ssh 檢索日誌

外部檔案

測試可能必須在運行時讀取其他檔案,例如 .yaml 宣告檔案。但是 Kubernetes e2e.test 二進制檔案應該是可用的並且完全獨立的,因為這簡化了它的交付和運行。Kubernetes 建構系統中的解決方案是使用 go-bindatatest/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 套件強制執行,該套件在第二次註冊標誌時會 panic。新的 config 套件簡化了多個選項的定義,這些選項儲存在單個結構中。

總而言之,這是現在處理參數的方式

  • 測試套件中的初始化程式碼定義測試和參數。實際的參數尚不可用,因此測試定義無法使用它們。
  • 測試套件的初始化程式碼解析參數和(可選)組態檔案。
  • 測試運行,現在可以使用參數值。

然而,最近 有人指出,希望並且有可能不將測試設定公開為命令列標誌,而僅透過組態檔案設定它們。有一個 未解決的錯誤 和一個關於此的 待處理的 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 驅動程式,從與透過 kubectl 部署也使用的完全相同的 .yaml 檔案中部署。如果 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 測試套件 HOWTO

測試套件初始化

第一步是設定定義測試套件的必要樣板程式碼。在 Kubernetes E2E 中,這在 e2e.goe2e_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.ClientSetf.Namespace

PMEM-CSI 儲存測試 匯入了 Kubernetes 儲存測試套件,並為必須已安裝在測試叢集中的 PMEM-CSI 驅動程式設定了儲存配置測試的一個實例。儲存測試套件更改儲存類別以使用不同的檔案系統類型運行測試。由於此要求,儲存類別是從 .yaml 檔案建立的。

解釋框架中可用的所有各種實用方法超出了這篇部落格文章的範圍。閱讀現有的測試和框架的原始碼是入門的好方法。

供應商鎖定

即使在消除許多不必要的依賴項之後,供應商鎖定 Kubernetes 程式碼仍然不簡單。k8s.io/kubernetes 並非旨在包含在其他專案中,並且沒有以 dep 等工具可以理解的方式定義其依賴項。其他 k8s.io 套件旨在包含在內,但 尚未遵循語義版本控制 或未標記任何版本(k8s.io/kube-openapik8s.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 移動到暫存儲存庫並重組它,使其更加模組化 (#74352)。
  • 透過將更多程式碼移動到 test/e2e/framework (#74353) 來簡化 e2e.go
  • 從 Kubernetes E2E 測試套件中刪除供應商特定的程式碼 (#70194)。

特別感謝本文的審閱者