本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
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 模式中。它們的表現力足以取代當前在准入 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 的值驗證(
maxLength
、maxItems
、maxProperties
、required
、enum
、minimum
、maximum
等)和字串格式。 - 在適當的地方使用
x-kubernetes-int-or-string
、x-kubernetes-embedded-type
和x-kubernetes-list-type=(set|map)
。
良好實踐的示例
驗證 | 最佳實踐 | 示例 |
---|---|---|
驗證一個整數在 0 到 100 之間。 | 使用 OpenAPIv3 的值驗證。 | type: integer |
限制對映(帶有 additionalProperties 的物件)、陣列和字串的最大大小限制。 | 使用 OpenAPIv3 值驗證。推薦用於所有對映、陣列和字串。這一最佳實踐對於規則成本估算(下文解釋)至關重要。 | type: |
要求一個日期時間比某個特定時間戳更晚。 | 使用 OpenAPIv3 字串格式來宣告該欄位為日期時間。使用驗證規則將其與特定時間戳進行比較。 | type: string |
要求兩個集合不相交。 | 使用 x-kubernetes-list-type 來驗證陣列是集合。 使用驗證規則來驗證集合不相交。 | type: object |
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 模式中為所有陣列、對映(帶有 `additionalProperties` 的 `object`)和字串型別設定 `maxItems`、`maxProperties` 和 `maxLength`!這會帶來更低、更準確的估算成本,並通常使 CRD 更安全。
CRD 驗證規則的執行時成本限制
除了估算成本限制外,CEL 在評估 CEL 表示式時還會跟蹤實際成本,如果超過限制,將停止表示式的執行。
由於已經有了估算成本限制,執行時成本限制很少會遇到。但它是有可能發生的。例如,對於一個完全由單個大列表組成的大型資源,以及一個在列表的每個元素上評估或遍歷整個列表的驗證規則,可能會遇到這種情況。
CRD 作者可以確保不會超過執行時成本限制,方法與避免估算成本限制的方式大致相同:透過在陣列、對映和字串型別上設定 `maxItems`、`maxProperties` 和 `maxLength`。
未來的工作
我們期待與社群合作,共同推動 CRD 驗證規則的採用,並希望在即將到來的 Kubernetes 版本中看到該功能晉升為正式釋出!
一個不斷壯大的 Kubernetes 貢獻者社群正在思考如何使用 CEL 作為準入 Webhook 的替代品,為策略執行用例編寫可擴充套件的准入控制器。任何感興趣的人都應該透過常規的 SIG API Machinery 渠道或 Slack 上的 #sig-api-machinery-cel-dev 與我們聯絡。
致謝
特別感謝 Cici Huang、Ben Luddy、Jordan Liggitt、David Eads、Daniel Smith、Stefan Schimanski 博士、Leila Jalali 以及所有為驗證規則做出貢獻的人!