这篇文章发布已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已不正确。
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 | 验证 map 中存在一个键为 'Available' 的条目 |
self.set1.all(e, !(e in self.set2)) | 验证两个集合的元素是不相交的 |
self == oldSelf | 验证一个必需字段一旦设置就不可变 |
self.created + self.ttl < self.expired | 验证“过期”日期在“创建”日期加上“ttl”持续时间之后 |
验证规则具有表达性和灵活性。 请参阅验证规则文档,了解有关验证规则功能的更多信息。
为什么选择 CEL?
选择 CEL 作为验证规则的语言有两个原因
- CEL 表达式可以很容易地内联到 CRD 模式中。它们具有足够的表达能力,可以取代目前在 admission webhooks 中实现的大多数 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 |
约束 maps (带有 additionalProperties 的对象)、数组和字符串的最大大小限制。 | 使用 OpenAPIv3 值验证。 推荐用于所有 maps、数组和字符串。 此最佳实践对于规则成本估算(如下所述)至关重要。 | type: |
要求日期时间比特定时间戳更新。 | 使用 OpenAPIv3 字符串格式声明该字段是日期时间。 使用验证规则将其与特定的时间戳进行比较。 | type: string |
要求两个集合是不相交的。 | 使用 x-kubernetes-list-type 验证数组是集合。 使用验证规则验证集合是不相交的。 | type: object |
CRD 过渡规则
过渡规则使得可以在验证规则中将资源的新状态与旧状态进行比较。 您可以使用过渡规则来确保集群的 API 服务器不接受无效的状态转换。 过渡规则是引用 'oldSelf' 的验证规则。 仅当旧值和新值都存在时,API 服务器才会评估过渡规则。
过渡规则示例
过渡规则 | 目的 |
---|---|
self == oldSelf | 对于必需字段,一旦设置该字段就使其不可变。 对于可选字段,仅允许从 unset 到 set 或从 set 到 unset 的转换。 |
(在字段的父级上)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
、maps 的 maxProperties
、字符串的 maxLength
)来降低估计成本。
良好实践
在 CRD 模式中的所有数组、map (带有 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 以及所有为验证规则做出贡献的人!