使用 CustomResourceDefinitions 扩展 Kubernetes API

此页面展示了如何通过创建 CustomResourceDefinition自定义资源 安装到 Kubernetes API 中。

开始之前

您需要拥有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。建议在至少有两个节点(不充当控制平面主机)的集群上运行本教程。如果您还没有集群,可以使用 minikube 创建一个,或者可以使用以下 Kubernetes 游乐场之一

您的 Kubernetes 服务器必须是 1.16 或更高版本。要检查版本,请输入 kubectl version。如果您使用的是仍然受支持的旧版本 Kubernetes,请切换到该版本的文档以查看与您的集群相关的建议。

创建 CustomResourceDefinition

当您创建新的 CustomResourceDefinition (CRD) 时,Kubernetes API 服务器会为您指定的每个版本创建一个新的 RESTful 资源路径。从 CRD 对象创建的自定义资源可以是命名空间范围的,也可以是集群范围的,具体取决于 CRD 的 spec.scope 字段中指定的范围。与现有的内置对象一样,删除命名空间会删除该命名空间中的所有自定义对象。CustomResourceDefinitions 本身是非命名空间的,对所有命名空间都可用。

例如,如果您将以下 CustomResourceDefinition 保存到 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  # name must match the spec fields below, and be in the form: <plural>.<group>
  name: crontabs.stable.example.com
spec:
  # group name to use for REST API: /apis/<group>/<version>
  group: stable.example.com
  # list of versions supported by this CustomResourceDefinition
  versions:
    - name: v1
      # Each version can be enabled/disabled by Served flag.
      served: true
      # One and only one version must be marked as the storage version.
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                image:
                  type: string
                replicas:
                  type: integer
  # either Namespaced or Cluster
  scope: Namespaced
  names:
    # plural name to be used in the URL: /apis/<group>/<version>/<plural>
    plural: crontabs
    # singular name to be used as an alias on the CLI and for display
    singular: crontab
    # kind is normally the CamelCased singular type. Your resource manifests use this.
    kind: CronTab
    # shortNames allow shorter string to match your resource on the CLI
    shortNames:
    - ct

并创建它

kubectl apply -f resourcedefinition.yaml

那么,将在以下位置创建一个新的命名空间 RESTful API 端点:

/apis/stable.example.com/v1/namespaces/*/crontabs/...

然后,可以使用此端点 URL 来创建和管理自定义对象。这些对象的 kind 将是 CronTab,来自您上面创建的 CustomResourceDefinition 对象的规范。

端点可能需要几秒钟才能创建。您可以观察 CustomResourceDefinition 的 Established 条件是否为真,或者观察 API 服务器的发现信息以查看您的资源是否出现。

创建自定义对象

创建 CustomResourceDefinition 对象后,您可以创建自定义对象。自定义对象可以包含自定义字段。这些字段可以包含任意 JSON。在以下示例中,cronSpecimage 自定义字段在 CronTab 类型的自定义对象中设置。CronTab 类型的 kind 来自您上面创建的 CustomResourceDefinition 对象的规范。

如果您将以下 YAML 保存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image

并创建它

kubectl apply -f my-crontab.yaml

然后,您可以使用 kubectl 管理您的 CronTab 对象。例如

kubectl get crontab

应该打印类似以下内容的列表

NAME                 AGE
my-new-cron-object   6s

使用 kubectl 时,资源名称不区分大小写,您可以使用 CRD 中定义的单数或复数形式,以及任何简短名称。

您还可以查看原始 YAML 数据

kubectl get ct -o yaml

您应该看到它包含您用来创建它的 YAML 中的自定义 cronSpecimage 字段

apiVersion: v1
items:
- apiVersion: stable.example.com/v1
  kind: CronTab
  metadata:
    annotations:
      kubectl.kubernetes.io/last-applied-configuration: |
        {"apiVersion":"stable.example.com/v1","kind":"CronTab","metadata":{"annotations":{},"name":"my-new-cron-object","namespace":"default"},"spec":{"cronSpec":"* * * * */5","image":"my-awesome-cron-image"}}        
    creationTimestamp: "2021-06-20T07:35:27Z"
    generation: 1
    name: my-new-cron-object
    namespace: default
    resourceVersion: "1326"
    uid: 9aab1d66-628e-41bb-a422-57b8b3b1f5a9
  spec:
    cronSpec: '* * * * */5'
    image: my-awesome-cron-image
kind: List
metadata:
  resourceVersion: ""
  selfLink: ""

删除 CustomResourceDefinition

当您删除 CustomResourceDefinition 时,服务器将卸载 RESTful API 端点并删除存储在其中的所有自定义对象。

kubectl delete -f resourcedefinition.yaml
kubectl get crontabs
Error from server (NotFound): Unable to list {"stable.example.com" "v1" "crontabs"}: the server could not
find the requested resource (get crontabs.stable.example.com)

如果您稍后重新创建相同的 CustomResourceDefinition,它将从空状态开始。

指定结构化模式

CustomResources 在自定义字段中存储结构化数据(以及 API 服务器隐式验证的内置字段 apiVersionkindmetadata)。使用 OpenAPI v3.0 验证 可以指定模式,该模式将在创建和更新期间进行验证,请参阅以下内容以了解此类模式的详细信息和限制。

使用 apiextensions.k8s.io/v1,结构化模式的定义对于 CustomResourceDefinitions 是强制性的。在 CustomResourceDefinition 的 beta 版本中,结构化模式是可选的。

结构化模式是 OpenAPI v3.0 验证模式,它

  1. 为根指定非空类型(通过 OpenAPI 中的 type),为对象节点的每个指定字段(通过 OpenAPI 中的 propertiesadditionalProperties)和为数组节点中的每个项目(通过 OpenAPI 中的 items)指定非空类型,但以下情况除外:
    • 具有 x-kubernetes-int-or-string: true 的节点
    • 具有 x-kubernetes-preserve-unknown-fields: true 的节点
  2. 对于在任何 allOfanyOfoneOfnot 中指定的每个对象字段和每个数组项目,模式还在这些逻辑连接符之外指定字段/项目(比较示例 1 和 2)。
  3. 不设置 allOfanyOfoneOfnot 中的 descriptiontypedefaultadditionalPropertiesnullable,但以下两种模式除外:x-kubernetes-int-or-string: true(见下文)。
  4. 如果指定了 metadata,则只允许对 metadata.namemetadata.generateName 进行限制。

非结构化示例 1

allOf:
- properties:
    foo:
      ...

与规则 2 冲突。以下将是正确的

properties:
  foo:
    ...
allOf:
- properties:
    foo:
      ...

非结构化示例 2

allOf:
- items:
    properties:
      foo:
        ...

与规则 2 冲突。以下将是正确的

items:
  properties:
    foo:
      ...
allOf:
- items:
    properties:
      foo:
        ...

非结构化示例 3

properties:
  foo:
    pattern: "abc"
  metadata:
    type: object
    properties:
      name:
        type: string
        pattern: "^a"
      finalizers:
        type: array
        items:
          type: string
          pattern: "my-finalizer"
anyOf:
- properties:
    bar:
      type: integer
      minimum: 42
  required: ["bar"]
  description: "foo bar object"

不是结构化模式,因为它违反了以下规则:

  • 根处的类型缺失(规则 1)。
  • foo 的类型缺失(规则 1)。
  • anyOf 中的 bar 未在外部指定(规则 2)。
  • bartypeanyOf 中(规则 3)。
  • descriptionanyOf 中设置(规则 3)。
  • metadata.finalizers 可能不受限制(规则 4)。

相反,以下相应的模式是结构化的

type: object
description: "foo bar object"
properties:
  foo:
    type: string
    pattern: "abc"
  bar:
    type: integer
  metadata:
    type: object
    properties:
      name:
        type: string
        pattern: "^a"
anyOf:
- properties:
    bar:
      minimum: 42
  required: ["bar"]

结构化模式规则的违规行为将在 CustomResourceDefinition 的 NonStructural 条件中报告。

字段修剪

CustomResourceDefinitions 将经过验证的资源数据存储在集群的持久性存储中,即 etcd。与本机 Kubernetes 资源(如 ConfigMap)一样,如果您指定 API 服务器无法识别的字段,则该未知字段将在持久化之前被修剪(删除)。

apiextensions.k8s.io/v1beta1 转换为 apiextensions.k8s.io/v1 的 CRD 可能缺少结构化模式,并且 spec.preserveUnknownFields 可能为 true

对于作为 apiextensions.k8s.io/v1beta1 创建的旧版 CustomResourceDefinition 对象,其 spec.preserveUnknownFields 设置为 true,以下也适用:

  • 修剪未启用。
  • 您可以存储任意数据。

为了与 apiextensions.k8s.io/v1 兼容,请更新您的自定义资源定义以:

  1. 使用结构化 OpenAPI 模式。
  2. spec.preserveUnknownFields 设置为 false

如果您将以下 YAML 保存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image
  someRandomField: 42

并创建它

kubectl create --validate=false -f my-crontab.yaml -o yaml

您的输出类似于

apiVersion: stable.example.com/v1
kind: CronTab
metadata:
  creationTimestamp: 2017-05-31T12:56:35Z
  generation: 1
  name: my-new-cron-object
  namespace: default
  resourceVersion: "285"
  uid: 9423255b-4600-11e7-af6a-28d2447dc82b
spec:
  cronSpec: '* * * * */5'
  image: my-awesome-cron-image

请注意,someRandomField 字段已被修剪。

此示例通过添加 --validate=false 命令行选项来关闭客户端验证,以演示 API 服务器的行为。由于 OpenAPI 验证模式也发布 给客户端,因此 kubectl 也会检查未知字段,并在这些对象发送到 API 服务器之前拒绝它们。

控制修剪

默认情况下,所有版本中自定义资源的所有未指定字段都会被修剪。但是,可以通过在 结构化 OpenAPI v3 验证模式 中添加 x-kubernetes-preserve-unknown-fields: true 来选择退出特定字段子树的修剪。

例如

type: object
properties:
  json:
    x-kubernetes-preserve-unknown-fields: true

json 字段可以存储任何 JSON 值,而不会被修剪。

您还可以部分指定允许的 JSON;例如

type: object
properties:
  json:
    x-kubernetes-preserve-unknown-fields: true
    type: object
    description: this is arbitrary JSON

这样,只允许 object 类型的 value。

对于每个指定的属性(或 additionalProperties),修剪将再次启用

type: object
properties:
  json:
    x-kubernetes-preserve-unknown-fields: true
    type: object
    properties:
      spec:
        type: object
        properties:
          foo:
            type: string
          bar:
            type: string

这样,value

json:
  spec:
    foo: abc
    bar: def
    something: x
  status:
    something: x

将被修剪为

json:
  spec:
    foo: abc
    bar: def
  status:
    something: x

这意味着,指定 spec 对象中的 something 字段将被修剪,但外部的所有内容都不会被修剪。

IntOrString

模式中具有 x-kubernetes-int-or-string: true 的节点将被排除在规则 1 之外,因此以下内容是结构化的

type: object
properties:
  foo:
    x-kubernetes-int-or-string: true

这些节点还部分被排除在规则 3 之外,因为允许以下两种模式(完全相同,没有顺序变化以添加其他字段)

x-kubernetes-int-or-string: true
anyOf:
  - type: integer
  - type: string
...

x-kubernetes-int-or-string: true
allOf:
  - anyOf:
      - type: integer
      - type: string
  - ... # zero or more
...

使用其中一个规范,整数和字符串都将验证。

验证模式发布 中,x-kubernetes-int-or-string: true 将展开为上面显示的两种模式之一。

RawExtension

RawExtensions(如 runtime.RawExtension)保存完整的 Kubernetes 对象,即包含 apiVersionkind 字段的 Kubernetes 对象。

可以通过设置 x-kubernetes-embedded-resource: true 来指定这些嵌入式对象(既可以完全无约束地指定,也可以部分指定)。例如

type: object
properties:
  foo:
    x-kubernetes-embedded-resource: true
    x-kubernetes-preserve-unknown-fields: true

这里,foo 字段保存一个完整的对象,例如:

foo:
  apiVersion: v1
  kind: Pod
  spec:
    ...

由于同时指定了 x-kubernetes-preserve-unknown-fields: true,因此不会进行任何修剪。不过,使用 x-kubernetes-preserve-unknown-fields: true 是可选的。

使用 x-kubernetes-embedded-resource: true 时,apiVersionkindmetadata 会被隐式指定并验证。

提供 CRD 的多个版本

有关提供 CustomResourceDefinition 的多个版本以及将对象从一个版本迁移到另一个版本的更多信息,请参阅 CustomResourceDefinition 版本控制

高级主题

终结器

终结器 允许控制器实现异步预删除钩子。自定义对象支持与内置对象类似的终结器。

您可以像这样向自定义对象添加终结器

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  finalizers:
  - stable.example.com/finalizer

自定义终结器的标识符由域名、正斜杠和终结器名称组成。任何控制器都可以向任何对象的终结器列表中添加终结器。

对具有终结器的对象的第一个删除请求将为 metadata.deletionTimestamp 字段设置一个值,但不会删除它。一旦设置了此值,finalizers 列表中的条目就只能被删除。只要存在任何终结器,就无法强制删除对象。

metadata.deletionTimestamp 字段被设置时,监视该对象的控制器将执行它们处理的任何终结器,并在完成后从列表中删除该终结器。每个控制器都有责任从列表中删除其终结器。

metadata.deletionGracePeriodSeconds 的值控制轮询更新之间的间隔。

一旦终结器列表为空,表示所有终结器都已执行,Kubernetes 将删除该资源。

验证

自定义资源通过 OpenAPI v3 架构 进行验证,当 验证规则功能 启用时,通过 x-kubernetes-validations 进行验证,并且您可以使用 准入 Webhook 添加额外的验证。

此外,以下限制适用于架构

  • 这些字段不能设置

    • definitions,
    • dependencies,
    • deprecated,
    • discriminator,
    • id,
    • patternProperties,
    • readOnly,
    • writeOnly,
    • xml,
    • $ref.
  • 字段 uniqueItems 不能设置为 true

  • 字段 additionalProperties 不能设置为 false

  • 字段 additionalPropertiesproperties 互斥。

验证规则 功能启用且 CustomResourceDefinition 架构为 结构化架构 时,可以使用 x-kubernetes-validations 扩展使用 通用表达式语言 (CEL) 表达式来验证自定义资源。

有关其他限制和 CustomResourceDefinition 功能,请参阅 结构化架构 部分。

架构在 CustomResourceDefinition 中定义。在以下示例中,CustomResourceDefinition 对自定义对象应用以下验证

  • spec.cronSpec 必须是字符串,并且必须符合正则表达式描述的格式。
  • spec.replicas 必须是整数,并且必须具有最小值为 1 和最大值为 10。

将 CustomResourceDefinition 保存到 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        # openAPIV3Schema is the schema for validating custom objects.
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                  pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
                image:
                  type: string
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 10
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct

并创建它

kubectl apply -f resourcedefinition.yaml

如果其字段中存在无效值,则拒绝创建类型为 CronTab 的自定义对象的请求。在以下示例中,自定义对象包含具有无效值的字段

  • spec.cronSpec 不匹配正则表达式。
  • spec.replicas 大于 10。

如果您将以下 YAML 保存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * *"
  image: my-awesome-cron-image
  replicas: 15

并尝试创建它

kubectl apply -f my-crontab.yaml

然后你会收到错误

The CronTab "my-new-cron-object" is invalid: []: Invalid value: map[string]interface {}{"apiVersion":"stable.example.com/v1", "kind":"CronTab", "metadata":map[string]interface {}{"name":"my-new-cron-object", "namespace":"default", "deletionTimestamp":interface {}(nil), "deletionGracePeriodSeconds":(*int64)(nil), "creationTimestamp":"2017-09-05T05:20:07Z", "uid":"e14d79e7-91f9-11e7-a598-f0761cb232d1", "clusterName":""}, "spec":map[string]interface {}{"cronSpec":"* * * *", "image":"my-awesome-cron-image", "replicas":15}}:
validation failure list:
spec.cronSpec in body should match '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
spec.replicas in body should be less than or equal to 10

如果字段包含有效值,则对象创建请求将被接受。

将以下 YAML 保存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image
  replicas: 5

并创建它

kubectl apply -f my-crontab.yaml
crontab "my-new-cron-object" created

验证棘轮

功能状态: Kubernetes v1.30 [beta]

如果您使用的是早于 v1.30 的 Kubernetes 版本,则需要显式启用 CRDValidationRatcheting 功能开关 才能使用此行为,该行为随后将应用于集群中的所有 CustomResourceDefinition。

如果您启用了功能开关,Kubernetes 将为 CustomResourceDefinition 实现验证棘轮。API 服务器愿意接受对更新后无效的资源的更新,前提是更新操作未更改资源中每个未通过验证的部分。换句话说,资源中任何保持无效的部分必须已经错误。您不能使用此机制来更新有效资源,使其变为无效。

此功能允许 CRD 的作者在某些条件下自信地将新的验证添加到 OpenAPIV3 架构中。用户可以安全地更新到新架构,而无需更改对象的版本或破坏工作流程。

虽然 OpenAPIV3 架构中放置的大多数验证都支持棘轮,但也有一些例外。以下 OpenAPIV3 架构验证不受 Kubernetes 1.30 中实现的棘轮支持,如果违反,将继续像往常一样抛出错误

  • 量词

    • allOf
    • oneOf
    • anyOf
    • not
    • 这些字段的任何后代中的任何验证
  • x-kubernetes-validations 对于 Kubernetes 1.28,CRD 验证规则](#validation-rules) 被棘轮忽略。从 Kubernetes 1.29 的 Alpha 2 开始,x-kubernetes-validations 仅在不引用 oldSelf 时才被棘轮。

    转换规则永远不会被棘轮:只有不使用 oldSelf 的规则引发的错误,如果其值保持不变,将被自动棘轮。

    要为 CEL 表达式编写自定义棘轮逻辑,请查看 optionalOldSelf

  • x-kubernetes-list-type 由于更改子架构的列表类型而产生的错误不会被棘轮。例如,在具有重复项的列表上添加 set 将始终导致错误。

  • x-kubernetes-map-keys 由于更改列表架构的映射键而产生的错误不会被棘轮。

  • required 由于更改必需字段列表而产生的错误不会被棘轮。

  • properties 添加/删除/修改属性的名称不会被棘轮,但如果属性的名称保持不变,则每个属性的架构和子架构中的验证更改可能会被棘轮。

  • additionalProperties 删除先前指定的 additionalProperties 验证不会被棘轮。

  • metadata 来自 Kubernetes 对对象 metadata 的内置验证的错误不会被棘轮(例如对象名称或标签值中的字符)。如果您为自定义资源的元数据指定了自己的额外规则,则该额外验证将被棘轮。

验证规则

功能状态: Kubernetes v1.29 [稳定]

验证规则使用 通用表达式语言 (CEL) 来验证自定义资源值。验证规则使用 x-kubernetes-validations 扩展包含在 CustomResourceDefinition 架构中。

规则的范围限定为架构中 x-kubernetes-validations 扩展的位置。CEL 表达式中的 self 变量绑定到范围限定的值。

所有验证规则的范围都限定为当前对象:不支持跨对象或有状态验证规则。

例如

  ...
  openAPIV3Schema:
    type: object
    properties:
      spec:
        type: object
        x-kubernetes-validations:
          - rule: "self.minReplicas <= self.replicas"
            message: "replicas should be greater than or equal to minReplicas."
          - rule: "self.replicas <= self.maxReplicas"
            message: "replicas should be smaller than or equal to maxReplicas."
        properties:
          ...
          minReplicas:
            type: integer
          replicas:
            type: integer
          maxReplicas:
            type: integer
        required:
          - minReplicas
          - replicas
          - maxReplicas

将拒绝创建此自定义资源的请求

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  minReplicas: 0
  replicas: 20
  maxReplicas: 10

响应为

The CronTab "my-new-cron-object" is invalid:
* spec: Invalid value: map[string]interface {}{"maxReplicas":10, "minReplicas":0, "replicas":20}: replicas should be smaller than or equal to maxReplicas.

x-kubernetes-validations 可以具有多个规则。x-kubernetes-validations 下的 rule 表示将由 CEL 评估的表达式。message 表示验证失败时显示的消息。如果消息未设置,则上述响应将为

The CronTab "my-new-cron-object" is invalid:
* spec: Invalid value: map[string]interface {}{"maxReplicas":10, "minReplicas":0, "replicas":20}: failed rule: self.replicas <= self.maxReplicas

验证规则在创建/更新 CRD 时进行编译。如果验证规则的编译失败,则 CRD 创建/更新的请求将失败。编译过程包括类型检查。

编译失败

  • no_matching_overload:此函数没有针对参数类型的重载。

    例如,针对整数类型字段的规则 self == true 将出现错误

    Invalid value: apiextensions.ValidationRule{Rule:"self == true", Message:""}: compilation failed: ERROR: \<input>:1:6: found no matching overload for '_==_' applied to '(int, bool)'
    
  • no_such_field:不包含所需字段。

    例如,针对不存在的字段的规则 self.nonExistingField > 0 将返回以下错误

    Invalid value: apiextensions.ValidationRule{Rule:"self.nonExistingField > 0", Message:""}: compilation failed: ERROR: \<input>:1:5: undefined field 'nonExistingField'
    
  • invalid argument:宏的无效参数。

    例如,规则 has(self) 将返回错误

    Invalid value: apiextensions.ValidationRule{Rule:"has(self)", Message:""}: compilation failed: ERROR: <input>:1:4: invalid argument to has() macro
    

验证规则示例

规则目的
self.minReplicas <= self.replicas && self.replicas <= self.maxReplicas验证定义副本的三个字段是否按适当顺序排列
'Available' in self.stateCounts验证映射中是否存在具有 'Available' 键的条目
(size(self.list1) == 0) != (size(self.list2) == 0)验证两个列表中只有一个是非空的,但不能同时为空
!('MY_KEY' in self.map1) || self['MY_KEY'].matches('^[a-zA-Z]*$')验证映射中特定键的值(如果该键存在于映射中)
self.envars.filter(e, e.name == 'MY_ENV').all(e, e.value.matches('^[a-zA-Z]*$')验证键字段 'name' 为 'MY_ENV' 的列表映射条目的 'value' 字段
has(self.expired) && self.created + self.ttl < self.expired验证 'expired' 日期是否在 'create' 日期加上 'ttl' 持续时间之后
self.health.startsWith('ok')验证 'health' 字符串字段是否具有前缀 'ok'
self.widgets.exists(w, w.key == 'x' && w.foo < 10)验证键为 'x' 的列表映射项的 'foo' 属性是否小于 10
type(self) == string ? self == '100%' : self == 1000验证整数或字符串字段的整数和字符串情况
self.metadata.name.startsWith(self.prefix)验证对象的名称是否具有另一个字段值的开头
self.set1.all(e, !(e in self.set2))验证两个列表集是否是不相交的
size(self.names) == size(self.details) && self.names.all(n, n in self.details)验证 'details' 映射是否以 'names' 列表集中的项目为键
size(self.clusters.filter(c, c.name == self.primary)) == 1验证 'primary' 属性在 'clusters' 列表映射中是否只出现一次

交叉引用:CEL 上支持的评估

  • 如果规则的范围限定为资源的根目录,则它可以进行字段选择,选择 CRD 的 OpenAPIv3 架构中声明的任何字段,以及 apiVersionkindmetadata.namemetadata.generateName。这包括在同一个表达式中选择 specstatus 中的字段

      ...
      openAPIV3Schema:
        type: object
        x-kubernetes-validations:
          - rule: "self.status.availableReplicas >= self.spec.minReplicas"
        properties:
            spec:
              type: object
              properties:
                minReplicas:
                  type: integer
                ...
            status:
              type: object
              properties:
                availableReplicas:
                  type: integer
    
  • 如果规则的范围限定为具有属性的对象,则可以通过 self.field 选择对象的属性,并且可以通过 has(self.field) 检查字段是否存在。在 CEL 表达式中,空值字段被视为不存在的字段。

      ...
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            x-kubernetes-validations:
              - rule: "has(self.foo)"
            properties:
              ...
              foo:
                type: integer
    
  • 如果规则的范围限定为具有 additionalProperties(即映射)的对象,则可以通过 self[mapKey] 访问映射的值,可以通过 mapKey in self 检查映射包含关系,并且可以通过 CEL 宏和函数(例如 self.all(...))访问映射的所有条目。

      ...
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            x-kubernetes-validations:
              - rule: "self['xyz'].foo > 0"
            additionalProperties:
              ...
              type: object
              properties:
                foo:
                  type: integer
    
  • 如果规则的范围限定为数组,则可以通过 self[i] 以及宏和函数访问数组的元素。

      ...
      openAPIV3Schema:
        type: object
        properties:
          ...
          foo:
            type: array
            x-kubernetes-validations:
              - rule: "size(self) == 1"
            items:
              type: string
    
  • 如果规则的范围限定为标量,则 self 绑定到标量值。

      ...
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              ...
              foo:
                type: integer
                x-kubernetes-validations:
                - rule: "self > 0"
    

示例

字段规则范围限定的类型规则示例
根对象self.status.actual <= self.spec.maxDesired
对象映射self.components['Widget'].priority < 10
整数列表self.values.all(value, value >= 0 && value < 100)
字符串self.startsWith('kube')

apiVersionkindmetadata.namemetadata.generateName 始终可从对象的根目录和任何带有 x-kubernetes-embedded-resource 注释的对象访问。其他元数据属性不可访问。

通过 x-kubernetes-preserve-unknown-fields 保存在自定义资源中的未知数据在 CEL 表达式中不可访问。这包括

  • 通过带有 x-kubernetes-preserve-unknown-fields 的对象模式保留的未知字段值。

  • 属性模式为“未知类型”的对象属性。“未知类型”递归定义为

    • 没有类型且 x-kubernetes-preserve-unknown-fields 设置为 true 的模式
    • 项目模式为“未知类型”的数组
    • additionalProperties 模式为“未知类型”的对象

只有 [a-zA-Z_.-/][a-zA-Z0-9_.-/]* 形式的属性名称可访问。在表达式中访问时,可访问的属性名称将根据以下规则进行转义

转义序列属性名称等效
__underscores____
__dot__.
__dash__-
__slash__/
__{keyword}__CEL 保留关键字

注意:CEL 保留关键字需要与要转义的精确属性名称匹配(例如,单词 sprint 中的 int 不会被转义)。

转义示例

属性名称带有转义属性名称的规则
namespaceself.__namespace__ > 0
x-propself.x__dash__prop > 0
redact__dself.redact__underscores__d > 0
字符串self.startsWith('kube')

带有 x-kubernetes-list-typesetmap 的数组的相等性忽略元素顺序,即 [1, 2] == [2, 1]。带有 x-kubernetes-list-type 的数组的串联使用列表类型的语义

  • setX + Y 执行一个联合,其中保留 X 中所有元素的数组位置,并将 Y 中的非相交元素追加,保留其部分顺序。

  • mapX + Y 执行一个合并,其中保留 X 中所有键的数组位置,但当 XY 的键集相交时,值会被 Y 中的值覆盖。Y 中具有非相交键的元素将被追加,保留其部分顺序。

以下是 OpenAPIv3 与 CEL 类型之间的声明类型映射

OpenAPIv3 类型CEL 类型
'object' with Propertiesobject / "message type"
'object' with AdditionalPropertiesmap
'object' with x-kubernetes-embedded-typeobject / "message type",'apiVersion'、'kind'、'metadata.name' 和 'metadata.generateName' 隐式包含在模式中
'object' with x-kubernetes-preserve-unknown-fieldsobject / "message type",未知字段在 CEL 表达式中不可访问
x-kubernetes-int-or-string动态对象,可以是 int 或 string,type(value) 可用于检查类型
'arraylist
'array' with x-kubernetes-list-type=map具有基于 map 的相等性和唯一键保证的列表
'array' with x-kubernetes-list-type=set具有基于 set 的相等性和唯一条目保证的列表
'boolean'boolean
'number' (all formats)double
'integer' (all formats)int (64)
'null'null_type
'string'字符串
'string' with format=byte (base64 encoded)bytes
'string' with format=datetimestamp (google.protobuf.Timestamp)
'string' with format=datetimetimestamp (google.protobuf.Timestamp)
'string' with format=durationduration (google.protobuf.Duration)

交叉引用:CEL 类型OpenAPI 类型Kubernetes 结构模式

messageExpression 字段

类似于 message 字段,它定义了验证规则失败时报告的字符串,messageExpression 允许您使用 CEL 表达式来构建消息字符串。这使您能够将更具描述性的信息插入验证失败消息中。messageExpression 必须计算一个字符串,并且可以使用与 rule 字段可用的相同变量。例如

x-kubernetes-validations:
- rule: "self.x <= self.maxLimit"
  messageExpression: '"x exceeded max limit of " + string(self.maxLimit)'

请记住,CEL 字符串串联(+ 运算符)不会自动转换为字符串。如果您有一个非字符串标量,请使用 string(<value>) 函数将标量转换为字符串,如上面的示例所示。

messageExpression 必须计算为字符串,并在写入 CRD 时进行检查。请注意,可以在同一规则上设置 messagemessageExpression,如果两者都存在,则将使用 messageExpression。但是,如果 messageExpression 计算为错误,则将使用 message 中定义的字符串,并且 messageExpression 错误将被记录。如果 messageExpression 中定义的 CEL 表达式生成空字符串或包含换行的字符串,也会发生此回退。

如果满足上述条件之一且未设置 message,则将使用默认的验证失败消息。

messageExpression 是一个 CEL 表达式,因此 验证函数的资源使用 中列出的限制适用。如果在 messageExpression 执行期间由于资源限制而导致评估停止,则不会执行任何其他验证规则。

设置 messageExpression 是可选的。

message 字段

如果您想设置静态消息,可以提供 message 而不是 messageExpression。如果验证失败,message 的值将用作不透明的错误字符串。

设置 message 是可选的。

reason 字段

您可以在 validation 中添加一个机器可读的验证失败原因,以便在请求失败此验证规则时返回。

例如

x-kubernetes-validations:
- rule: "self.x <= self.maxLimit"
  reason: "FieldValueInvalid"

返回给调用者的 HTTP 状态代码将与第一个失败的验证规则的原因匹配。当前支持的原因是:“FieldValueInvalid”、“FieldValueForbidden”、“FieldValueRequired”、“FieldValueDuplicate”。如果未设置或未知原因,则默认使用“FieldValueInvalid”。

设置 reason 是可选的。

fieldPath 字段

您可以指定验证失败时返回的字段路径。

例如

x-kubernetes-validations:
- rule: "self.foo.test.x <= self.maxLimit"
  fieldPath: ".foo.test.x"

在上面的示例中,验证检查字段 x 的值是否小于 maxLimit 的值。如果未指定 fieldPath,则验证失败时,fieldPath 将默认为 self 范围内的任何位置。指定 fieldPath 后,返回的错误将具有 fieldPath 正确地引用字段 x 的位置。

fieldPath 值必须是相对于模式中此 x-kubernetes-validations 扩展位置的相对 JSON 路径。此外,它应该引用模式内的现有字段。例如,当验证检查 map testMap 下的特定属性 foo 时,您可以将 fieldPath 设置为 ".testMap.foo".testMap['foo']'。如果验证需要检查两个列表中的唯一属性,则可以将 fieldPath 设置为这两个列表中的任何一个。例如,可以将其设置为 .testList1.testList2。它目前支持子操作来引用现有字段。有关更多信息,请参阅 Kubernetes 中的 JSONPath 支持fieldPath 字段不支持按数字对数组进行索引。

设置 fieldPath 是可选的。

optionalOldSelf 字段

功能状态: Kubernetes v1.30 [beta]

如果您的集群没有启用 CRD 验证棘轮,则 CustomResourceDefinition API 不包含此字段,尝试设置它可能会导致错误。

optionalOldSelf 字段是一个布尔字段,它会改变下面描述的 转换规则 的行为。通常,如果无法确定 oldSelf,则转换规则不会评估:在对象创建期间或在更新中引入新值时。

如果 optionalOldSelf 设置为 true,则转换规则将始终被评估,并且 oldSelf 的类型将更改为 CEL Optional 类型。

optionalOldSelf 在模式作者希望使用比 默认基于相等性的行为提供的工具更强大的工具 来对新值引入更新的(通常更严格的)约束,同时仍然允许使用旧的验证来“祖父”或棘轮旧值的情况下很有用。

使用示例

CEL描述
`self.foo == "foo"
[oldSelf.orValue(""), self].all(x, ["OldCase1", "OldCase2"].exists(case, x == case))
oldSelf.optMap(o, o.size()).orValue(0) < 4

验证函数

可用的函数包括

转换规则

包含引用标识符 oldSelf 的表达式的规则隐式地被认为是转换规则。转换规则允许模式作者阻止两个否则有效的状态之间的某些转换。例如

type: string
enum: ["low", "medium", "high"]
x-kubernetes-validations:
- rule: "!(self == 'high' && oldSelf == 'low') && !(self == 'low' && oldSelf == 'high')"
  message: cannot transition directly between 'low' and 'high'

与其他规则不同,转换规则仅适用于满足以下条件的操作

  • 操作更新现有对象。转换规则永远不会应用于创建操作。

  • 存在旧值和新值。通过将转换规则放在父节点上,仍然可以检查是否添加或删除了值。转换规则永远不会应用于自定义资源创建。当放置在可选字段上时,转换规则不会应用于设置或取消设置字段的更新操作。

  • 转换规则验证的模式节点的路径必须解析为一个节点,该节点在旧对象和新对象之间是可比较的。例如,列表项及其后代 (spec.foo[10].bar) 在现有对象和对同一对象的后续更新之间可能无法相关联。

如果模式节点包含永远无法应用的转换规则,例如“path:更新规则 rule 无法设置在模式上,因为模式或其父模式不可合并”,则将在 CRD 写入时生成错误。

转换规则仅允许在模式的可关联部分上。如果所有 array 父模式的类型为 x-kubernetes-list-type=map,则模式的一部分是可关联的;任何 setatomic 数组父模式都会使无法明确地关联 selfoldSelf

以下是一些转换规则的示例

转换规则示例
用例规则
不可变性self.foo == oldSelf.foo
分配后防止修改/删除oldSelf != 'bar' || self == 'bar'!has(oldSelf.field) || has(self.field)
仅追加集合self.all(element, element in oldSelf)
如果先前值为 X,则新值只能为 A 或 B,不能为 Y 或 ZoldSelf != 'X' || self in ['A', 'B']
单调(非递减)计数器self >= oldSelf

验证函数的资源使用

当您创建或更新使用验证规则的 CustomResourceDefinition 时,API 服务器会检查运行这些验证规则的可能影响。如果估计某个规则的执行成本过高,API 服务器将拒绝创建或更新操作,并返回错误消息。类似的系统在运行时使用,观察解释器采取的操作。如果解释器执行的指令过多,则规则的执行将被停止,并导致错误。每个 CustomResourceDefinition 也允许使用一定数量的资源来完成所有验证规则的执行。如果在创建时估计其所有规则的总和超过该限制,则也会发生验证错误。

如果您只指定始终花费相同时间(无论其输入大小如何)的规则,则不太可能遇到验证资源预算的问题。例如,断言 self.foo == 1 的规则本身不会有任何因验证资源预算组而被拒绝的风险。但是,如果 foo 是一个字符串,并且您定义了一个验证规则 self.foo.contains("someString"),则该规则的执行时间取决于 foo 的长度。另一个例子是,如果 foo 是一个数组,并且您指定了一个验证规则 self.foo.all(x, x > 5)。如果未给出 foo 长度的限制,则成本系统始终假设最坏情况,这将发生在任何可以迭代的内容(列表、映射等)上。

因此,建议使用 maxItemsmaxPropertiesmaxLength 为将在验证规则中处理的任何内容设置限制,以防止在成本估算期间出现验证错误。例如,给定以下带有单个规则的模式

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      items:
        type: string
      x-kubernetes-validations:
        - rule: "self.all(x, x.contains('a string'))"

那么 API 服务器会因验证预算原因拒绝此规则,并返回错误

spec.validation.openAPIV3Schema.properties[spec].properties[foo].x-kubernetes-validations[0].rule: Forbidden:
CEL rule exceeded budget by more than 100x (try simplifying the rule, or adding maxItems, maxProperties, and
maxLength where arrays, maps, and strings are used)

拒绝发生是因为 self.all 意味着对 foo 中的每个字符串调用 contains(),这反过来将检查给定字符串以查看它是否包含 'a string'。如果没有限制,这是一个非常昂贵的规则。

如果您没有指定任何验证限制,则此规则的估计成本将超过每个规则的成本限制。但是,如果您在适当的位置添加限制,则该规则将被允许

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      maxItems: 25
      items:
        type: string
        maxLength: 10
      x-kubernetes-validations:
        - rule: "self.all(x, x.contains('a string'))"

成本估算系统会考虑规则执行的次数以及规则本身的估计成本。例如,以下规则将与前面的示例具有相同的估计成本(尽管规则现在是在单个数组项上定义的)

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      maxItems: 25
      items:
        type: string
        x-kubernetes-validations:
          - rule: "self.contains('a string'))"
        maxLength: 10

如果列表内部的列表有一个使用 self.all 的验证规则,那么它比具有相同规则的非嵌套列表要昂贵得多。在非嵌套列表上允许的规则可能需要在嵌套列表上设置更低的限制才能被允许。例如,即使没有设置限制,以下规则也是允许的

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      items:
        type: integer
    x-kubernetes-validations:
      - rule: "self.all(x, x == 5)"

但是,在以下模式(添加了嵌套数组)上使用相同的规则会产生验证错误

openAPIV3Schema:
  type: object
  properties:
    foo:
      type: array
      items:
        type: array
        items:
          type: integer
        x-kubernetes-validations:
          - rule: "self.all(x, x == 5)"

这是因为 foo 的每个项目本身都是一个数组,并且每个子数组反过来都调用 self.all。如果可能,请避免在使用验证规则的地方使用嵌套列表和映射。

默认值

默认值允许在 OpenAPI v3 验证模式 中指定默认值

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        # openAPIV3Schema is the schema for validating custom objects.
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                  pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$'
                  default: "5 0 * * *"
                image:
                  type: string
                replicas:
                  type: integer
                  minimum: 1
                  maximum: 10
                  default: 1
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct

这样,cronSpecreplicas 都会被赋予默认值

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  image: my-awesome-cron-image

导致

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "5 0 * * *"
  image: my-awesome-cron-image
  replicas: 1

默认值发生在对象上

  • 在使用请求版本默认值的 API 服务器请求中,
  • 在使用存储版本默认值从 etcd 读取时,
  • 在使用非空补丁的准入 webhook 对象版本默认值对准入插件进行变异后。

从 etcd 读取数据时应用的默认值不会自动写入 etcd。需要通过 API 发出更新请求才能将这些默认值持久化回 etcd。

默认值必须进行修剪(除了 metadata 字段的默认值),并且必须根据提供的模式进行验证。

x-kubernetes-embedded-resources: true 节点(或覆盖 metadata 的默认值的一部分)的 metadata 字段的默认值不会在 CustomResourceDefinition 创建期间进行修剪,而是在处理请求期间的修剪步骤中进行修剪。

默认值和可空

对于未指定可空标志或将其设置为 false 的字段,其空值将在默认值生效之前进行修剪。如果存在默认值,则将应用该默认值。当可空为 true 时,空值将被保留,不会被赋予默认值。

例如,给定以下 OpenAPI 模式

type: object
properties:
  spec:
    type: object
    properties:
      foo:
        type: string
        nullable: false
        default: "default"
      bar:
        type: string
        nullable: true
      baz:
        type: string

创建一个具有 foobarbaz 的空值的物体

spec:
  foo: null
  bar: null
  baz: null

导致

spec:
  foo: "default"
  bar: null

其中 foo 被修剪并赋予默认值,因为该字段不可空,bar 保持空值,因为 nullable: true,而 baz 被修剪,因为该字段不可空且没有默认值。

在 OpenAPI 中发布验证模式

CustomResourceDefinition OpenAPI v3 验证模式结构化的 并且 启用修剪 的,它们将作为 OpenAPI v3 和 OpenAPI v2 从 Kubernetes API 服务器发布。建议使用 OpenAPI v3 文档,因为它是对 CustomResourceDefinition OpenAPI v3 验证模式的无损表示,而 OpenAPI v2 表示有损转换。

kubectl 命令行工具使用发布的模式执行客户端验证(kubectl createkubectl apply)、模式解释(kubectl explain)操作,这些操作针对自定义资源。发布的模式也可以用于其他目的,例如客户端生成或文档。

与 OpenAPI V2 的兼容性

为了与 OpenAPI V2 兼容,OpenAPI v3 验证模式会执行有损转换以生成 OpenAPI v2 模式。该模式显示在 OpenAPI v2 规范 中的 definitionspaths 字段中。

在转换过程中会应用以下修改,以保持与以前 1.13 版本的 kubectl 向后兼容。这些修改可以防止 kubectl 过于严格,并拒绝它不理解的有效 OpenAPI 模式。转换不会修改 CRD 中定义的验证模式,因此不会影响 API 服务器中的 验证

  1. 以下字段将被删除,因为它们不受 OpenAPI v2 支持。

    • allOfanyOfoneOfnot 字段将被删除
  2. 如果设置了 nullable: true,我们将删除 typenullableitemsproperties,因为 OpenAPI v2 无法表达可空性。为了避免 kubectl 拒绝好的对象,这是必要的。

其他打印机列

kubectl 工具依赖于服务器端输出格式。您的集群的 API 服务器决定 kubectl get 命令显示哪些列。您可以为 CustomResourceDefinition 自定义这些列。以下示例添加了 SpecReplicasAge 列。

将 CustomResourceDefinition 保存到 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct
  versions:
  - name: v1
    served: true
    storage: true
    schema:
      openAPIV3Schema:
        type: object
        properties:
          spec:
            type: object
            properties:
              cronSpec:
                type: string
              image:
                type: string
              replicas:
                type: integer
    additionalPrinterColumns:
    - name: Spec
      type: string
      description: The cron spec defining the interval a CronJob is run
      jsonPath: .spec.cronSpec
    - name: Replicas
      type: integer
      description: The number of jobs launched by the CronJob
      jsonPath: .spec.replicas
    - name: Age
      type: date
      jsonPath: .metadata.creationTimestamp

创建 CustomResourceDefinition

kubectl apply -f resourcedefinition.yaml

使用上一节中的 my-crontab.yaml 创建一个实例。

调用服务器端打印

kubectl get crontab my-new-cron-object

请注意输出中的 NAMESPECREPLICASAGE

NAME                 SPEC        REPLICAS   AGE
my-new-cron-object   * * * * *   1          7s

字段选择器

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

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

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

自定义资源的可选择字段

功能状态: Kubernetes v1.30 [alpha]

您需要启用 CustomResourceFieldSelectors 功能网关 才能使用此行为,然后它将应用于集群中的所有 CustomResourceDefinition。

CustomResourceDefinitionspec.versions[*].selectableFields 字段可用于声明自定义资源中的哪些其他字段可用于字段选择器。以下示例将 .spec.color.spec.size 字段添加为可选择字段。

将 CustomResourceDefinition 保存到 shirt-resource-definition.yaml

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

创建 CustomResourceDefinition

kubectl apply -f https://k8s.io/examples/customresourcedefinition/shirt-resource-definition.yaml

通过编辑 shirt-resources.yaml 来定义一些衬衫;例如

---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example1
spec:
  color: blue
  size: S
---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example2
spec:
  color: blue
  size: M
---
apiVersion: stable.example.com/v1
kind: Shirt
metadata:
  name: example3
spec:
  color: green
  size: M

创建自定义资源

kubectl apply -f https://k8s.io/examples/customresourcedefinition/shirt-resources.yaml

获取所有资源

kubectl get shirts.stable.example.com

输出为

NAME       COLOR  SIZE
example1   blue   S
example2   blue   M
example3   green  M

获取蓝色衬衫(检索颜色为 blue 的衬衫)

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

应该输出

NAME       COLOR  SIZE
example1   blue   S
example2   blue   M

仅获取颜色为 green 且尺寸为 M 的资源

kubectl get shirts.stable.example.com --field-selector spec.color=green,spec.size=M

应该输出

NAME       COLOR  SIZE
example2   blue   M

优先级

每列都包含一个 priority 字段。目前,优先级区分标准视图或宽视图(使用 -o wide 标志)中显示的列。

  • 优先级为 0 的列在标准视图中显示。
  • 优先级大于 0 的列仅在宽视图中显示。

类型

列的 type 字段可以是以下任何一种(比较 OpenAPI v3 数据类型

  • integer – 非浮点数
  • number – 浮点数
  • string – 字符串
  • booleantruefalse
  • date – 作为自此时间戳以来的时间差进行渲染。

如果自定义资源中的值与为列指定的类型不匹配,则该值将被省略。使用自定义资源验证来确保值类型正确。

格式

列的 format 字段可以是以下任何一种

  • int32
  • int64
  • float
  • double
  • byte
  • date
  • date-time
  • password

列的 format 控制 kubectl 打印值时使用的样式。

子资源

自定义资源支持 /status/scale 子资源。

可以通过在 CustomResourceDefinition 中定义它们来选择性地启用状态和比例子资源。

状态子资源

启用状态子资源后,自定义资源的 /status 子资源将被公开。

  • 状态和规范段分别由自定义资源内的 .status.spec JSONPath 表示。

  • /status 子资源的 PUT 请求将接受一个自定义资源对象,并忽略除状态段之外的任何更改。

  • /status 子资源的 PUT 请求仅验证自定义资源的状态段。

  • 对自定义资源的 PUT/POST/PATCH 请求将忽略对状态段的更改。

  • 除对 .metadata.status 的更改外,所有更改都会使 .metadata.generation 值递增。

  • CRD OpenAPI 验证模式的根目录仅允许以下结构

    • description
    • example
    • exclusiveMaximum
    • exclusiveMinimum
    • externalDocs
    • format
    • items
    • maximum
    • maxItems
    • maxLength
    • minimum
    • minItems
    • minLength
    • multipleOf
    • pattern
    • properties
    • required
    • title
    • type
    • uniqueItems

缩放子资源

启用缩放子资源后,自定义资源的 /scale 子资源将被公开。autoscaling/v1.Scale 对象将作为 /scale 的有效负载发送。

要启用缩放子资源,请在 CustomResourceDefinition 中定义以下字段。

  • specReplicasPath 定义自定义资源内对应于 scale.spec.replicas 的 JSONPath。

    • 这是一个必需的值。
    • 仅允许 .spec 下的 JSONPath,并使用点符号。
    • 如果自定义资源的 specReplicasPath 下没有值,则 /scale 子资源在 GET 时将返回错误。
  • statusReplicasPath 定义自定义资源内对应于 scale.status.replicas 的 JSONPath。

    • 这是一个必需的值。
    • 仅允许 .status 下的 JSONPath,并使用点符号。
    • 如果自定义资源的 statusReplicasPath 下没有值,则 /scale 子资源中的状态副本值将默认为 0。
  • labelSelectorPath 定义自定义资源内对应于 Scale.Status.Selector 的 JSONPath。

    • 这是一个可选值。
    • 必须设置它才能与 HPA 和 VPA 协同工作。
    • 仅允许 .status.spec 下的 JSONPath,并使用点符号。
    • 如果自定义资源的 labelSelectorPath 下没有值,则 /scale 子资源中的状态选择器值将默认为空字符串。
    • 此 JSON 路径指向的字段必须是字符串字段(而不是复杂的 selector 结构),其中包含以字符串形式序列化后的标签选择器。

在以下示例中,状态和缩放子资源都已启用。

将 CustomResourceDefinition 保存到 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                image:
                  type: string
                replicas:
                  type: integer
            status:
              type: object
              properties:
                replicas:
                  type: integer
                labelSelector:
                  type: string
      # subresources describes the subresources for custom resources.
      subresources:
        # status enables the status subresource.
        status: {}
        # scale enables the scale subresource.
        scale:
          # specReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Spec.Replicas.
          specReplicasPath: .spec.replicas
          # statusReplicasPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Replicas.
          statusReplicasPath: .status.replicas
          # labelSelectorPath defines the JSONPath inside of a custom resource that corresponds to Scale.Status.Selector.
          labelSelectorPath: .status.labelSelector
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct

并创建它

kubectl apply -f resourcedefinition.yaml

创建 CustomResourceDefinition 对象后,您可以创建自定义对象。

如果您将以下 YAML 保存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image
  replicas: 3

并创建它

kubectl apply -f my-crontab.yaml

然后,新的命名空间 RESTful API 端点将在以下位置创建

/apis/stable.example.com/v1/namespaces/*/crontabs/status

/apis/stable.example.com/v1/namespaces/*/crontabs/scale

可以使用 kubectl scale 命令缩放自定义资源。例如,以下命令将上面创建的自定义资源的 .spec.replicas 设置为 5

kubectl scale --replicas=5 crontabs/my-new-cron-object
crontabs "my-new-cron-object" scaled

kubectl get crontabs my-new-cron-object -o jsonpath='{.spec.replicas}'
5

您可以使用 PodDisruptionBudget 来保护启用了缩放子资源的自定义资源。

类别

类别是自定义资源所属的已分组资源列表(例如 all)。您可以使用 kubectl get <category-name> 列出属于该类别的资源。

以下示例在 CustomResourceDefinition 的类别列表中添加 all,并说明如何使用 kubectl get all 输出自定义资源。

将以下 CustomResourceDefinition 保存到 resourcedefinition.yaml

apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: crontabs.stable.example.com
spec:
  group: stable.example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                cronSpec:
                  type: string
                image:
                  type: string
                replicas:
                  type: integer
  scope: Namespaced
  names:
    plural: crontabs
    singular: crontab
    kind: CronTab
    shortNames:
    - ct
    # categories is a list of grouped resources the custom resource belongs to.
    categories:
    - all

并创建它

kubectl apply -f resourcedefinition.yaml

创建 CustomResourceDefinition 对象后,您可以创建自定义对象。

将以下 YAML 保存到 my-crontab.yaml

apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
  name: my-new-cron-object
spec:
  cronSpec: "* * * * */5"
  image: my-awesome-cron-image

并创建它

kubectl apply -f my-crontab.yaml

使用 kubectl get 时,您可以指定类别

kubectl get all

它将包含类型为 CronTab 的自定义资源

NAME                          AGE
crontabs/my-new-cron-object   3s

下一步

上次修改时间:2024 年 7 月 1 日凌晨 12:28 PST:删除重复的功能状态简码 (46ecfd46f1)