Kubernetes v1.36:声明式验证正式发布
在 Kubernetes v1.36 中,Kubernetes 原生类型的声明式验证特性已正式发布(GA)。
对于用户而言,这意味着更可靠、更可预测且文档更完善的 API。 通过迁移到声明式模型,该项目还为未来通过 OpenAPI 发布验证规则以及与 Kubebuilder 等生态系统工具集成奠定了基础。 对于贡献者和生态系统开发者而言,这意味着可以用一个统一且易于维护的框架取代数千行手写的验证代码。
本文将介绍此次迁移的必要性、声明式验证框架的工作原理以及此正式版带来的新特性。
动机:摆脱“手写”技术债务
多年来,Kubernetes 原生 API 的验证几乎完全依赖于手写的 Go 代码。 如果某个字段需要设置最小值限制,或者两个字段需要互斥,开发人员就必须编写显式的 Go 函数来强制执行这些约束。
随着 Kubernetes API 接口的扩展,这种方法导致了几个系统性问题:
- 技术债务:该项目积累了大约 18,000 行样板验证代码。这些代码难以维护、容易出错, 并且在代码审查期间需要进行严格审查。
- 不一致性:由于缺乏集中式框架,验证规则有时会在不同的资源中以不一致的方式应用。
- API 不透明:手写的验证逻辑难以通过编程方式发现或分析。 这意味着客户端和工具无法在不查阅源代码或在运行时遇到错误的情况下,预先了解验证规则。
SIG API Machinery 提出的解决方案是声明式验证:
直接在 types.go 文件中使用接口定义语言(IDL)标签(特别是 +k8s: 标记标签)来定义验证规则。
引入 validation-gen
声明式验证特性的核心是一个名为 validation-gen 的全新代码生成器。
正如 Kubernetes 使用生成器进行深度复制、转换和默认值设置一样,validation-gen
会解析 +k8s: 标签并自动生成相应的 Go 验证函数。
这些生成的函数随后会无缝注册到 API 方案中。该生成器被设计为一个可扩展的框架, 允许开发人员通过描述它们要解析的标签以及它们应该生成的 Go 逻辑来插入新的“验证器”。
一套全面的 +k8s: 标签
声明式验证框架引入了一套全面的标记标签,提供丰富的验证功能,并针对 Go 类型进行了高度优化。有关支持标签的完整列表, 请参阅官方文档。 以下列出了一些你现在将在 Kubernetes 代码库中看到的最常用标签:
- 存在性:
+k8s:optional、+k8s:required - 基本约束:
+k8s:minimum=0、+k8s:maximum=100、+k8s:maxLength=16和+k8s:format=k8s-short-name - 集合:
+k8s:listType=map、+k8s:listMapKey=type - 联合:
+k8s:unionMember、+k8s:unionDiscriminator - 不可变性:
+k8s:immutable、+k8s:update=[NoSet, NoModify, NoClear]
用法示例:
type ReplicationControllerSpec struct {
// +k8s:optional
// +k8s:minimum=0
Replicas *int32 `json:"replicas,omitempty"`
}
通过将这些标签直接放置在字段定义上方,约束条件就具有了自文档性, 任何阅读类型定义的人都可以立即看到这些约束条件。
高级功能:“Ambient 机制”
这项工作最重要的成果之一是,验证棘轮机制现在已成为 API 的标准组成部分。 过去,如果我们需要加强验证,必须先编写手动棘轮代码,等待版本发布,然后再加强验证,以避免破坏现有对象。
借助声明式验证,这种安全机制已内置。如果用户更新现有对象,验证框架会将传入的对象与 oldObject 进行比较。
如果特定字段的值在语义上与其先前状态相同(即用户未对其进行更改),则新的验证规则将被忽略。
这种 “Ambient 机制”意味着我们可以立即以尽可能减少干扰的方式放松或加强验证。
使用 kube-api-linter 扩展 API 审查
达到正式发布(GA)要求我们对生成的代码绝对有信心,但我们的愿景远不止于代码验证。 声明式验证是全面改进 API 审查的关键组成部分,它能使审查更轻松、更一致、更具可扩展性。
通过将验证规则从不透明的 Go 函数中移至结构化标记,我们增强了 kube-api-linter
等工具的功能。该代码检查器现在可以静态分析 API 类型并自动强制执行 API 约定,
从而显著减轻 SIG API Machinery 审查人员的手动负担,并为贡献者提供即时反馈。
下一步是什么?
随着 Kubernetes v1.36 的发布,声明式验证正式上线(GA)。
作为一项稳定特性,相关的 DeclarativeValidation 特性门控现在默认启用。
它已成为向 Kubernetes 原生类型添加新验证规则的主要机制。
展望未来,该项目致力于更广泛地采用声明式验证。 这包括迁移现有 API 中剩余的旧式手写验证代码,并要求所有新 API 和新字段都使用声明式验证。 这一持续的过渡将不断降低代码库的复杂性,同时增强整个 Kubernetes API 接口的一致性和可靠性。
除了核心迁移之外,声明式验证也为更广泛的生态系统开启了令人兴奋的未来。
由于验证规则现在被定义为结构化标记,而不是不透明的 Go 代码,因此它们可以被解析并反映在
Kubernetes API 服务器发布的 OpenAPI schema 中。这为 kubectl 等工具、客户端库和
IDE 等在向集群发送请求之前执行丰富的客户端验证铺平了道路。
同样的声明式框架也可以被 Kubebuilder 等生态系统工具使用,从而为自定义资源定义(CRD)的作者带来更一致的开发体验。
参与其中
向声明式验证的迁移是一项持续进行的工作。虽然框架本身已经正式发布 (GA), 但仍需将旧版 API 迁移到新的声明式格式。
如果你有兴趣为 Kubernetes API Machinery 的核心做出贡献,这里是一个绝佳的起点。
请查看 validation-gen 文档,查找带有 sig/api-machinery 标签的问题,
并加入 Kubernetes Slack 上的 #sig-api-machinery
和 #sig-api-machinery-dev-tools
频道参与讨论(如需邀请,请访问 https://slack.k8s.io/)。
你还可以参加
SIG API Machinery 会议直接参与其中。
致谢
衷心感谢所有帮助将此特性上线 GA 的朋友们:
- Tim Hockin
- Joe Betz
- Aaron Prindle
- Lalit Chauhan
- David Eads
- Darshan Murthy
- Jordan Liggitt
- Patrick Ohly
- Maciej Szulik
- Wojciech Tyczynski
- Joel Speed
- Bryce Palmer
以及 Kubernetes 社区中其他众多为此做出贡献的人。
欢迎来到 Kubernetes 验证的声明式未来!