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

Kubernetes 1.25:CustomResourceDefinition 驗證規則晉升 Beta 版

在 Kubernetes 1.25 中,CustomResourceDefinitions 的驗證規則 (CRD) 已晉升為 Beta 版!

驗證規則可以宣告如何使用 通用表達式語言 (CEL) 驗證自訂資源。例如

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
    ...
    openAPIV3Schema:
      type: object
      properties:
        spec:
          type: object
          x-kubernetes-validations:
            - rule: "self.minReplicas <= self.replicas && self.replicas <= self.maxReplicas"
              message: "replicas should be in the range minReplicas..maxReplicas."
          properties:
            replicas:
              type: integer
            ...

驗證規則支援廣泛的使用案例。為了了解一些功能,讓我們看幾個例子

驗證規則目的
self.minReplicas <= self.replicas驗證整數字段小於或等於另一個整數字段
'Available' in self.stateCounts驗證地圖中是否存在具有 'Available' 鍵的條目
self.set1.all(e, !(e in self.set2))驗證兩個集合的元素是不相交的
self == oldSelf驗證必填欄位一旦設定後就不可變更
self.created + self.ttl < self.expired驗證 'expired' 日期晚於 'create' 日期加上 'ttl' 期間

驗證規則具有表現力和彈性。請參閱驗證規則文件,以了解有關驗證規則功能的更多資訊。

為什麼選擇 CEL?

選擇 CEL 作為驗證規則的語言有幾個原因

  • CEL 表達式可以輕鬆地內嵌到 CRD 模式中。它們具有足夠的表現力,可以取代目前在 Admission Webhook 中實作的大多數 CRD 驗證檢查。這使得 CRD 成為自包含的,並且更容易理解。
  • CEL 表達式會針對 CRD 的模式進行「預先」編譯和類型檢查(在建立和更新 CRD 時),使其能夠在「執行時」(驗證自訂資源時)有效率且安全地評估。即使 CEL 中的正則表達式字串文字也會在建立或更新 CRD 時進行驗證和預先編譯。

為什麼不使用驗證 Webhook?

與驗證 Webhook 相比,使用驗證規則的好處

  • CRD 作者受益於更簡單的工作流程,因為驗證規則消除了開發和維護 Webhook 的需求。
  • 叢集管理員受益於不再需要為了 CRD 驗證而安裝、升級和運作 Webhook。
  • 叢集可操作性得到改善,因為 CRD 驗證不再需要遠端呼叫 Webhook 端點,從而消除了 Kubernetes API 伺服器請求服務路徑中潛在的故障點。這使得叢集能夠在擴展到更多已安裝的 CRD 擴充功能時保持高可用性,因為預期的控制平面可用性否則會隨著安裝的每個額外 Webhook 而降低。

開始使用驗證規則

在 OpenAPIv3 模式中編寫驗證規則

您可以為 CRD 的 OpenAPIv3 模式的任何層級定義驗證規則。驗證規則會自動限定於它們在模式中宣告的位置。

CRD 驗證規則的最佳實務

  • 將驗證規則的範圍盡可能接近它們驗證的欄位。
  • 在驗證獨立約束時使用多個規則。
  • 不要將驗證規則用於已經
  • 在可用的情況下,使用 OpenAPIv3 值驗證 (maxLengthmaxItemsmaxPropertiesrequiredenumminimummaximum、..) 和 字串格式
  • 在適當的情況下使用 x-kubernetes-int-or-stringx-kubernetes-embedded-typex-kubernetes-list-type=(set|map)

良好實務範例

驗證最佳實務範例
驗證整數介於 0 到 100 之間。使用 OpenAPIv3 值驗證。
type: integer
minimum: 0
maximum: 100
約束地圖(具有 additionalProperties 的物件)、陣列和字串上的最大大小限制。使用 OpenAPIv3 值驗證。建議用於所有地圖、陣列和字串。此最佳實務對於規則成本估算至關重要(如下所述)。
type:
maxItems: 100
要求日期時間比特定時間戳記更近。使用 OpenAPIv3 字串格式宣告該欄位是日期時間。使用驗證規則將其與特定時間戳記進行比較。
type: string
format: date-time
x-kubernetes-validations:
- rule: "self >= timestamp('2000-01-01T00:00:00.000Z')"
要求兩個集合不相交。使用 x-kubernetes-list-type 驗證陣列是集合。
使用驗證規則驗證集合是不相交的。
type: object
properties:
set1:
type: array
x-kubernetes-list-type: set
set2: ...
x-kubernetes-validations:
- rule: "!self.set1.all(e, !(e in self.set2))"

CRD 轉換規則

轉換規則使得可以在驗證規則中比較資源的新狀態與舊狀態。您可以使用轉換規則來確保叢集的 API 伺服器不接受無效的狀態轉換。轉換規則是引用 'oldSelf' 的驗證規則。僅當新舊值都存在時,API 伺服器才會評估轉換規則。

轉換規則範例

轉換規則目的
self == oldSelf對於必填欄位,使其一旦設定後就不可變更。對於可選欄位,僅允許從未設定轉換為已設定,或從已設定轉換為未設定。
(在欄位的父項上)has(self.field) == has(oldSelf.field)
在欄位上:self == oldSelf
使欄位不可變更:驗證欄位(即使是可選的)在資源建立後永遠不會變更(對於必填欄位,先前的規則更簡單)。
self.all(x, x in oldSelf)僅允許將項目新增到代表集合的欄位(防止移除)。
self >= oldSelf驗證數字是單調遞增的。

使用函數庫

驗證規則可以訪問幾個不同的函數庫

使用中的函數庫範例

驗證規則目的
!(self.getDayOfWeek() in [0, 6])驗證日期不是星期日或星期六。
isUrl(self) && url(self).getHostname() in [a.example.com', 'b.example.com']驗證 URL 具有允許的主機名稱。
self.map(x, x.weight).sum() == 1驗證物件列表的權重總和為 1。
int(self.find('^[0-9]*')) < 100驗證字串以小於 100 的數字開頭。
self.isSorted()驗證列表已排序。

資源使用和限制

為了防止 CEL 評估消耗過多的計算資源,驗證規則施加了一些限制。這些限制基於 CEL 成本單位,這是一種與平台和機器無關的執行成本度量。因此,無論在何處強制執行,限制都是相同的。

估計成本限制

根據設計,CEL 是非圖靈完備的,因此停機問題不是問題。CEL 利用此設計選擇來包含「估計成本」子系統,該子系統可以靜態計算任何 CEL 表達式的最壞情況執行時間成本。驗證規則與估計成本系統整合在一起,並且不允許將估計成本足夠差(高)的 CEL 表達式包含在 CRD 中。估計成本限制設定得相當高,通常需要 O(n^2) 或更差的操作,跨越無界大小的東西才能超過。幸運的是,修復通常非常簡單:因為成本系統知道 CRD 模式中宣告的大小限制,所以 CRD 作者可以將大小限制新增到 CRD 的模式中(陣列的 maxItems、地圖的 maxProperties、字串的 maxLength)以降低估計成本。

良好實務

在 CRD 模式中,為所有陣列、地圖(具有 additionalPropertiesobject)和字串類型設定 maxItemsmaxPropertiesmaxLength!這會導致更低且更準確的估計成本,並且通常使 CRD 更安全地使用。

CRD 驗證規則的執行時成本限制

除了估計成本限制外,CEL 還會在評估 CEL 表達式時追蹤實際成本,如果超出限制,將會停止執行表達式。

由於估計成本限制已經到位,因此很少遇到執行時成本限制。但這是可能的。例如,對於完全由單一大型列表和驗證規則組成的龐大資源,可能會遇到這種情況,該驗證規則要么在列表中的每個元素上評估,要么遍歷整個列表。

CRD 作者可以確保不會超出執行時成本限制,其方式與避免估計成本限制的方式非常相似:通過在陣列、地圖和字串類型上設定 maxItemsmaxPropertiesmaxLength

未來工作

我們期待與社群合作採用 CRD 驗證規則,並希望看到此功能在即將發布的 Kubernetes 版本中升級為正式發布!

越來越多的 Kubernetes 貢獻者社群正在思考如何使用 CEL 作為 Admission Webhook 的替代方案,來編寫可擴展的 Admission Controller,以用於政策強制執行用例。任何有興趣的人都應該通過常用的 SIG API Machinery 管道或通過 slack 在 #sig-api-machinery-cel-dev 上與我們聯繫。

誌謝

特別感謝 Cici Huang、Ben Luddy、Jordan Liggitt、David Eads、Daniel Smith、Stefan Schimanski 博士、Leila Jalali 以及所有為驗證規則做出貢獻的人!