API 设计指南
原文:https://gateway-api.sigs.k8s.io/contributing/api-design-guide/
整个 API 中贯穿着一些通用的设计指导原则。
Kubernetes API 仅在单个资源层面保证一致性。这对复杂的资源图(与单个资源相对)带来两个后果:
- 跨越多个资源的属性校验是异步且最终一致的。简单的语法检查可以在单个资源层面完成,但跨资源的依赖必须由控制器自行处理。
- 控制器必须能够处理资源之间链接失效以及/或者配置不匹配的情况。
冲突
相互独立的行为者(例如集群运维和应用开发者)之间责任分离与委派,会导致配置中的冲突。例如,两个应用团队可能会不经意地对同一个 HTTP 路径提交配置。
大多数情况下,可能发生冲突的字段会在文档中给出冲突解决指南。如果某个冲突没有规定的解决方案,则应按以下指导原则来处理:
- 优先不去破坏正在工作的东西。
- 尽可能少地丢流量。
- 在冲突发生时提供一致的体验。
- 当识别出冲突时,清楚地说明选择了哪条路径。在可能的情况下,应通过在相关资源的 status 条件中设置适当的值来告知用户。
- 更具体的匹配应当比不太具体的匹配优先。
- 创建时间最早的资源获胜。
- 如果其它一切都相等(包括创建时间),应当把优先级交给字典序靠前的资源(
namespace/name)。例如,foo/bar应当比foo/baz优先。
优雅地处理未来的 API 版本
实现本 API 时一个重要的考量是:它在未来会如何变化。与它之前的 Ingress API 类似,本 API 被设计为由同一集群中的多种不同产品实现。这意味着:你的实现开发时所基于的 API 版本可能与实际使用时的 API 版本不同。
至少,必须满足以下要求,才能保证未来版本的 API 不会破坏你的实现:
- 不因字段验证被放宽而崩溃。
- 不因字段从必填变为可选而崩溃。
支持的 API 版本
集群中安装的 Gateway API CRD 版本,可以通过查看每个 CRD 上的 gateway.networking.k8s.io/bundle-version 注解来确定。每个实现必须把该版本与它识别和支持的版本列表做比较。拥有 GatewayClass 的实现必须在 GatewayClass 上发布 SupportedVersion 条件,用以指出集群中安装的 CRD 是否受支持。
CRD 与 Webhook 校验的局限
CRD 与 webhook 校验并非最终校验——webhook 只是"良好的 UX",不是模式强制(schema enforcement)。这种校验意在为用户在提供了无效配置时提供即时反馈。以防御式的方式编写代码——假设到你的控制器的输入中至少会有部分无效的输入(Gateway API 资源)。Webhook 和 CRD 校验都不是完全可靠的,因为它们:
- 可能没有被正确部署。
- 可能在未来的 API 发布中被放宽(字段可能在新版本 API 中包含验证更宽松的值)。
注:这些限制并非 Gateway API 独有,更普遍地适用于所有 Kubernetes 的 CRD 与 webhook。
实施者应当保证:即使 API 中出现了意料之外的值,他们的实现也仍然尽可能安全、并能优雅地处理这种输入。最常见的做法是把该配置视为格式错误并拒绝**,再通过 status 块中的 condition 告知用户。为了避免重复劳动,Gateway API 维护者们正在考虑添加一个共享的校验包,让实现可以直接使用——这由 #926 跟踪。
期望
我们预期在这个 API 的早期,不同提供方之间的一致性程度会参差不齐。用户可以通过一致性测试的结果来了解实现行为与规范可能存在差异的地方**。
实现特有(Implementation-specific)
在 API 的部分方面,我们让用户能够指定该特性的使用方式,但具体行为可能取决于底层实现。例如,正则表达式匹配在所有实现中都存在,但由于底层库的微妙差异(PCRE、ECMA、Re2),指定一个精确的行为是不可能的。让用户在最大程度上描述该特性仍然是有用的,但我们也承认:部分 API 子集的行为可能仍然会有所不同(这是**可以接受的)。
这些情形会被标记为 API 的"实现特有"界定部分。
Kind vs. Resource
与其它 Kubernetes API 类似,Gateway API 在整个 API 的对象引用中使用"Kind"而不是"Resource"。这种用法对大多数 Kubernetes 用户来说应该不陌生。
根据 Kubernetes API 约定,这意味着本 API 的所有实现都应当在 kind 与 resource 之间有一份预定义的映射。依赖动态 resource 映射是不安全的。
API 约定
Gateway API 遵循 Kubernetes API 约定。这些约定旨在简化客户端开发,并保证配置机制能够在各种用例中被一致地实现。除了 Kubernetes API 约定之外,Gateway API 还有下面这些约定:
列表名(List Names)
本项目用的另一个约定是:CRD 中列表的字段名使用复数。我们使用以下规则:
- 如果字段名是名词,用复数。
- 如果字段名是动词,用单数。