自定义资源

自定义资源 是 Kubernetes API 的扩展。本页面讨论何时向 Kubernetes 集群添加自定义资源以及何时使用独立的(Standalone)服务。它描述了添加自定义资源的两种方法以及如何选择它们。

自定义资源

资源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,并且必须检查一个单独的操作对象以确定请求是否完成。
  • 你谈论远程过程调用 (RPC)。
  • 直接存储大量数据;例如,每个对象 > 几 KB,或 > 数千个对象。
  • 需要高带宽访问(每秒 10 次请求持续不断)。
  • 存储应用程序处理的最终用户数据(如图像、PII 等)或其他大规模数据。
  • 对对象的自然操作不是 CRUD 式的。
  • API 不容易建模为对象。
  • 你选择用操作 ID 或操作对象来表示待处理的操作。

我应该使用 ConfigMap 还是自定义资源?

如果符合以下任何条件,请使用 ConfigMap

  • 存在一个已有的、文档完善的配置文件格式,例如 mysql.cnfpom.xml
  • 你希望将整个配置放入 ConfigMap 的一个键中。
  • 配置文件主要用于在集群的 Pod 中运行的程序,以消费该文件来配置自身。
  • 文件的消费者更喜欢通过 Pod 中的文件或 Pod 中的环境变量进行消费,而不是通过 Kubernetes API。
  • 你希望在文件更新时通过 Deployment 等执行滚动更新。

如果以下大多数情况适用,请使用自定义资源(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)。

CustomResourceDefinition

CustomResourceDefinition API 资源允许你定义自定义资源。定义 CRD 对象会创建具有你指定名称和模式的新自定义资源。Kubernetes API 提供并处理自定义资源的存储。CRD 对象本身的名称必须是派生自定义的资源名称及其 API 组的有效 DNS 子域名;有关更多详细信息,请参阅 如何创建 CRD。此外,由 CRD 定义其种类/资源的对象的名称也必须是有效的 DNS 子域名。

这使你无需编写自己的 API 服务器来处理自定义资源,但实现的通用性意味着你的灵活性不如使用 API 服务器聚合

请参阅自定义控制器示例,了解如何注册新的自定义资源、使用新资源类型的实例以及使用控制器处理事件的示例。

API 服务器聚合

通常,Kubernetes API 中的每个资源都需要处理 REST 请求和管理对象持久存储的代码。主 Kubernetes API 服务器处理 podsservices 等内置资源,还可以通过 CRD 泛型处理自定义资源。

聚合层 允许你通过编写和部署自己的 API 服务器,为自定义资源提供专门的实现。主 API 服务器将请求委托给你的 API 服务器,以处理你负责的自定义资源,使其对所有客户端可用。

选择添加自定义资源的方法

CRD 更易于使用。聚合 API 更灵活。选择最符合你需求的方法。

通常,如果出现以下情况,CRD 是一个不错的选择

  • 你只有少数几个字段
  • 你正在公司内部使用该资源,或者作为小型开源项目的一部分使用(而不是商业产品)

易用性比较

CRD 比聚合 API 更容易创建。

CRD聚合 API
不需要编程。用户可以选择任何语言来编写 CRD 控制器。需要编程和构建二进制文件和镜像。
无需额外服务运行;CRD 由 API 服务器处理。需要创建可能失败的额外服务。
CRD 创建后无需持续支持。任何 Bug 修复都作为正常的 Kubernetes 主版本升级的一部分进行。可能需要定期从上游获取 Bug 修复,并重建和更新聚合 API 服务器。
无需处理 API 的多个版本;例如,当您控制此资源的客户端时,可以与 API 同步升级它。你需要处理 API 的多个版本;例如,当你开发一个要与世界共享的扩展时。

高级功能和灵活性

聚合 API 提供更高级的 API 功能和对其他功能(例如存储层)的自定义。

特性描述CRD聚合 API
验证帮助用户防止错误,并允许你独立于客户端演进你的 API。这些功能在许多客户端无法同时更新时最有用。是。大多数验证可以在 CRD 中使用 OpenAPI v3.0 验证 来指定。CRDValidationRatcheting 功能门允许在资源失败部分未更改的情况下,也可以忽略使用 OpenAPI 指定的失败验证。通过添加 Validating Webhook 支持任何其他验证。是,任意验证检查
默认值见上文是的,可以通过 OpenAPI v3.0 验证 default 关键字(1.17 GA),或者通过 Mutating Webhook(尽管当从 etcd 读取旧对象时不会运行此操作)。
多版本控制允许通过两个 API 版本提供相同的对象。可以帮助简化 API 更改,例如字段重命名。如果您控制客户端版本,则不那么重要。
自定义存储如果您需要不同性能模式的存储(例如,时间序列数据库而不是键值存储)或为了安全进行隔离(例如,敏感信息加密等)
自定义业务逻辑在创建、读取、更新或删除对象时执行任意检查或操作是的,使用 Webhooks
扩缩子资源允许 HorizontalPodAutoscaler 和 PodDisruptionBudget 等系统与你的新资源交互
状态子资源允许细粒度访问控制,用户可以编写 spec 部分,控制器可以编写 status 部分。允许在自定义资源数据变动时递增对象 Generation(要求资源中包含独立的 spec 和 status 部分)
其他子资源添加除了 CRUD 之外的操作,例如“logs”或“exec”。
战略合并补丁新端点支持带有 Content-Type: application/strategic-merge-patch+json 的 PATCH。对于更新可能在本地和服务器上都已修改的对象很有用。更多信息,请参阅 “使用 kubectl patch 就地更新 API 对象”
Protocol Buffers新资源支持想要使用 Protocol Buffers 的客户端
OpenAPI Schema是否存在一个 OpenAPI (swagger) 模式,可以从服务器动态获取类型?是否通过确保只设置允许的字段来保护用户免于拼写错误的字段名?是否强制执行类型(换句话说,不要将 int 放入 string 字段)?是,基于 OpenAPI v3.0 验证 模式 (1.16 GA)。
实例名称此扩展机制是否对以这种方式定义的种类/资源的对象名称施加任何限制?是的,这类对象的名称必须是有效的 DNS 子域名。

常见功能

与在 Kubernetes 平台之外实现 API 相比,通过 CRD 或 AA 创建自定义资源,你的 API 可以获得许多功能

特性作用
CRUD新端点支持通过 HTTP 和 kubectl 进行 CRUD 基本操作。
Watch新端点通过 HTTP 支持 Kubernetes Watch 操作。
发现kubectl 和仪表盘等客户端会自动对你的资源提供列表、显示和字段编辑操作。
json-patch新端点支持带有 Content-Type: application/json-patch+json 的 PATCH。
合并补丁新端点支持带有 Content-Type: application/merge-patch+json 的 PATCH。
HTTPS新端点使用 HTTPS
内置认证访问扩展使用核心 API 服务器(聚合层)进行认证
内置授权访问扩展可以重用核心 API 服务器使用的授权;例如 RBAC。
终结器阻止删除扩展资源,直到外部清理完成。
Admission Webhook在任何创建/更新/删除操作期间设置默认值并验证扩展资源。
UI/CLI 显示Kubectl、仪表盘可以显示扩展资源。
未设置与空值客户端可以将未设置的字段与零值字段区分开来。
客户端库生成Kubernetes 提供通用客户端库,以及生成特定类型客户端库的工具。
标签和注解工具知道如何为核心和自定义资源编辑的常见对象元数据。

准备安装自定义资源

在向集群添加自定义资源之前,有几点需要注意。

第三方代码和新的故障点

虽然创建 CRD 不会自动添加任何新的故障点(例如,通过导致第三方代码在你的 API 服务器上运行),但包(例如,Charts)或其他安装包通常包括 CRD 以及实现新自定义资源业务逻辑的第三方代码的 Deployment。

安装聚合 API 服务器总是涉及运行新的 Deployment。

存储

自定义资源会像 ConfigMap 一样占用存储空间。创建过多的自定义资源可能会使 API 服务器的存储空间过载。

聚合 API 服务器可能会使用与主 API 服务器相同的存储,在这种情况下,同样的警告也适用。

身份认证、授权和审计

CRD 总是使用与 API 服务器内置资源相同的身份认证、授权和审计日志。

如果你使用 RBAC 进行授权,大多数 RBAC 角色将不会授予对新资源的访问权限(除了 cluster-admin 角色或任何使用通配符规则创建的角色)。你需要明确授予对新资源的访问权限。CRD 和聚合 API 通常捆绑了它们添加的类型的新角色定义。

聚合 API 服务器可能会或可能不会使用与主 API 服务器相同的身份认证、授权和审计。

访问自定义资源

Kubernetes 客户端库 可用于访问自定义资源。并非所有客户端库都支持自定义资源。GoPython 客户端库支持。

添加自定义资源后,你可以使用以下方式访问它

  • kubectl
  • Kubernetes 动态客户端。
  • 你编写的 REST 客户端。
  • 使用 Kubernetes 客户端生成工具 生成的客户端(生成客户端是一项高级任务,但某些项目可能会随 CRD 或 AA 提供客户端)。

自定义资源字段选择器

字段选择器 允许客户端根据一个或多个资源字段的值选择自定义资源。

所有自定义资源都支持 metadata.namemetadata.namespace 字段选择器。

CustomResourceDefinition 中声明的字段也可以与字段选择器一起使用,当它们包含在 CustomResourceDefinitionspec.versions[*].selectableFields 字段中时。

自定义资源的可选字段

特性状态: Kubernetes v1.32 [stable] (默认启用:true)

CustomResourceDefinitionspec.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

然后可以使用字段选择器仅获取 colorblue 的资源

kubectl get shirts.stable.example.com --field-selector spec.color=blue

输出应该是

NAME       COLOR  SIZE
example1   blue   S
example2   blue   M

下一步

最后修改于 2024 年 10 月 31 日太平洋标准时间上午 10:47:删除稳定功能的字段门信息,为字段选择器文档添加详细信息 (2b996e4434)