本篇文章是关于 Kubernetes API 的。如何使用自定义资源 (CR) 对其进行扩展,以及当它的某些部分被弃用时意味着什么?
Kubernetes API 是 Kubernetes 最强大的部分。它为你的基础设施和应用程序提供可预测、可扩展的 API。可预测性来自精心设计的使用模式和强大的稳定性。有了这些东西,API 总是易于扩展。
你可以依靠最少的声明性数据来驱动复杂的控制循环。这些控制循环是一切服务的关键,从 Kubernetes 调度程序到 GitOps。
这种模式非常可靠,以至于业界采用它的用途比最初想象的要多。无论你是使用 Kubernetes 通过Cluster-API进行Deployment ,还是通过Vitess运行数据库,你可以使用相同的 Kubernetes API 来解决业务需求。
API 组和扩展
Kubernetes API 由不同的groups组成。这些组允许
- 可预测的 API 模式
- 用户逐步采用功能
- 独立定义资源范围和成熟度
- 特定用例的唯一 API 路径(例如 pod/logs)
消失的TPR
最初 Kubernetes API 没有组(group)。此功能后来被命名为核心组。由于资源和版本号之间的紧密耦合,核心组中的资源被证明很难扩展。由于所有资源都在一条 /apis/$VERSION/ 路径下,用户很难使用不同版本的资源并保持控制器之间的兼容性。开发 API 需要更多版本来扩展资源,并且在添加第三方资源 (TPR) 之前无法扩展 API。随着客户和供应商开始采用 TPR,各种缺点得到解决,TPR 被CustomResourceDefinitions (CRD)取代 。
CRD
CRD 非常成功,以至于核心组中的资源正在慢慢转移到更具体的 API 组中。一些 API 组包括应用程序、扩展程序和scheduling.k8s.io. 你将在规范文件中看到这些组作为apiVersion字段的一部分。
代码语言:javascript复制# batch is the group and v1 is the versionapiVersion: batch/v1
其他 Kubernetes 资源可以分成命名空间。这显示在 API 中的namespaces/$NAMESPACE,如下例所示:
代码语言:javascript复制/apis/$GROUP/$VERSION/namespaces/$NAMESPACE/$RESOURCES/$RESOURCE
这种方法意味着我们可以对资源执行可预测的操作,例如使用GET HTTP动词读取todo-list命名空间中的所有Deployment :
代码语言:javascript复制GET /apis/apps/v1/namespaces/todo-list/deployments
或者,我们可以使用以下命令读取 todo-list 命名空间中名为frontend的特定Deployment:
代码语言:javascript复制GET /apis/apps/v1/namespaces/todo-list/deployments/frontend
这种模式使得使用新的资源类型和组扩展 API 变得非常容易。
你可以使用 apiextensions.k8s.io 组来创建你自己的自定义资源 (CR),这将创建全新的组以供使用。
以下有个示例,用于创建版本为 v1alpha1, 资源类型为 sock , 组为 mine.k8s.io的对象。
代码语言:javascript复制apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: socks.mine.k8s.io
spec:
group: mine.k8s.io
versions:
- name: v1alpha1
names:
kind: Sock
plural: socks
scope: Namespaced
通过向 Kubernetes API 提交少量数据,你将获得以下 API:
代码语言:javascript复制/apis/mine.k8s.io/v1alpha1/namespaces/$NAMESPACE/socks/$SOCK
我们可以通过kubectl get socks –all-namespaces命令,检查我们拥有哪些 sock 资源。
这些构造使 API 足够灵活,可以针对未知用例进行扩展,并且足够简单。
CRD 与聚合
需要指出的一点是,Custom Resources 允许 Kubernetes API 识别自定义资源,而 API 路径是主要 kubernetes-api 进程的一部分。你还可以使用聚合 API server扩展 Kubernetes API 以声明特定路径(例如,/apis/socks.mine.co/v1)。
主要区别在于聚合 API 将请求代理到 Kubernetes 服务端点。这意味着你需要在集群内运行负责状态存储和版本生命周期的服务。这里不会专门讨论聚合 API,但在扩展 API 时了解它们的区别很重要。
熟悉这些概念很重要。在本文中,我们关注的不是如何使用这些东西,而是了解它们。Kubernetes 发展 API ,就是通过对组进行严格的版本控制。
版本和生命周期
版本作为 URL 路径的一部分,并定义了关于服务如何从一个版本变化到另一个版本的指南。这些版本将显示在你的 yaml 文件中 apiVersion 中的组名之后。
Kubernetes 遵循 alpha → beta → stable 的成熟度进程,并带有一些额外的版本控制,因此资源可以迭代而无需进入下一个成熟度级别。
alpha 资源可以从 v1alpha1 开始并使用, v1alpha2 进行迭代,或者如果有重大更改,则可能是 v2alpha1,Beta API 可能与 Alpha API 具有相同的规范,但成熟度会有所不同。
- Alpha API 是实验性的。它们可能有错误和向后不兼容的更改。默认情况下它们不启用,你应该谨慎使用它们。
- Beta API 已经过良好测试并默认启用。它们可以依赖于未来的功能,但它们的实现可能会根据用户反馈或可扩展性等约束而改变。
- 稳定的 API 没有“beta”或“alpha”名称。它们用一个版本(例如,v1)表示,并且它们的实现不应该在不更改版本号的情况下进行重大更改。
当 Kubernetes API 被弃用时,通常意味着它的一个版本不再可用。绝大多数弃用的发生是因为:
- 资源方案更改(例如,v1beta1 → v1beta2)。
- API 变得更加稳定(例如,v1alpha2 → v1beta1)。
- 组名称已更改(例如,入口从 extensions/v1beta1 移至networking.k8s.io/v1beta1)。
弃用意味着 API 的某个版本已被删除,你需要在清单和资源中验证你使用的 API 版本是否正确。在某些情况下,你可能需要更改资源字段。
如果一个 API 同时有多个版本可用,Kubernetes API 可以为你默默地升级其中的一些。但是,你仍然应该确保拥有正确的资源方案——尤其是随着 alpha API 的成熟,方案可能会在不同版本之间发生变化。
这些版本很重要,因为当你想要升级你的 Kubernetes API Server时,你需要确保你的资源——存储在 etcd 和静态清单中——匹配服务器中可用的资源。当你在多个集群或环境中存在版本偏差时,此过程会变得非常棘手。
此步骤对于你的自定义资源也很重要。即使你不更新 Kubernetes 版本,如果你不确保将它们匹配或迁移在一起,你仍然可以在控制器和组版本之间进行重大更改。
升级 Kubernetes 和验证清单
你可以使用 kubectl 命令从正在运行的集群中获取 API 组和版本的列表api-versions。针对正在运行的集群执行此操作的最佳部分是你还可以查看你拥有的自定义资源和聚合 API 组。
如果你没有正在运行的集群,则可以在API 参考文档 (https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#-strong-api-groups-strong-)中查看可用的默认组和版本。在 URL 中将 API 版本更改为你的目标版本。
Pluto
如果要针对特定 Kubernetes API 版本验证静态清单文件,可以使用pluto。Pluto 可以读取文件目录,并让某个版本是DEPRECATED或REMOVED。
代码语言:javascript复制$ pluto detect-files -d pkg/finder/testdata
NAME KIND VERSION REPLACEMENT REMOVED DEPRECATED
utilities Deployment extensions/v1beta1 apps/v1 true true
utilities Deployment extensions/v1beta1 apps/v1 true true
Pluto 还可以帮助处理默认资源类型,但不能帮助处理来自 CRD 或聚合 API 的自定义 API 组。运行 Pluto 是一个很好的冒烟测试,可以在更新 API Server 之前或在将现有清单Deployment到新集群之前验证配置。
Pluto 可以帮助处理默认组和版本,但如何升级自定义资源?如果你通过 helm 使用或创建 CRD,你可以查看其文档以了解如何最好地使用它们。如果你使用来自第三方供应商的 CRD,你应该查看他们关于如何处理升级的文档。
如果你想比较一个开源项目中的 CRD 从一个版本到另一个版本,请查看 docs.crds.dev。它将帮助你快速查看项目中包含哪些 CRD——包括哪些 API 组和版本。
如果你需要验证的不仅仅是 API 版本差异,你还应该查看kubeval 和conftest。这些工具可以帮助验证基于scheme 文档或开放策略代理的清单文件。
自定义资源
对于你创建的自定义资源,以下是处理升级和弃用的方法。测试你的 CR 升级很重要,以确保你的控制器能够使用自定义资源以及 Kubernetes API 组和版本正常运行。当你针对scheme和 API 版本更改更新控制器时,可能需要更新 CR 定义,也可能不需要更新。
CustomResourceDefinitions可以在其规范中定义多个版本。这种方法允许 Kubernetes API 同时为多个版本提供服务。
使用我们之前版本 v1alpha1 的socks示例,如果我们还想提供 API 的 v1beta1 版本,我们可以定义它:
代码语言:javascript复制apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: socks.mine.k8s.io
spec:
group: mine.k8s.io
versions:
- name: v1alpha1
served: true
storage: false
schema: ...
- name: v1beta1
served: true
storage: true
schema: ...
names:
kind: Sock
plural: socks
scope: Namespaced
该规范是指两个/apsi/mine.k8s.io/v1alpha1/和/apis/mine.k8s.io/v1beta1/将从API服务。当一个新的“sock”对象被创建时,它会作为 v1beta1 存储在 etcd 中,因为 storage: true 在 v1beta1 版本下。etcd 中只能存储一个版本。
如果你的版本有方案更改,则需要在将资源提交给 API 时对其进行修改。此步骤通过转换 webhook处理 。webhook 负责读取资源并将方案转换为不同的版本并将其发送回 API 服务器。
你可以像这样将转换 webhook 规范添加到你的 CR:
代码语言:javascript复制conversion: strategy: Webhook webhook: clientConfig: url: "https://socks.converter.example/convert-me"
任何时候在 Kubernetes API 服务器中创建 sock 资源时,其规范都会发送到指定的 URL 进行转换。转换 webhook 应该对资源执行任何必要的操作,并将其作为 ConversionReview 对象发送回 API 服务器。
使用 webhooks 进行转换可以非常灵活地管理 CR 生命周期,并让你可以根据需要缓慢地从一个版本迁移到另一个版本。
带有转换 webhook 的 CR 需要与聚合 API 相同数量的组件,但你可以利用 etcd`来存储对象。此外,默认的 API 模式可以简化你需要维护的工作量。
更新所有资源后,你可以通过在 CR 定义版本中使用 deprecated: true来弃用旧版本。不推荐使用的版本仍将由 API 提供服务,但当使用不推荐使用的版本将资源提交给 API 服务器时,它们将打印警告。
结论
Kubernetes API 的核心优势之一是在任何环境中都具有灵活性。了解你的资源使用的组和版本是用户的责任,以确保他们的资源与当前的 Kubernetes API 兼容。
在许多情况下,资源可以被通过修改并存储为较新的资源,而无需任何用户操作。此功能使用户对 API 升级更有信心,并允许逐步更改方案。
无论你是使用 pluto 之类的工具静态验证你的资源还是使用转换 webhook 自动转换你的资源,重要的是确保你能够安全地将资源从一个版本迁移到另一个版本。尽早添加这些测试将帮助你在长期使用 Kubernetes 时充满信心。
参考:https://www.kubernetes.org.cn/9768.html