Kubernetes CRD 自定义资源
1. CRD 简介
Custom resources:是对K8S API的扩展,代表了一个特定的kubetnetes的定制化安装。通过自定义资源定义(CRD),用户可以将新的资源类型动态的注册到集群中。一旦自定义资源类型被注册,用户可以像操作其他 Kubernetes 资源(如 Pod)一样,通过 Kubernetes API 创建、管理和访问这些自定义对象。Custom controllers:Custom resources可以让用户简单的存储和获取结构化数据。只有结合控制器才能变成一个真正的declarative API(被声明过的API)。控制器可以把资源更新成用户想要的状态,并且通过一系列操作维护和变更状态。定制化控制器是用户可以在运行中的集群内部署和更新的一个控制器,它独立于集群本身的生命周期。
定制化控制器可以和任何一种资源一起工作,当和定制化资源结合使用时尤其有效。
Operator模式 是一个customer controllers和Custom resources结合的例子。它可以允许开发者将特殊应用编码至kubernetes的扩展API内。
2. 使用场景
Kubernetes 中的 Custom Resource Definitions (CRD) 允许用户扩展 Kubernetes API,定义自定义资源类型,适用于多种场景,如应用管理、跨团队资源共享、多租户资源隔离、复杂业务对象的定义、资源生命周期自动化等。常见的 Operator 组件,如 Prometheus Operator 和 Fluent Bit Operator,也都是通过 CRD 扩展 Kubernetes API 来简化和自动化特定应用(如监控、日志收集)的管理。通过 CRD 和 Operator,用户可以创建和管理自定义资源,并自动化其生命周期管理。
如何添加一个Custom resources到我的kubernetes集群呢? kubernetes提供了两种方式将Custom resources添加到集群。
- Custom Resource Definitions (CRDs):更易用、不需要编码。但是缺乏灵活性。
- API Aggregation:需要编码,允许通过聚合层的方式提供更加定制化的实现。
本文重点讲解Custom Resource Definitions (CRD)的使用方法。
3. 操作环境
kubernetes 1.21.5 集群。
4.自定义资源
这里假设大家对k8s 相关的基础资源已经了解,本次使用的yaml文件crontab_crd.yaml(相当于关系型数据库定义表)。
apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: # 称必须与下面的spec字段匹配,格式为: <plural>.<group> name: crontabs.crd.test.com spec: # 用于REST API的组名称: /apis/<group>/<version> group: crd.test.com versions: - name: v1 # 每个版本都可以通过服务标志启用/禁用。 served: true # 必须将一个且只有一个版本标记为存储版本。 storage: true scope: Namespaced # 指定crd资源作用范围在命名空间或集群 names: # URL中使用的复数名称: /apis/<group>/<version>/<plural> plural: crontabs # 在CLI(shell界面输入的参数)上用作别名并用于显示的单数名称 singular: crontab kind: CronTab # 短名称允许短字符串匹配CLI上的资源,意识就是能通过kubectl 在查看资源的时候使用该资源的简名称来获取。 shortNames: - ct
创建crd:
kubectl apply -f crontab_crd.yaml
查看crd:
kubectl get crd | grep crontab
查看api:
准备 test_crontab.yaml(相当于关系型数据库表中插入一行)。:
apiVersion: crd.test.com/v1 kind: CronTab metadata: name: my-test-crontab spec: cronSpec: "* * * * */10" image: my-test-image replicas: 2
创建:
kubectl apply -f test_crontab.yml
查看 ct:
删除自定义对象:
kubectl delete ct my-test-crontab
删除crd:
kubectl delete crd crontabs.crd.test.com
5. 自定义资源-validations
准备 crontab_crd_validation.yml,主要改动为新增validation部分:validation这个验证是为了在创建好自定义资源后,通过该资源创建对象的时候,对象的字段中存在无效值,则创建该对象的请求将被拒绝,否则会被创建。我们可以在crd文件中添加“validation:”字段来添加相应的验证机制。
apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: # 称必须与下面的spec字段匹配,格式为: <plural>.<group> name: crontabs.crd.test.com spec: # 用于REST API的组名称: /apis/<group>/<version> group: crd.test.com versions: - name: v1 # 每个版本都可以通过服务标志启用/禁用。 served: true # 必须将一个且只有一个版本标记为存储版本。 storage: true scope: Namespaced # 指定crd资源作用范围在命名空间或集群 names: # URL中使用的复数名称: /apis/<group>/<version>/<plural> plural: crontabs # 在CLI(shell界面输入的参数)上用作别名并用于显示的单数名称 singular: crontab kind: CronTab # 短名称允许短字符串匹配CLI上的资源,意识就是能通过kubectl 在查看资源的时候使用该资源的简名称来获取。 shortNames: - ct validation: openAPIV3Schema: properties: spec: properties: cronSpec: #必须是字符串、符合正则规则 type: string pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' replicas: #设置副本数的限制 type: integer minimum: 1 maximum: 10
创建不符合的对象:
apiVersion: crd.test.com/v1 kind: CronTab metadata: name: my-test-crontab spec: cronSpec: "* * * * */10" image: my-test-image replicas: 15
上面的replicas为15 所以创建报错限制的最大值为10;
6. 自定义资源-additionalPrinterColumns
从Kubernetes 1.11开始,kubectl使用服务器端打印。服务器决定由kubectl get命令显示哪些列即在我们获取一个内置资源的时候会显示出一些列表信息(比如:kubectl get nodes)。这里我们可以使用CustomResourceDefinition自定义这些列,当我们在查看自定义资源信息的时候显示出我们需要的列表信息。通过在crd文件中添加“additionalPrinterColumns:”字段,在该字段下声明需要打印列的的信息
准备crontab_crd_additionalPrinterColumns.yml:
apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: # 称必须与下面的spec字段匹配,格式为: <plural>.<group> name: crontabs.crd.test.com spec: # 用于REST API的组名称: /apis/<group>/<version> group: crd.test.com versions: - name: v1 # 每个版本都可以通过服务标志启用/禁用。 served: true # 必须将一个且只有一个版本标记为存储版本。 storage: true scope: Namespaced # 指定crd资源作用范围在命名空间或集群 names: # URL中使用的复数名称: /apis/<group>/<version>/<plural> plural: crontabs # 在CLI(shell界面输入的参数)上用作别名并用于显示的单数名称 singular: crontab kind: CronTab # 短名称允许短字符串匹配CLI上的资源,意识就是能通过kubectl 在查看资源的时候使用该资源的简名称来获取。 shortNames: - ct validation: openAPIV3Schema: properties: spec: properties: cronSpec: #必须是字符串、符合正则规则 type: string pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' replicas: #设置副本数的限制 type: integer minimum: 1 maximum: 10 additionalPrinterColumns: - name: Replicas type: integer JSONPath: .spec.replicas - name: Age type: date JSONPath: .metadata.creationTimestamp
准备test_crontab.yml:
apiVersion: crd.test.com/v1 kind: CronTab metadata: name: my-test-crontab spec: cronSpec: "* * * * */10" image: my-test-image replicas: 2
7. 自定义资源-subresources
一般我们要是没有在自定义资源当中配置关于资源对象的伸缩和状态信息的一些相关配置的话,那么在当我们通过该自定义资源创建对象后,又想通过“kubectl scale”来弹性的扩展该对象的容器的时候就会无能为力。而CRD可以允许我们添加该方面的相关配置声明,从而达到我们可以对自定义资源对象的伸缩处理。添加“ subresources:”字段来声明状态和伸缩信息。
准备crontab_crd_subresources.yml:
apiVersion: apiextensions.k8s.io/v1beta1 kind: CustomResourceDefinition metadata: # 称必须与下面的spec字段匹配,格式为: <plural>.<group> name: crontabs.crd.test.com spec: # 用于REST API的组名称: /apis/<group>/<version> group: crd.test.com versions: - name: v1 # 每个版本都可以通过服务标志启用/禁用。 served: true # 必须将一个且只有一个版本标记为存储版本。 storage: true scope: Namespaced # 指定crd资源作用范围在命名空间或集群 names: # URL中使用的复数名称: /apis/<group>/<version>/<plural> plural: crontabs # 在CLI(shell界面输入的参数)上用作别名并用于显示的单数名称 singular: crontab kind: CronTab # 短名称允许短字符串匹配CLI上的资源,意识就是能通过kubectl 在查看资源的时候使用该资源的简名称来获取。 shortNames: - ct validation: openAPIV3Schema: properties: spec: properties: cronSpec: #必须是字符串、符合正则规则 type: string pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' replicas: #设置副本数的限制 type: integer minimum: 1 maximum: 10 additionalPrinterColumns: - name: Replicas type: integer JSONPath: .spec.replicas - name: Age type: date JSONPath: .metadata.creationTimestamp subresources: scale: specReplicasPath: .spec.replicas statusReplicasPath: .status.replicas
准备test_crontab.yml:
apiVersion: crd.test.com/v1 kind: CronTab metadata: name: my-test-crontab spec: cronSpec: "* * * * */10" image: my-test-image replicas: 2
测试:
kubectl scale --replicas=5 crontabs/my-test-crontab
8、新版本k8s(1.22+)创建或者修改CRD!!!
上文中第四章节在Kubernetes集群中创建新的CRD时给出警告,说apiextensions.k8s.io/v1beta1在k8s 1.16版本已强烈反对,在k8s 1.22将不可用,需要使用v1稳定版本。
同上,在上文中第五章节修改CRD,添加validations信息也是使用apiextensions.k8s.io/v1beta1版本,apply crd yaml文件时给出了同样的警告。本文使用的是k8s 1.21,应该改成apiextensions.k8s.io/v1版本。
先删除上文中创建的CRD,改成apiextensions.k8s.io/v1后再发布。
新的crontab_crd_subresources.yml如下:
apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: # 称必须与下面的spec字段匹配,格式为: <plural>.<group> name: crontabs.crd.test.com spec: # 用于REST API的组名称: /apis/<group>/<version> group: crd.test.com versions: - name: v1 # 每个版本都可以通过服务标志启用/禁用。 served: true # 必须将一个且只有一个版本标记为存储版本。 storage: true scope: Namespaced # 指定crd资源作用范围在命名空间或集群 names: # URL中使用的复数名称: /apis/<group>/<version>/<plural> plural: crontabs # 在CLI(shell界面输入的参数)上用作别名并用于显示的单数名称 singular: crontab kind: CronTab # 短名称允许短字符串匹配CLI上的资源,意识就是能通过kubectl 在查看资源的时候使用该资源的简名称来获取。 shortNames: - ct validation: openAPIV3Schema: properties: spec: properties: cronSpec: #必须是字符串、符合正则规则 type: string pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' replicas: #设置副本数的限制 type: integer minimum: 1 maximum: 10
创建新版本CRD:
报错apiextensions.k8s.io/v1版本spec规格配置下不知道validation字段,查看官方配置文件(kuberneters 官方文档),发现字段验证已经改了,改到了spec.versions.schema下。
CRD 对象在定制字段中保存结构化的数据,这些字段和内置的字段 apiVersion、kind 和 metadata 等一起存储,不过内置的字段都会被 API 服务器隐式完成合法性检查。有了 OpenAPI v3.0 检查 能力之后,你可以设置一个模式(Schema),在创建和更新定制对象时,这一模式会被用来对对象内容进行合法性检查。
在 apiextensions.k8s.io/v1 版本中,CustomResourceDefinition 的这一结构化模式定义是必需的。 在 CustomResourceDefinition 的 beta 版本中,结构化模式定义是可选的。
apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: crontabs.crd.test.com spec: group: crd.test.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}$' replicas: type: integer minimum: 1 maximum: 10 scope: Namespaced names: plural: crontabs singular: crontab kind: CronTab shortNames: - ct
再次创建不报错。
重点解释下openAPIV3Schema内容:
- spec.type: object 指定spec是一个对象;
- spec.properties.cronSpec.type: string 指定cronSpec是一个字符串
- spec.properties.cronSpec.pattern: '^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$' 使用正则表达式定义了cronSpec的格式,必须匹配一个cron表达式。cron表达式用于指定任务的执行时间
- spec.properties.replicas.type: integer 指定replicas是一个整数
- spec.properties.replicas.minimum/maximum 指定replicas的最小值为1,最大值为10
通过定义openAPIV3Schema,Kubernetes可以自动校验用户提交的crontab资源对象是否符合预期的数据格式和值范围,从而避免数据错误或不一致。
创建CR,在上文中第五章节修改CRD,添加validations信息,给cronSpec、replicas字段添加了验证信息,其他字段是没有添加验证信息的,能够正常创建CR。
apiVersion: crd.test.com/v1 kind: CronTab metadata: name: my-test-crontab spec: cronSpec: "* * * * */10" image: my-test-image replicas: 2
新版本创建报错,如果配置了properties字段后,需要每个字段都验证。
error validating data: ValidationError(CronTab.spec): unknown field "image" in com.test.crd.v1.CronTab.spec; if you choose to ignore these errors, turn validation off with --validate=false
如果不想对字段加验证,可以这么做(不再对指定字段加验证,不推荐):
apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: crontabs.crd.test.com spec: group: crd.test.com versions: - name: v1 served: true storage: true schema: openAPIV3Schema: type: object properties: spec: type: object x-kubernetes-preserve-unknown-fields: true #必须加此字段,不然没有加验证规则的字段都会被裁剪 scope: Namespaced names: plural: crontabs singular: crontab kind: CronTab shortNames: - ct
注意 1:apiextensions.k8s.io/v1版本,schema.openAPIV3Schema是必填字段,如果不写创建CRD报错。
注意 2:x-kubernetes-preserve-unknown-fields: true #必须加此字段,不然没有加验证规则的字段都会被裁剪,对于以上示例如果不加此字段结果为:
详细openAPIV3Schema语法参加官方文档,本文不再赘余。