使用 CustomResourceDefinitions 扩展 Kubernetes API
此页面展示如何通过创建 自定义资源 来将 CustomResourceDefinition 安装到 Kubernetes API 中。
在开始之前
您需要拥有一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。建议您在至少有两个节点(不充当控制平面主机)的集群上运行本教程。如果您还没有集群,可以使用 minikube 创建一个,或者可以使用以下 Kubernetes playground 之一
您的 Kubernetes 服务器必须是 1.16 版本或更高版本。要检查版本,请输入kubectl version
。如果您使用的是仍然受支持的较旧版本的 Kubernetes,请切换到该版本的文档以查看与您的集群相关的建议。创建 CustomResourceDefinition
创建新的 CustomResourceDefinition (CRD) 时,Kubernetes API 服务器会为您指定的每个版本创建一个新的 RESTful 资源路径。从 CRD 对象创建的自定义资源可以是命名空间范围的,也可以是集群范围的,具体取决于 CRD 的 spec.scope
字段中指定的范围。与现有的内置对象一样,删除命名空间会删除该命名空间中的所有自定义对象。CustomResourceDefinition 本身是非命名空间的,对所有命名空间都可用。
例如,如果您将以下 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
条件是否为 true,或者观察 API 服务器的发现信息以查看您的资源是否出现。
创建自定义对象
创建 CustomResourceDefinition 对象后,您可以创建自定义对象。自定义对象可以包含自定义字段。这些字段可以包含任意 JSON。在以下示例中,cronSpec
和 image
自定义字段在 CronTab
类型的自定义对象中设置。CronTab
类型来自您上面创建的 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 的自定义 cronSpec
和 image
字段
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 将结构化数据存储在自定义字段中(以及内置字段 apiVersion
、kind
和 metadata
旁边,API 服务器会隐式验证这些字段)。使用 OpenAPI v3.0 验证 可以指定一个模式,该模式在创建和更新期间进行验证,请参见下面的详细信息和此类模式的限制。
使用 apiextensions.k8s.io/v1
,结构化模式的定义对于 CustomResourceDefinition 是强制性的。在 CustomResourceDefinition 的 beta 版本中,结构化模式是可选的。
结构化模式是一个 OpenAPI v3.0 验证模式,它
- 为根指定一个非空类型(通过 OpenAPI 中的
type
),为对象节点的每个指定字段指定一个非空类型(通过 OpenAPI 中的properties
或additionalProperties
),以及为数组节点中的每个项目指定一个非空类型(通过 OpenAPI 中的items
),但以下情况除外- 具有
x-kubernetes-int-or-string: true
的节点 - 具有
x-kubernetes-preserve-unknown-fields: true
的节点
- 具有
- 对于对象中的每个字段和数组中的每个项目(在任何
allOf
、anyOf
、oneOf
或not
中指定),该模式还在这些逻辑连接词之外指定字段/项目(比较示例 1 和 2)。 - 不会在
allOf
、anyOf
、oneOf
或not
中设置description
、type
、default
、additionalProperties
、nullable
,但以下两种模式的x-kubernetes-int-or-string: true
除外(见下文)。 - 如果指定了
metadata
,则只允许限制metadata.name
和metadata.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)。bar
的type
在anyOf
中(规则 3)。- 描述在
anyOf
中设置(规则 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
条件中报告。
字段修剪
CustomResourceDefinition 将经过验证的资源数据存储在集群的持久性存储中,即 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
兼容,请更新您的自定义资源定义以
- 使用结构化 OpenAPI 模式。
- 将
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
类型的值。
对于每个指定的属性(或 additionalProperties
),修剪再次启用
type: object
properties:
json:
x-kubernetes-preserve-unknown-fields: true
type: object
properties:
spec:
type: object
properties:
foo:
type: string
bar:
type: string
这样,值
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
RawExtension(如 runtime.RawExtension
)包含完整的 Kubernetes 对象,即带有 apiVersion
和 kind
字段的 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
,apiVersion
、kind
和 metadata
会被隐式指定和验证。
提供 CRD 的多个版本
有关提供 CustomResourceDefinition 的多个版本以及将您的对象从一个版本迁移到另一个版本的详细信息,请参见 CustomResourceDefinition 版本控制。
高级主题
终结器
Finalizer 允许控制器实现异步预删除钩子。自定义对象支持类似于内置对象的 Finalizer。
您可以像这样向自定义对象添加 Finalizer
apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
finalizers:
- stable.example.com/finalizer
自定义 Finalizer 的标识符由域名、正斜杠和 Finalizer 的名称组成。任何控制器都可以向任何对象的 Finalizer 列表中添加 Finalizer。
具有 Finalizer 的对象的第一个删除请求会设置 metadata.deletionTimestamp
字段的值,但不会删除该对象。设置此值后,只能删除 finalizers
列表中的条目。当存在任何 Finalizer 时,也无法强制删除对象。
当设置了 metadata.deletionTimestamp
字段时,观察对象的控制器会执行它们处理的任何 Finalizer,并在完成后从列表中删除 Finalizer。每个控制器负责从列表中删除其 Finalizer。
metadata.deletionGracePeriodSeconds
的值控制轮询更新之间的间隔。
一旦 Finalizer 列表为空,这意味着所有 Finalizer 都已执行,Kubernetes 将删除该资源。
验证
自定义资源通过 OpenAPI v3 schemas 进行验证,在启用 验证规则功能 时通过 x-kubernetes-validations 进行验证,还可以使用 准入 Webhook 添加额外的验证。
此外,对模式应用以下限制
这些字段不能设置
definitions
,dependencies
,deprecated
,discriminator
,id
,patternProperties
,readOnly
,writeOnly
,xml
,$ref
.
字段
uniqueItems
不能设置为true
。字段
additionalProperties
不能设置为false
。字段
additionalProperties
与properties
相互排斥。
当启用 验证规则 功能且 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.31 中实现的棘轮支持,如果违反,将继续像往常一样抛出错误
量词
allOf
oneOf
anyOf
not
- 这些字段的任何后代中的任何验证
x-kubernetes-validations
对于 Kubernetes 1.28,CRD 验证规则 被棘轮忽略。从 Kubernetes 1.29 的 Alpha 2 开始,x-kubernetes-validations
仅在它们不引用oldSelf
时才被棘轮。转换规则永远不会被棘轮:只有没有使用
oldSelf
的规则引发的错误,如果其值保持不变,则会自动被棘轮。要为 CEL 表达式编写自定义棘轮逻辑,请查看 可选的 oldSelf。
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
注意
您可以在 CEL Playground 中快速测试 CEL 表达式。验证规则在创建/更新 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 模式中声明的任何字段以及
apiVersion
、kind
、metadata.name
和metadata.generateName
进行字段选择。这包括在同一个表达式中选择spec
和status
中的字段... 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') |
apiVersion
、kind
、metadata.name
和 metadata.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 不会被转义)。
关于转义的示例
属性名称 | 包含转义属性名称的规则 |
---|---|
namespace | self.__namespace__ > 0 |
x-prop | self.x__dash__prop > 0 |
redact__d | self.redact__underscores__d > 0 |
字符串 | self.startsWith('kube') |
x-kubernetes-list-type
为 set
或 map
的数组上的相等性会忽略元素顺序,即 [1, 2] == [2, 1]
。具有 x-kubernetes-list-type 的数组上的连接使用列表类型的语义
set
:X + Y
执行并集操作,其中保留X
中所有元素的数组位置,并将Y
中的非交集元素追加到末尾,保留其部分顺序。map
:X + Y
执行合并操作,其中保留X
中所有键的数组位置,但当X
和Y
的键集相交时,Y
中的值会覆盖X
中的值。具有非交集键的Y
中的元素将追加到末尾,保留其部分顺序。
以下是 OpenAPIv3 和 CEL 类型之间的声明类型映射
OpenAPIv3 类型 | CEL 类型 |
---|---|
'object' with Properties | object / "message type" |
'object' with AdditionalProperties | map |
'object' with x-kubernetes-embedded-type | object / "message type", 'apiVersion', 'kind', 'metadata.name' 和 'metadata.generateName' 隐式包含在模式中 |
'object' with x-kubernetes-preserve-unknown-fields | object / "message type", 未知字段在 CEL 表达式中不可访问 |
x-kubernetes-int-or-string | 动态对象,可以是整数或字符串,type(value) 可用于检查类型 |
'array | list |
'array' with x-kubernetes-list-type=map | 具有基于 map 的相等性和唯一键保证的列表 |
'array' with x-kubernetes-list-type=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=date | timestamp (google.protobuf.Timestamp) |
'string' with format=datetime | timestamp (google.protobuf.Timestamp) |
'string' with format=duration | duration (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 时进行检查。请注意,可以在同一个规则上设置 message
和 messageExpression
,如果两者都存在,则将使用 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
)在现有对象和对同一对象的后续更新之间不一定能够相关联。
如果模式节点包含一个永远无法应用的转换规则,例如“oldSelf 不能在路径中的模式不可关联部分使用”,则将在 CRD 写入时生成错误。
转换规则仅允许在模式的可关联部分上使用。如果所有 array
父模式都是 x-kubernetes-list-type=map
类型,则模式的一部分是可关联的;任何 set
或 atomic
数组父模式都会使 self
与 oldSelf
的明确关联变得不可能。
以下是一些转换规则的示例
用例 | 规则 |
---|---|
不可变性 | self.foo == oldSelf.foo |
防止在分配后进行修改/删除 | oldSelf != 'bar' || self == 'bar' 或 !has(oldSelf.field) || has(self.field) |
追加的集合 | self.all(element, element in oldSelf) |
如果先前值为 X,则新值只能是 A 或 B,不能是 Y 或 Z | oldSelf != '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
长度的限制,则成本系统始终假设最坏情况,对于任何可以迭代的内容(列表、映射等)都会发生这种情况。
因此,对于将在验证规则中处理的任何内容,建议通过maxItems
、maxProperties
和 maxLength
设置限制,以防止在成本估算期间出现验证错误。例如,给定以下具有一个规则的架构
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
。如果可能,请避免在使用验证规则的地方使用嵌套列表和映射。
默认值
注意
要使用默认值,您的 CustomResourceDefinition 必须使用 API 版本apiextensions.k8s.io/v1
。默认值允许在 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
这样,cronSpec
和 replicas
都会被设为默认值
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
创建一个对象,其中 foo
、bar
和 baz
的值为 null
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 create
和 kubectl apply
),架构说明 (kubectl explain
) 在自定义资源上。发布的架构还可以用于其他目的,例如客户端生成或文档。
与 OpenAPI V2 的兼容性
为了与 OpenAPI V2 兼容,OpenAPI v3 验证架构会对 OpenAPI v2 架构执行有损转换。该架构将显示在 OpenAPI v2 规范 中的 definitions
和 paths
字段中。
在转换过程中,会应用以下修改以保持与以前 1.13 版本的 kubectl 向后兼容。这些修改可以防止 kubectl 过于严格,并拒绝它无法理解的有效 OpenAPI 架构。转换不会修改 CRD 中定义的验证架构,因此不会影响 API 服务器中的 验证。
以下字段将被移除,因为它们不受 OpenAPI v2 支持。
allOf
、anyOf
、oneOf
和not
字段将被移除
如果设置了
nullable: true
,我们会删除type
、nullable
、items
和properties
,因为 OpenAPI v2 无法表达可空。为了避免 kubectl 拒绝好的对象,这是必要的。
其他打印列
kubectl 工具依赖于服务器端输出格式。您的集群的 API 服务器会决定 kubectl get
命令显示哪些列。您可以为 CustomResourceDefinition 自定义这些列。以下示例添加了 Spec
、Replicas
和 Age
列。
将 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
请注意输出中的 NAME
、SPEC
、REPLICAS
和 AGE
列
NAME SPEC REPLICAS AGE
my-new-cron-object * * * * * 1 7s
注意
NAME
列是隐式的,不需要在 CustomResourceDefinition 中定义。优先级
每列都包含一个 priority
字段。目前,优先级区分标准视图或宽视图(使用 -o wide
标志)中显示的列。
- 优先级为
0
的列将显示在标准视图中。 - 优先级大于
0
的列将仅在宽视图中显示。
类型
列的 type
字段可以是以下任何一个(请比较 OpenAPI v3 数据类型)
integer
– 非浮点数number
– 浮点数string
– 字符串boolean
–true
或false
date
– 以自该时间戳以来的时间差的形式渲染。
如果自定义资源中的值与为该列指定的类型不匹配,则该值将被省略。使用自定义资源验证以确保值类型正确。
格式
列的 format
字段可以是以下任何一个
int32
int64
float
double
byte
date
date-time
password
该列的 format
控制 kubectl
打印该值时使用的样式。
字段选择器
字段选择器 允许客户端根据一个或多个资源字段的值选择自定义资源。
所有自定义资源都支持 metadata.name
和 metadata.namespace
字段选择器。
在 CustomResourceDefinition 中声明的字段也可以与字段选择器一起使用,前提是这些字段包含在 CustomResourceDefinition 的 spec.versions[*].selectableFields
字段中。
自定义资源的可选择字段
Kubernetes v1.31 [beta]
对于 Kubernetes 1.31,为自定义资源定义字段选择器功能默认可用(从 Kubernetes v1.31 开始默认启用);您可以通过关闭 CustomResourceFieldSelectors
功能开关 来为您的集群禁用它。可以使用 CustomResourceDefinition 的 spec.versions[*].selectableFields
字段来声明自定义资源中的哪些其他字段可以使用 CustomResourceFieldSelectors
功能开关 的功能(此功能开关从 Kubernetes v1.31 开始默认启用)。以下示例将 .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
子资源
自定义资源支持 /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 子资源后,自定义资源的 /scale
子资源将被暴露。autoscaling/v1.Scale
对象作为 /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
子资源中的状态选择器值将默认为空字符串。 - 此 JSONPath 指向的字段必须是字符串字段(而不是复杂的选择器结构体),其中包含以字符串形式序列化后的标签选择器。
在以下示例中,状态和 Scale 子资源都已启用。
将 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 来保护已启用 Scale 子资源的自定义资源。
类别
类别是自定义资源所属的已分组资源列表(例如 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