简介
k8s中的 CRD(Custom Resource Definition)是一种强大的功能,允许用户通过定义自己的资源来扩展 k8s API。这意味着用户可以创建自定义的资源类型,这些资源类型与 k8s 内置的资源(如 Pods、Deployments 等)具有相同的 API 风格。CRD 为 k8s 生态系统的扩展和自定义提供了极大的灵活性。
- 自定义资源(Custom Resource):用户定义的资源类型,可以通过 k8s API 进行管理。自定义资源的实例被 k8s 存储在 etcd 中,并可以通过 k8s API 访问。
- 自定义资源定义(Custom Resource Definition):定义自定义资源的 YAML 文件。它告诉 k8s 如何理解这个新资源的结构,包括资源的名称、版本、字段等。
官方文档:https://kubernetes.io/zh-cn/docs/concepts/extend-kubernetes/api-extension/custom-resources/
创建CRD
即编写一个 CRD 定义文件,k8s API 服务器会为你所指定的每个版本生成一个新的 RESTful 资源路径。 基于 CRD 对象所创建的自定义资源可以是 namespace 作用域的,也可以是集群作用域的, 取决于 CRD 对象 spec.scope
字段的设置。
与其它的内置对象一样,删除名字空间也将删除该名字空间中的所有自定义对象。 CRD 本身是无 namespace 的,可在所有 namespace 中访问。
下面是一个crontab CRD示例的yaml文件:
cat crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
# 名字必需与下面的 spec 字段匹配,格式为 <plural>.<group>
name: crontabs.stable.example.com
spec:
# 组名称,用于 REST API: /apis/<group>/<version>
group: stable.example.com
# 列举此 CustomResourceDefinition 所支持的版本
versions:
- name: v1
# 每个版本都可以通过 served 服务标志启用/禁用
served: true
# 有且仅有一个版本被标记为存储版本。
storage: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
cronSpec:
type: string
image:
type: string
replicas:
type: integer
# 可以是 Namespaced 或 Cluster
scope: Namespaced
names:
# URL中使用的复数名称: /apis/<group>/<version>/<plural>
plural: crontabs
# 名称的单数形式,作为命令行使用时和显示时的别名
singular: crontab
# kind 通常是单数形式的驼峰命名(CamelCased)形式。你的资源清单会使用这一形式。
kind: CronTab
# shortNames 允许你在命令行使用较短的字符串来匹配资源
shortNames:
- ct
k apply -f crd.yaml
这样一个新的受namespace约束的 RESTful API 端点会被创建在:/apis/stable.example.com/v1/namespaces/*/crontabs/...
,此端点 URL 自此可以用来创建和管理定制对象。对象的 kind 将是来自你上面创建时 所用的 spec 中指定的 CronTab。
查看CRD
k get crontab/ct
创建自定义对象
在创建了 CRD 对象之后,你可以创建自定义对象(Custom Objects)。自定义对象可以包含自定义字段。这些字段可以包含任意的 JSON 数据。
cat my-crontab.yaml
apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
name: my-new-cron-object
spec:
cronSpec: "* * * * */5"
image: my-awesome-cron-image
k apply -f my-crontab.yaml
k get ct
删除CRD
k delete -f crd.yaml
k get ct
设置结构化模式
CRD 对象在定制字段中保存结构化的数据,这些字段和内置的字段 apiVersion、kind 和 metadata 等一起存储,不过内置的字段都会被 API 服务器隐式完成合法性检查。有了 OpenAPI v3.0 检查 能力之后,你可以设置一个模式(Schema),在创建和更新定制对象时,这一模式会被用来对对象内容进行合法性检查。
在 apiextensions.k8s.io/v1 版本中,CustomResourceDefinition 的这一结构化模式 定义是必需的。 在 CustomResourceDefinition 的 beta 版本中,结构化模式定义是可选的。
结构化模式本身是一个 OpenAPI v3.0 验证模式,其中:
- 为对象根(root)设置一个非空的 type 值(藉由 OpenAPI 中的 type),对每个 object 节点的每个字段(藉由 OpenAPI 中的 properties 或 additionalProperties)以及 array 节点的每个条目(藉由 OpenAPI 中的 items)也要设置非空的 type 值, 除非:
- 节点包含属性
x-kubernetes-int-or-string: true
- 节点包含属性
x-kubernetes-preserve-unknown-fields: true
- 节点包含属性
- 对于 object 的每个字段或 array 中的每个条目,如果其定义中包含 allOf、anyOf、oneOf 或 not,则模式也要指定这些逻辑组合之外的字段或条目(试比较例 1 和例 2)。
- 在 allOf、anyOf、oneOf 或 not 上下文内不设置 description、type、default、 additionalProperties 或者 nullable。此规则的例外是
x-kubernetes-int-or-string
的两种模式。 - 如果 metadata 被设置,则只允许对
metadata.name
和metadata.generateName
设置约束。
如果违反了结构化模式规则,CRD 的 NonStructural
状况中会包含报告信息。
字段剪裁
CRD 在 etcd 中保存经过合法性检查的资源数据。如果你指定了 API 服务器所无法识别的字段,则该未知字段会在保存资源之前被 剪裁(Pruned) 掉(删除)。
--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 数据格式通过这样设置,JSON 中只能设置 object 类型的值。对于所指定的每个属性(或 additionalProperties),剪裁会再次被启用。
RawExtension
RawExtensions(就像在 k8s.io/apimachinery 项目中 runtime.RawExtension 所定义的那样) 可以保存完整的 Kubernetes 对象,也就是,其中会包含 apiVersion 和 kind 字段。
设置了 x-kubernetes-embedded-resource: true
之后,apiVersion、kind 和 metadata 都是隐式设定并隐式完成合法性验证。
Finalizers
Finalizer 能够让控制器实现异步的删除前(Pre-delete)回调。 与内置对象类似,定制对象也支持 Finalizer。
你可以像下面一样为定制对象添加 Finalizer:
apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
finalizers:
- stable.example.com/finalizer
自定义 Finalizer 的标识符包含一个域名、一个正向斜线和 finalizer 的名称。 任何控制器都可以在任何对象的 finalizer 列表中添加新的 finalizer。删除逻辑和其他资源一样。
合法性检查
定制资源是通过 OpenAPI v3 模式定义 来执行合法性检查的,当启用验证规则特性时,通过 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)表达式来验证定制资源。
也可以通过修改apiserver的配置来关闭检查。--feature-gates=CustomResourceValidationExpressions=false
在下面的例子中, CRD 对定制对象的spec.cronSpec
和spec.replicas
字段执行合法性检查:
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 是验证自定义对象的模式。
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
修改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
修改为合法的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 工具依赖服务器端的输出格式化。你的集群的 API 服务器决定 kubectl get 命令要显示的列有哪些。 你可以为 CRD 定制这些要打印的列。 下面的例子添加了 Spec、Replicas 和 Age 列:
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
输出中包含了 NAME、SPEC、REPLICAS 和 AGE 列。
子资源
定制资源支持 /status
和 /scale
子资源。通过在 CRD 中定义 status 和 scale, 可以有选择地启用这些子资源。下面的例子同时启用了两者。
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 描述定制资源的子资源
subresources:
# status 启用 status 子资源
status: {}
# scale 启用 scale 子资源
scale:
# specReplicasPath 定义定制资源中对应 scale.spec.replicas 的 JSON 路径
specReplicasPath: .spec.replicas
# statusReplicasPath 定义定制资源中对应 scale.status.replicas 的 JSON 路径
statusReplicasPath: .status.replicas
# labelSelectorPath 定义定制资源中对应 scale.status.selector 的 JSON 路径
labelSelectorPath: .status.labelSelector
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ct
再使用下面的yaml创建自定义对象。
apiVersion: "stable.example.com/v1"
kind: CronTab
metadata:
name: my-new-cron-object
spec:
cronSpec: "* * * * */5"
image: my-awesome-cron-image
replicas: 3
然后会创建新的、命名空间作用域的 RESTful API 端点:/apis/stable.example.com/v1/namespaces/*/crontabs/status
和/apis/stable.example.com/v1/namespaces/*/crontabs/scale
。
定制资源可以使用 kubectl scale
命令来扩缩其规模。
kubectl scale --replicas=5 crontabs/my-new-cron-object
kubectl get crontabs my-new-cron-object -o jsonpath='{.spec.replicas}'
=
分类
分类(Categories)是定制资源所归属的分组资源列表(例如,all)。 你可以使用 kubectl get <分类名称> 来列举属于某分类的所有资源。
下面的示例在 CRD 中将 ctab 添加到分类列表中, 并展示了如何使用 kubectl get ctab
来输出定制资源:
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 是定制资源所归属的分类资源列表
categories:
- ctab