自定义资源
自定义资源是 Kubernetes API 的扩展。此页面讨论何时向 Kubernetes 集群添加自定义资源,以及何时使用独立服务。它描述了添加自定义资源的两种方法,以及如何选择它们。
自定义资源
资源是 Kubernetes API 中的一个端点,它存储特定类型的 API 对象的集合;例如,内置的 pods 资源包含 Pod 对象的集合。
自定义资源是 Kubernetes API 的扩展,它不一定在默认的 Kubernetes 安装中可用。它表示特定 Kubernetes 安装的自定义。然而,许多核心 Kubernetes 功能现在是使用自定义资源构建的,这使得 Kubernetes 更加模块化。
自定义资源可以通过动态注册在运行的集群中出现和消失,并且集群管理员可以独立于集群本身更新自定义资源。安装自定义资源后,用户可以使用 kubectl 创建和访问其对象,就像他们对 Pods 等内置资源所做的那样。
自定义控制器
自定义资源本身允许您存储和检索结构化数据。当您将自定义资源与自定义控制器结合使用时,自定义资源将提供真正的声明式 API。
Kubernetes 声明式 API 强制执行职责分离。您声明资源的期望状态。Kubernetes 控制器使 Kubernetes 对象的当前状态与您声明的期望状态保持同步。这与命令式 API 形成对比,在命令式 API 中,您指示服务器执行什么操作。
您可以在运行的集群上部署和更新自定义控制器,而无需考虑集群的生命周期。自定义控制器可以使用任何类型的资源,但当与自定义资源结合使用时,它们尤其有效。Operator 模式结合了自定义资源和自定义控制器。您可以使用自定义控制器将特定应用程序的领域知识编码到 Kubernetes API 的扩展中。
我应该向我的 Kubernetes 集群添加自定义资源吗?
在创建新的 API 时,请考虑是否将您的 API 与 Kubernetes 集群 API 聚合,或者让您的 API 独立存在。
如果以下情况,请考虑 API 聚合 | 如果以下情况,请首选独立的 API |
---|---|
您的 API 是声明式的。 | 您的 API 不符合声明式模型。 |
您希望使用 kubectl 读取和写入新类型。 | 不需要 kubectl 支持 |
您希望在 Kubernetes UI 中(例如仪表板)查看新类型,以及内置类型。 | 不需要 Kubernetes UI 支持。 |
您正在开发新的 API。 | 您已经有一个可以很好地为您的 API 提供服务的程序。 |
您愿意接受 Kubernetes 对 REST 资源路径的格式限制,例如 API 组和命名空间。(请参阅API 概述。) | 您需要具有特定的 REST 路径才能与已定义的 REST API 兼容。 |
您的资源自然地限定在集群或集群的命名空间中。 | 集群或命名空间作用域资源不太合适;您需要控制资源路径的具体细节。 |
您希望重用Kubernetes API 支持的功能。 | 您不需要这些功能。 |
声明式 API
在声明式 API 中,通常
- 您的 API 由相对较少的相对较小的对象(资源)组成。
- 对象定义应用程序或基础结构的配置。
- 对象更新的频率相对较低。
- 人类通常需要读取和写入对象。
- 对象的主要操作是 CRUD(创建、读取、更新和删除)。
- 不需要跨对象的事务:API 表示期望的状态,而不是精确的状态。
命令式 API 不是声明式的。您的 API 可能不是声明式的迹象包括
- 客户端说“执行此操作”,然后在操作完成时收到同步响应。
- 客户端说“执行此操作”,然后收到操作 ID,并且必须检查单独的 Operation 对象以确定请求是否完成。
- 您谈论远程过程调用 (RPC)。
- 直接存储大量数据;例如,每个对象 > 几 kB,或 > 数千个对象。
- 需要高带宽访问(持续每秒 10 个请求)。
- 存储最终用户数据(例如图像、PII 等)或应用程序处理的其他大规模数据。
- 对象的自然操作不是 CRUD。
- API 不容易建模为对象。
- 您选择使用操作 ID 或操作对象来表示挂起的操作。
我应该使用 ConfigMap 还是自定义资源?
如果以下任何一项适用,请使用 ConfigMap
- 存在现有的、有据可查的配置文件格式,例如
mysql.cnf
或pom.xml
。 - 您希望将整个配置放入 ConfigMap 的一个键中。
- 配置文件的主要用途是供集群上的 Pod 中运行的程序使用,以配置自身。
- 文件的使用者更喜欢通过 Pod 中的文件或 Pod 中的环境变量使用,而不是 Kubernetes API。
- 当文件更新时,您希望通过 Deployment 等执行滚动更新。
注意
对于敏感数据,请使用 Secret,它类似于 ConfigMap 但更安全。如果以下大部分适用,请使用自定义资源(CRD 或聚合 API)
- 您希望使用 Kubernetes 客户端库和 CLI 创建和更新新资源。
- 您希望
kubectl
提供顶级支持;例如,kubectl get my-object object-name
。 - 您希望构建新的自动化,监视新对象的更新,然后 CRUD 其他对象,反之亦然。
- 您希望编写处理对象更新的自动化。
- 您希望使用 Kubernetes API 约定,如
.spec
、.status
和.metadata
。 - 您希望该对象是对一组受控资源的抽象,或者对其他资源的汇总。
添加自定义资源
Kubernetes 提供了两种方法将自定义资源添加到您的集群
- CRD 很简单,无需任何编程即可创建。
- API 聚合需要编程,但允许对 API 行为(如数据存储方式以及 API 版本之间的转换)进行更多控制。
Kubernetes 提供了这两种选择以满足不同用户的需求,从而在易用性和灵活性之间取得平衡。
聚合 API 是位于主 API 服务器之后的从属 API 服务器,主 API 服务器充当代理。这种安排称为 API 聚合(AA)。对于用户而言,Kubernetes API 看起来被扩展了。
CRD 允许用户创建新的资源类型,而无需添加另一个 API 服务器。您无需了解 API 聚合即可使用 CRD。
无论如何安装,新资源都被称为自定义资源,以将其与内置的 Kubernetes 资源(如 Pod)区分开来。
注意
避免将自定义资源用作应用程序、最终用户或监控数据的数据存储:将应用程序数据存储在 Kubernetes API 中的架构设计通常表示设计过于紧密耦合。
在架构上,云原生应用程序架构倾向于组件之间的松耦合。如果您的工作负载的某些部分需要后台服务才能正常运行,请将该后台服务作为组件运行或将其作为外部服务使用。这样,您的工作负载就不会依赖 Kubernetes API 来正常运行。
CustomResourceDefinitions
CustomResourceDefinition API 资源允许您定义自定义资源。定义 CRD 对象会创建一个新的自定义资源,其中包含您指定的名称和模式。Kubernetes API 提供并处理自定义资源的存储。CRD 对象本身的名称必须是从定义的资源名称及其 API 组派生的有效 DNS 子域名;有关更多详细信息,请参见 如何创建 CRD。此外,由 CRD 定义的类型/资源的对象名称也必须是有效的 DNS 子域名。
这使您无需编写自己的 API 服务器来处理自定义资源,但实现的通用性意味着您的灵活性不如 API 服务器聚合。
有关如何注册新的自定义资源,使用新资源类型的实例以及使用控制器处理事件的示例,请参阅 自定义控制器示例。
API 服务器聚合
通常,Kubernetes API 中的每个资源都需要代码来处理 REST 请求并管理对象的持久存储。主 Kubernetes API 服务器处理内置资源,如 *pod* 和 *service*,并且还可以通过 CRD 通用地处理自定义资源。
聚合层允许您通过编写和部署自己的 API 服务器为自定义资源提供专门的实现。主 API 服务器将对您处理的自定义资源的请求委派给您的 API 服务器,使其可用于其所有客户端。
选择添加自定义资源的方法
CRD 更易于使用。聚合 API 更灵活。选择最适合您需求的方法。
通常,如果满足以下条件,则 CRD 是一个不错的选择
- 您只有少量字段
- 您在公司内部或作为小型开源项目的一部分使用该资源(而不是商业产品)
比较易用性
与聚合 API 相比,CRD 更容易创建。
CRD | 聚合 API |
---|---|
不需要编程。用户可以选择任何语言来编写 CRD 控制器。 | 需要编程并构建二进制文件和镜像。 |
无需运行其他服务;CRD 由 API 服务器处理。 | 需要创建且可能会失败的附加服务。 |
创建 CRD 后无需持续支持。任何错误修复都作为普通 Kubernetes Master 升级的一部分进行。 | 可能需要定期从上游获取错误修复并重新构建和更新聚合 API 服务器。 |
无需处理 API 的多个版本;例如,当您控制此资源的客户端时,可以与 API 同步升级它。 | 您需要处理 API 的多个版本;例如,当开发扩展以与世界共享时。 |
高级功能和灵活性
聚合 API 提供更高级的 API 功能和其他功能的自定义;例如,存储层。
功能 | 描述 | CRD | 聚合 API |
---|---|---|---|
验证 | 帮助用户防止错误,并允许您独立于客户端来演变 API。当有许多无法同时更新的客户端时,这些功能最有用。 | 是。大多数验证可以使用 OpenAPI v3.0 验证在 CRD 中指定。CRDValidationRatcheting 功能门允许忽略使用 OpenAPI 指定的失败验证,前提是资源的失败部分未更改。任何其他验证都支持通过添加 验证 Webhook。 | 是,任意验证检查 |
默认值 | 参见上文 | 是,可以通过 OpenAPI v3.0 验证 default 关键字(1.17 版本中 GA),或通过 变更 Webhook (尽管从 etcd 读取旧对象时不会运行)。 | 是 |
多版本控制 | 允许通过两个 API 版本提供相同的对象。可以帮助简化 API 更改,例如重命名字段。如果您控制客户端版本,则不太重要。 | 是 | 是 |
自定义存储 | 如果您需要具有不同性能模式的存储(例如,时间序列数据库而不是键值存储)或出于安全考虑进行隔离(例如,敏感信息的加密等) | 否 | 是 |
自定义业务逻辑 | 在创建、读取、更新或删除对象时执行任意检查或操作 | 是,使用 Webhook。 | 是 |
Scale 子资源 | 允许诸如 HorizontalPodAutoscaler 和 PodDisruptionBudget 之类的系统与您的新资源进行交互 | 是 | 是 |
Status 子资源 | 允许细粒度的访问控制,用户可以在其中编写 spec 部分,而控制器编写 status 部分。允许在自定义资源数据突变时增加对象生成(需要在资源中单独的 spec 和 status 部分) | 是 | 是 |
其他子资源 | 添加除 CRUD 之外的其他操作,例如“logs”或“exec”。 | 否 | 是 |
strategic-merge-patch | 新的端点支持使用 Content-Type: application/strategic-merge-patch+json 进行 PATCH。对于更新可能在本地和服务器上都被修改的对象很有用。有关更多信息,请参见 “使用 kubectl patch 就地更新 API 对象”。 | 否 | 是 |
协议缓冲区 | 新资源支持想要使用协议缓冲区的客户端 | 否 | 是 |
OpenAPI 模式 | 是否存在可以从服务器动态获取的类型的 OpenAPI (swagger) 模式?是否通过确保仅设置允许的字段来保护用户免于拼写错误字段名称?是否强制执行类型(换句话说,不要在 string 字段中放置 int )? | 是,基于 OpenAPI v3.0 验证 模式(1.16 版本中 GA)。 | 是 |
实例名称 | 此扩展机制是否对以这种方式定义的类型/资源的对象名称施加任何约束? | 是,此类对象的名称必须是有效的 DNS 子域名。 | 否 |
通用功能
当您通过 CRD 或 AA 创建自定义资源时,与在 Kubernetes 平台之外实现自定义资源相比,您将为 API 获得许多功能。
功能 | 它做什么 |
---|---|
CRUD | 新的端点支持通过 HTTP 和 kubectl 进行 CRUD 基本操作 |
Watch | 新的端点支持通过 HTTP 进行 Kubernetes Watch 操作 |
发现 | 诸如 kubectl 和仪表板之类的客户端会自动在您的资源上提供列表、显示和字段编辑操作 |
json-patch | 新的端点支持使用 Content-Type: application/json-patch+json 进行 PATCH |
merge-patch | 新的端点支持使用 Content-Type: application/merge-patch+json 进行 PATCH |
HTTPS | 新的端点使用 HTTPS |
内置身份验证 | 对扩展的访问使用核心 API 服务器(聚合层)进行身份验证 |
内置授权 | 对扩展的访问可以重用核心 API 服务器使用的授权;例如,RBAC。 |
终结器 | 阻止删除扩展资源,直到发生外部清理。 |
准入 Webhook | 在任何创建/更新/删除操作期间设置默认值并验证扩展资源。 |
UI/CLI 显示 | Kubectl,仪表板可以显示扩展资源。 |
未设置与空 | 客户端可以将未设置的字段与零值字段区分开来。 |
客户端库生成 | Kubernetes 提供通用客户端库,以及用于生成特定于类型的客户端库的工具。 |
标签和注释 | 跨对象的公共元数据,工具知道如何编辑核心资源和自定义资源。 |
准备安装自定义资源
在向集群添加自定义资源之前,需要注意以下几点。
第三方代码和新的故障点
虽然创建 CRD 不会自动添加任何新的故障点(例如,通过导致第三方代码在您的 API 服务器上运行),但软件包(例如,Chart)或其他安装包通常包含 CRD 以及实现新自定义资源业务逻辑的第三方代码的 Deployment。
安装聚合 API 服务器始终涉及运行新的 Deployment。
存储
自定义资源以与 ConfigMap 相同的方式消耗存储空间。创建过多的自定义资源可能会使 API 服务器的存储空间过载。
聚合 API 服务器可能使用与主 API 服务器相同的存储,在这种情况下,适用相同的警告。
身份验证、授权和审计
CRD 始终使用与 API 服务器的内置资源相同的身份验证、授权和审计日志记录。
如果您使用 RBAC 进行授权,则大多数 RBAC 角色将不会授予对新资源的访问权限(集群管理员角色或使用通配符规则创建的任何角色除外)。您需要显式授予对新资源的访问权限。CRD 和聚合 API 通常捆绑有他们添加的类型的新角色定义。
聚合 API 服务器可能使用也可能不使用与主 API 服务器相同的身份验证、授权和审计。
访问自定义资源
Kubernetes 客户端库 可用于访问自定义资源。并非所有客户端库都支持自定义资源。Go 和 Python 客户端库支持。
当你添加自定义资源时,可以使用以下方式访问它:
kubectl
- Kubernetes 动态客户端。
- 你编写的 REST 客户端。
- 使用 Kubernetes 客户端生成工具 生成的客户端(生成客户端是一项高级任务,但某些项目可能会随 CRD 或 AA 一起提供客户端)。
自定义资源字段选择器
字段选择器 允许客户端根据一个或多个资源字段的值选择自定义资源。
所有自定义资源都支持 metadata.name
和 metadata.namespace
字段选择器。
在 CustomResourceDefinition 中声明的字段也可以与字段选择器一起使用,当它们包含在 CustomResourceDefinition 的 spec.versions[*].selectableFields
字段中时。
自定义资源的可选字段
Kubernetes v1.32 [稳定]
(默认启用: true)CustomResourceDefinition 的 spec.versions[*].selectableFields
字段可用于声明自定义资源中哪些其他字段可以用于字段选择器。
以下示例添加了 .spec.color
和 .spec.size
字段作为可选字段。
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: shirts.stable.example.com
spec:
group: stable.example.com
scope: Namespaced
names:
plural: shirts
singular: shirt
kind: Shirt
versions:
- name: v1
served: true
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
color:
type: string
size:
type: string
selectableFields:
- jsonPath: .spec.color
- jsonPath: .spec.size
additionalPrinterColumns:
- jsonPath: .spec.color
name: Color
type: string
- jsonPath: .spec.size
name: Size
type: string
然后可以使用字段选择器来仅获取 color
为 blue
的资源
kubectl get shirts.stable.example.com --field-selector spec.color=blue
输出应为:
NAME COLOR SIZE
example1 blue S
example2 blue M
下一步
- 了解如何使用 聚合层扩展 Kubernetes API。
- 了解如何使用 CustomResourceDefinition 扩展 Kubernetes API。