使用 CustomResourceDefinitions 扩展 Kubernetes API
此页面展示如何通过创建 CustomResourceDefinition 将 自定义资源 安装到 Kubernetes API 中。
开始之前
您需要一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与您的集群通信。建议在至少有两个节点(不充当控制平面主机)的集群上运行本教程。如果您还没有集群,可以使用 minikube 创建一个,或者可以使用以下 Kubernetes 游乐场
您的 Kubernetes 服务器版本必须是 1.16 或更高版本。要检查版本,请输入 kubectl version。
创建 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 将是您在上面创建的 CustomResourceDefinition 对象的 spec 中的 CronTab。
端点创建可能需要几秒钟。您可以观察 CustomResourceDefinition 的 Established 条件是否为 true,或者观察 API 服务器的发现信息,以查看您的资源是否显示出来。
创建自定义对象
在创建 CustomResourceDefinition 对象后,您可以创建自定义对象。自定义对象可以包含自定义字段。这些字段可以包含任意 JSON。在以下示例中,在 CronTab 类型的自定义对象中设置了自定义字段 cronSpec 和 image。CronTab 类型来自您在上面创建的 CustomResourceDefinition 对象的 spec。
如果您将以下 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,结构化模式的定义对于 CustomResourceDefinitions 是必需的。在 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)。bar在anyOf内部未指定外部(规则 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 条件中报告。
字段修剪
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 兼容,请更新您的自定义资源定义为
- 使用结构化 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 已被修剪。
此示例关闭了客户端验证,以演示 API 服务器的行为,通过添加 --validate=false 命令行选项。由于 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
RawExtensions(如在 runtime.RawExtension 中)保存完整的 Kubernetes 对象,即带有 apiVersion 和 kind 字段的对象。
可以通过设置 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 的多个版本以及将对象从一个版本迁移到另一个版本的更多信息,请参阅 自定义资源定义版本控制。
高级主题
终结器
Finalizers 允许控制器实现异步预删除钩子。自定义对象支持与内置对象类似的 finalizers。
您可以像这样向自定义对象添加 finalizer
apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
finalizers:
- stable.example.com/finalizer
自定义 finalizer 的标识符由域名、正斜杠和 finalizer 的名称组成。任何控制器都可以将 finalizer 添加到任何对象的 finalizers 列表中。
对具有 finalizers 的对象的首次删除请求会为 metadata.deletionTimestamp 字段设置一个值,但不会删除它。一旦此值设置,就只能从 finalizers 列表中删除条目。只要任何 finalizers 仍然存在,就无法强制删除对象。
当 metadata.deletionTimestamp 字段设置时,监视该对象的控制器会执行它们处理的任何 finalizers,并在完成后从列表中删除 finalizer。每个控制器都有责任从列表中删除其 finalizer。
metadata.deletionGracePeriodSeconds 的值控制轮询更新的间隔。
一旦 finalizers 列表为空,意味着所有 finalizers 都已执行,Kubernetes 就会删除该资源。
验证
自定义资源通过 OpenAPI v3.0 模式、在启用 验证规则功能时通过 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
如果自定义对象的字段包含无效值,则创建自定义对象(kind 为 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.33 [稳定](默认启用)如果您使用的是 Kubernetes 1.30 之前的版本,则需要显式启用 CRDValidationRatcheting 功能门 才能使用此行为,然后将其应用于集群中的所有 CustomResourceDefinitions。
前提是您启用了功能门,Kubernetes 会为 CustomResourceDefinitions 实现验证分层。API 服务器愿意接受更新资源,即使在更新后资源无效,前提是资源的每个验证失败的部分未被更新操作更改。换句话说,任何仍然无效的无效部分必须已经错误。您不能使用此机制将有效资源更新为无效资源。
此功能允许 CRD 的作者在某些条件下自信地将新的验证添加到 OpenAPIV3 模式下。用户可以安全地更新到新模式,而无需升级对象版本或破坏工作流程。
虽然放置在 CRD 的 OpenAPIV3 模式中的大多数验证都支持分层,但也有一些例外。在 Kubernetes 1.35 的实现中,以下 OpenAPIV3 模式验证不受分层支持,如果违反,将继续引发错误
量词
allOfoneOfanyOfnot- 这些字段中的任何一个字段的后代中的任何验证
x-kubernetes-validations对于 Kubernetes 1.28,CRD 验证规则 被分层忽略。从 Kubernetes 1.29 的 Alpha 2 开始,如果它们不引用oldSelf,则x-kubernetes-validations将被分层。转换规则永远不会被分层:只有不使用
oldSelf的规则引发的错误才会被自动分层。要为 CEL 表达式编写自定义分层逻辑,请查看 optionalOldSelf。
x-kubernetes-list-type由于更改子模式的列表类型而产生的错误将不会被分层。例如,将set添加到具有重复项的列表中将始终导致错误。x-kubernetes-list-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]*$')) | 验证 listMap 条目中 key 字段为 '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) | 验证 key 为 'x' 的 listMap 项的 'foo' 属性是否小于 10 |
type(self) == string ? self == '100%' : self == 1000 | 验证 int-or-string 字段的 int 和 string 情况 |
self.metadata.name.startsWith(self.prefix) | 验证对象的名称是否具有另一个字段值的 前缀 |
self.set1.all(e, !(e in self.set2)) | 验证两个 listSet 是否不相交 |
size(self.names) == size(self.details) && self.names.all(n, n in self.details) | 验证 'details' map 的键由 'names' listSet 中的项键入 |
size(self.clusters.filter(c, c.name == self.primary)) == 1 | 验证 'primary' 属性在 'clusters' listMap 中恰好出现一次 |
Xref: 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如果 Rule 的作用域是具有属性的对象,则可以通过
self.field选择对象的可用属性,并通过has(self.field)检查属性是否存在。在 CEL 表达式中,值为 Null 的字段被视为不存在的字段。# ... openAPIV3Schema: type: object properties: spec: type: object x-kubernetes-validations: - rule: "has(self.foo)" properties: # ... foo: type: integer如果 Rule 的作用域是具有 additionalProperties(即 map)的对象,则可以通过
self[mapKey]访问 map 的值,可以通过mapKey in self检查 map 是否包含该键,并且可以通过 CEL 宏和函数(例如self.all(...))访问 map 的所有条目。# ... openAPIV3Schema: type: object properties: spec: type: object x-kubernetes-validations: - rule: "self['xyz'].foo > 0" additionalProperties: # ... type: object properties: foo: type: integer如果 Rule 的作用域是数组,则可以通过
self[i]以及宏和函数访问数组的元素。# ... openAPIV3Schema: type: object properties: # ... foo: type: array x-kubernetes-validations: - rule: "size(self) == 1" items: type: string如果 Rule 的作用域是标量,则
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 注解的对象中访问。其他 metadata 属性不可访问。
通过 x-kubernetes-preserve-unknown-fields 在自定义资源中保留的未知数据在 CEL 表达式中不可访问。这包括
由带有
x-kubernetes-preserve-unknown-fields的对象模式保留的未知字段值。对象属性,其属性模式的类型为“未知类型”。“未知类型”递归定义为
- 一个没有类型且 x-kubernetes-preserve-unknown-fields 设置为 true 的模式
- 一个其 items 模式为“未知类型”的数组
- 一个其 additionalProperties 模式为“未知类型”的对象
只有形式为 [a-zA-Z_.-/][a-zA-Z0-9_.-/]* 的属性名称可访问。在表达式中访问时,可访问的属性名称会根据以下规则进行转义
| 转义序列 | 属性名称等效项 |
|---|---|
__underscores__ | __ |
__dot__ | . |
__dash__ | - |
__slash__ | / |
__keyword__ | CEL 保留关键字 |
注意:CEL 保留关键字需要与要转义的精确属性名称匹配(例如,单词 sprint 中的 int 不会被转义)。
转义示例
| 属性名称 | 带有转义属性名称的规则 |
|---|---|
| 命名空间 | 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中的值覆盖值。将Y中具有不相交键的元素追加,保留它们的相对顺序。
以下是 OpenAPIv3 和 CEL 类型之间的声明类型映射
| OpenAPIv3 类型 | CEL 类型 |
|---|---|
| 带有属性的 'object' | object / "message type" |
| 带有 AdditionalProperties 的 'object' | map |
| 带有 x-kubernetes-embedded-type 的 'object' | object / "message type",'apiVersion'、'kind'、'metadata.name' 和 'metadata.generateName' 会隐式包含在模式中 |
| 带有 x-kubernetes-preserve-unknown-fields 的 'object' | object / "message type",未知字段在 CEL 表达式中不可访问 |
| x-kubernetes-int-or-string | 动态对象,可以是 int 或 string,可以使用 type(value) 来检查类型 |
| 'array | list |
| 带有 x-kubernetes-list-type=map 的 'array' | 基于 map 的相等性和唯一键保证的列表 |
| 带有 x-kubernetes-list-type=set 的 'array' | 基于 set 的相等性和唯一条目保证的列表 |
| 'boolean' | boolean |
| 'number' (所有格式) | double |
| 'integer' (所有格式) | int (64) |
| 'null' | null_type |
| 'string' | 字符串 |
| 带有 format=byte (base64 编码) 的 'string' | bytes |
| 带有 format=date 的 'string' | timestamp (google.protobuf.Timestamp) |
| 带有 format=datetime 的 'string' | timestamp (google.protobuf.Timestamp) |
| 带有 format=duration 的 'string' | duration (google.protobuf.Duration) |
xref: 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 错误。如果 CEL 表达式在 messageExpression 中生成一个空字符串或包含换行符的字符串,也会发生此回退。
如果满足上述条件之一,并且未设置 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 指定后,返回的错误将正确地引用字段 x 的位置。
fieldPath 值必须是相对于模式中此 x-kubernetes-validations 扩展位置的相对 JSON 路径。此外,它应引用模式中现有的字段。例如,当验证检查 map testMap 下的特定属性 foo 是否存在时,您可以将 fieldPath 设置为 ".testMap.foo" 或 .testMap['foo']'。如果验证需要检查两个列表中的唯一属性,则可以将 fieldPath 设置为任一列表。例如,可以将其设置为 .testList1 或 .testList2。它支持子操作来引用当前存在的字段。有关更多信息,请参阅 Kubernetes 中的 JSONPath 支持。fieldPath 字段不支持以数字方式索引数组。
设置 fieldPath 是可选的。
optionalOldSelf 字段
Kubernetes v1.33 [稳定](默认启用)如果您的集群未启用 CRD 验证渐进式增强,则 CustomResourceDefinition API 不包含此字段,并且尝试设置它可能会导致错误。
optionalOldSelf 字段是一个布尔字段,它会改变下面描述的 转换规则 的行为。通常,如果无法确定 oldSelf,则转换规则将不会评估:在对象创建期间或在更新中引入新值时。
如果将 optionalOldSelf 设置为 true,则始终评估转换规则,并且 oldSelf 的类型将更改为 CEL Optional 类型。
optionalOldSelf 在模式作者希望比默认基于相等性的行为 对引入更新的、通常更严格的约束的新值进行更多控制 的情况下很有用,同时仍然允许使用旧的验证来“祖父化”或渐进式增强旧值。
示例用法
| CEL | 描述 |
|---|---|
self.foo == "foo" || (oldSelf.hasValue() && oldSelf.value().foo != "foo") | 渐进式增强的规则。一旦将值设置为“foo”,它必须保持 foo。但是,如果它在引入“foo”约束之前就存在,则可以使用任何值 |
[oldSelf.orValue(""), self].all(x, ["OldCase1", "OldCase2"].exists(case, x == case)) || ["NewCase1", "NewCase2"].exists(case, self == case) || ["NewCase"].has(self) | 针对已使用旧枚举案例的渐进式验证 |
oldSelf.optMap(o, o.size()).orValue(0) < 4 || self.size() >= 4 | 对新增加的最小 map 或列表大小进行渐进式验证 |
验证函数
可用函数包括
转换规则
包含引用标识符 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) 在现有对象和对同一对象的后续更新之间不一定能够关联。
如果模式节点包含无法应用的转换规则,则会在 CRD 写入时生成错误,例如“oldSelf 不能在模式的不可关联部分内path中使用”。
转换规则仅允许在模式的可关联部分上使用。如果所有 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 读取时,
- 使用非空补丁的 mutating admission 插件使用 admission webhook 对象版本默认值。
从 etcd 读取时应用的默认值不会自动写回 etcd。需要通过 API 发送更新请求才能将这些默认值持久化回 etcd。
非叶子字段的默认值必须被修剪(metadata 字段的默认值除外),并且必须验证提供的模式。例如,在上面的示例中,为 spec 字段提供 {"replicas": "foo", "badger": 1} 的默认值将是无效的,因为 badger 是未知的字段,并且 replicas 不是字符串。
对于 x-kubernetes-embedded-resources: true 节点的 metadata 字段的默认值(或覆盖 metadata 的默认值的一部分),在 CustomResourceDefinition 创建期间不会被修剪,而是在处理请求期间通过修剪步骤进行修剪。
默认值和可为空性
对于没有指定 nullable 标志或将其设置为 false 的字段,在发生默认值之前,空值将被修剪。如果存在默认值,则会应用它。当 nullable 为 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 的空值的对象
spec:
foo: null
bar: null
baz: null
导致
spec:
foo: "default"
bar: null
foo 被修剪并默认,因为该字段不可为空,bar 由于 nullable: true 而保持空值,而 baz 被修剪,因为该字段不可为空且没有默认值。
在 OpenAPI 中发布验证模式
CustomResourceDefinition OpenAPI v3 验证模式,这些模式是 结构化的 并且 启用修剪,作为 Kubernetes API 服务器中的 OpenAPI v3 和 OpenAPI v2 发布。建议使用 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或falsedate– 以自此时间戳以来的时间差异形式呈现。
如果 CustomResource 中的值与列指定的类型不匹配,则该值将被省略。使用 CustomResource 验证来确保值类型正确。
格式
列的 format 字段可以是以下任何一种
int32int64浮点数double字节日期日期时间密码
列的 format 控制了 kubectl 打印值时使用的样式。
字段选择器
字段选择器 允许客户端基于资源的一个或多个字段的值来选择自定义资源。
所有自定义资源都支持 metadata.name 和 metadata.namespace 字段选择器。
在 CustomResourceDefinition 中声明的字段也可以在 spec.versions[*].selectableFields 字段的 CustomResourceDefinition 中与字段选择器一起使用。
自定义资源的 selectable 字段
Kubernetes v1.32 [稳定](默认启用)spec.versions[*].selectableFields 字段的 CustomResourceDefinition 可用于声明自定义资源中哪些其他字段可用于具有 CustomResourceFieldSelectors 功能门控 的字段选择器(此功能门控自 Kubernetes v1.31 起默认启用)。以下示例将 .spec.color 和 .spec.size 字段添加为 selectable 字段。
将 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 定义一些 Shirts,例如
---
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
获取蓝色 Shirts(检索 color 为 blue 的 Shirts)
kubectl get shirts.stable.example.com --field-selector spec.color=blue
应该输出
NAME COLOR SIZE
example1 blue S
example2 blue M
仅获取 color 为 green 且 size 为 M 的资源
kubectl get shirts.stable.example.com --field-selector spec.color=green,spec.size=M
应该输出
NAME COLOR SIZE
example3 green M
子资源
自定义资源支持 /status 和 /scale 子资源。
可以通过在 CustomResourceDefinition 中定义它们来选择性地启用状态和缩放子资源。
状态子资源
启用状态子资源后,将公开自定义资源的 /status 子资源。
状态和 spec 部分分别由自定义资源中的
.status和.specJSONPath 表示。对
/status子资源进行的PUT请求接收一个自定义资源对象,并忽略对状态部分以外的任何内容的更改。对
/status子资源进行的PUT请求仅验证自定义资源的状态部分。对自定义资源进行的
PUT/POST/PATCH请求会忽略对状态部分所做的更改。除了对
.metadata或.status的更改之外,.metadata.generation值会增加所有更改。仅允许以下结构位于 CRD OpenAPI 验证模式的根目录
description示例exclusiveMaximumexclusiveMinimumexternalDocsformatitemsmaximummaxItemsmaxLengthminimumminItemsminLengthmultipleOfpatternpropertiesrequiredtitletypeuniqueItems
缩放子资源
启用缩放子资源后,将公开自定义资源的 /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 路径指向的字段必须是字符串字段(不是复杂的选择器结构),其中包含字符串形式的序列化标签选择器。
在以下示例中,同时启用了状态和缩放子资源。
将 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
接下来
了解有关 自定义资源 的更多信息。