自定义资源
自定义资源是 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-y(创建、读取、更新和删除)。
- 不需要跨对象的事务:API 表示期望状态,而不是确切状态。
命令式 API 不是声明式的。您的 API 可能不是声明式的迹象包括
- 客户端说“执行此操作”,然后在操作完成后立即获得同步响应。
- 客户端说“执行此操作”,然后获得一个操作 ID,并且必须检查一个单独的操作对象以确定请求是否完成。
- 您谈论的是远程过程调用 (RPC)。
- 直接存储大量数据;例如,每个对象 > 几 kB,或 > 数千个对象。
- 需要高带宽访问(持续每秒 10 次请求)。
- 存储最终用户数据(例如图像、PII 等)或应用程序处理的其他大规模数据。
- 对对象的自然操作不是 CRUD-y。
- 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 对象的名称必须是有效的 DNS 子域名。
这使您无需编写自己的 API 服务器来处理自定义资源,但实现的通用性意味着您没有 API 服务器聚合 那么灵活。
有关如何注册新的自定义资源、使用新资源类型的实例以及使用控制器处理事件的示例,请参阅 自定义控制器示例。
API 服务器聚合
通常,Kubernetes API 中的每个资源都需要代码来处理 REST 请求和管理对象的持久存储。主 Kubernetes API 服务器处理 pods 和 services 等内置资源,还可以通过 CRD 通用地处理自定义资源。
聚合层 允许您通过编写和部署自己的 API 服务器来为您的自定义资源提供专门的实现。主 API 服务器将您处理的自定义资源的请求委托给您的 API 服务器,使其可供所有客户端使用。
选择添加自定义资源的方法
CRD 更易于使用。聚合 API 更灵活。选择最能满足您需求的方法。
通常,如果符合以下情况,CRD 是一个不错的选择
- 您只有少量字段
- 您在公司内部使用该资源,或将其作为小型开源项目的一部分(而不是商业产品)
比较易用性
CRD 比聚合 API 更容易创建。
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)或通过 Mutating Webhook(尽管在从 etcd 读取旧对象时不会运行)。 | 是 |
多版本 | 允许通过两个 API 版本提供相同的对象。可以帮助简化 API 更改,例如重命名字段。如果您控制客户端版本,则不太重要。 | 是 | 是 |
自定义存储 | 如果您需要具有不同性能模式的存储(例如,时间序列数据库而不是键值存储)或出于安全目的进行隔离(例如,敏感信息的加密等) | 否 | 是 |
自定义业务逻辑 | 在创建、读取、更新或删除对象时执行任意检查或操作 | 是,使用 Webhooks。 | 是 |
规模子资源 | 允许 HorizontalPodAutoscaler 和 PodDisruptionBudget 等系统与您的新资源交互 | 是 | 是 |
状态子资源 | 允许细粒度的访问控制,用户写入规范部分,控制器写入状态部分。允许在自定义资源数据突变时增加对象生成(需要资源中单独的规范和状态部分) | 是 | 是 |
其他子资源 | 添加 CRUD 以外的操作,例如“日志”或“执行”。 | 否 | 是 |
战略合并补丁 | 新端点支持使用 Content-Type: application/strategic-merge-patch+json 进行 PATCH。对于更新可能在本地和服务器上修改的对象很有用。有关更多信息,请参阅 “使用 kubectl patch 就地更新 API 对象” | 否 | 是 |
协议缓冲区 | 新资源支持希望使用协议缓冲区的客户端 | 否 | 是 |
OpenAPI 模式 | 是否存在可以从服务器动态获取的类型的 OpenAPI(swagger)模式?是否通过确保仅设置允许的字段来保护用户不会拼错字段名称?是否强制执行类型(换句话说,不要将 int 放在 string 字段中?) | 是,基于 OpenAPI v3.0 验证 模式(1.16 版中的 GA)。 | 是 |
常见功能
与在 Kubernetes 平台之外实现 API 相比,当您通过 CRD 或 AA 创建自定义资源时,您的 API 会获得许多功能
功能 | 它的作用 |
---|---|
CRUD | 新端点通过 HTTP 和 kubectl 支持 CRUD 基本操作 |
监视 | 新端点通过 HTTP 支持 Kubernetes 监视操作 |
发现 | 像 kubectl 和仪表板这样的客户端会自动为您的资源提供列表、显示和字段编辑操作 |
json 补丁 | 新端点支持使用 Content-Type: application/json-patch+json 进行 PATCH |
合并补丁 | 新端点支持使用 Content-Type: application/merge-patch+json 进行 PATCH |
HTTPS | 新端点使用 HTTPS |
内置身份验证 | 对扩展的访问使用核心 API 服务器(聚合层)进行身份验证 |
内置授权 | 对扩展的访问可以重用核心 API 服务器使用的授权;例如,RBAC。 |
终结器 | 阻止删除扩展资源,直到完成外部清理。 |
准入 Webhook | 在任何创建/更新/删除操作期间设置默认值并验证扩展资源。 |
UI/CLI 显示 | Kubectl、仪表板可以显示扩展资源。 |
未设置与空 | 客户端可以区分未设置的字段和零值字段。 |
客户端库生成 | Kubernetes 提供通用的客户端库,以及用于生成特定于类型的客户端库的工具。 |
标签和注释 | 跨对象的通用元数据,工具知道如何为核心资源和自定义资源编辑这些元数据。 |
准备安装自定义资源
在将自定义资源添加到集群之前,需要注意以下几点。
第三方代码和新的故障点
虽然创建 CRD 不会自动添加任何新的故障点(例如,通过导致第三方代码在您的 API 服务器上运行),但包(例如,图表)或其他安装包通常包含 CRD 以及实现新自定义资源的业务逻辑的第三方代码部署。
安装聚合 API 服务器始终涉及运行新的部署。
存储
自定义资源以与 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 的 spec.versions[*].selectableFields
字段中时,在 CustomResourceDefinition 中声明的字段也可以与字段选择器一起使用。
自定义资源的可选择字段
Kubernetes v1.30 [alpha]
您需要启用 CustomResourceFieldSelectors
功能门控 才能使用此行为,然后该行为将应用于集群中的所有 CustomResourceDefinition。
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