2.1.1 CRD介绍
1. 声明式 API
什么是声明式 API呢?首先我们需要了解在Kubernetes中,使用 Deployment、DamenSet,StatefulSet等资源来管理应用 Workload,使用 Service、Ingress等来管理应用的访问方式,使用 ConfigMap和 Secret 来管理应用配置。在集群中对这些资源的创建、更新、删除的动作都会被转换为事件(Event),Kubernetes 的 Controller Manager 负责监听这些事件并触发相应的任务来满足用户的期望。这种方式称为声明式,用户只需要关心应用程序的最终状态,其他的过程都通过 Kubernetes来完成,通过这种方式可以大大简化应用配置管理的复杂度。
声明式 API指的是用户提交一个定义好的 API 对象来描述所期望的状态。例如上面创建的Namespace 资源,这个资源类型表明用户期望的结果是创建一个名字为Nginx的命名空间。那么用户无须关心如何创建 Namespaces资源,只需要关注结果即可。
什么是过程式 API呢?过程式 API 一次只能处理一个写请求,否则可能会产生冲突,已不具备合并操作的能力 。
声明式 API的特点是允许有多个 API写端以 PATCH的方式对 API对象进行修改,而无须关心本地原始Yaml 文件的内容。声明式API才是Kubernetes 项目编排能力的核心。对于 API对象的增、删、改、查,可以在完全无须外界干预的情况下,完成对“实际状态”和“期望状态”的调谐(Reconcile)过程。这种调谐过程的实现者则是 Controller的处理逻辑。
当开发者对 Kubernetes 的使用逐渐增多之后,会发现这些默认的资源不足以支撑我们的系统,以 NginxIngress 为例,如果用户想要实现负载均衡限流器功能,目前 NiginxIngress 的配置不支持这样的特性,对于这种非通用的特性,Kubernetes提供了一种扩展性的支撑方式,即自定义资源。
典型地,声明式 API特点如下。
(1)你的 API 包含相对而言为数不多、尺寸较小的对象(资源)。
(2)对象定义了应用或者基础设施的配置信息。
(3)对象更新操作频率较低。
(4)通常需要人来读取或写入对象。
(5) 对象的主要操作是 CRUD风格的(创建、读取、更新和删除)。
(6) 不需要跨对象的事务支持:API 对象代表的是期望状态而非确切实际状态。命令式 API与声明式有所不同。 以下迹象表明你的 API可能不是声明式 API。
(1)客户端发出“做这个操作”的指令,之后在该操作结束时获得同步响应。
(2)客户端发出“做这个操作”的指令,并获得一个操作 ID,之后需要检查一个Operation对象来判断请求是否成功完成。
(3)将你的 API类比为 RPC。
(4)需要较高的访问带宽(长期保持每秒数十个请求)。
(5)在对象上执行的常规操作并非是CRUD。
(6) API 不太容易用对象来建模。
2. CRD场景
什么是 CRD呢?为什么要有 CRD资源呢?通过对下面内容的学习,大家会对 CRD有概念性的认识。首先 Kubernetes 为用户提供了丰富的资源,如资源对象、配置对象、存储对象和策略对象,如表 2-1所示。
表 2-1资源对象表
类别 |
名称 |
资源对象 |
Pod、ReplicaSet、Deployment、StatefulSet、DammonSet、Job、CronJob |
配置对象 |
Node、Namespace、Service、ConfigMap、Ingress、Label |
存储对象 |
Volume、Persistent Volume |
策略对象 |
SecurityContext、ResourceQuota、LimitRange |
虽然 Kubernetes 为我们提供了丰富的资源类型,但是在不同应用场景下,某些传统资源类型仍不能满足用户需求,他们对平台可能存在一些特殊的需求,为了满足这些需求,Kubernetes社区为我们提供了一种抽象Kubernetes的扩展资源。这种抽象的资源类型叫作自定义资源定义(CRD,Custom Resource Definition)。CRD为我们提供资源的快速注册和使用的接口。其实在很早的k8s 版本中自定义资源就已经被提出,当时叫作TPR(ThirdPartyResource),这是与CRD类似的概念,但是在1.9以上的版本中被弃用,而 CRD则进入 beta 状态。
(1)什么时候需要添加定制资源?
① 你希望使用 Kubernetes客户端库和 CLI 来创建和更改新的资源。
② 你希望 Kubectl 能够直接支持你的资源。
③ 你希望构造新的自动化机制,监测新对象的更新事件,并对其他对象执行 CRUD(增加、检索、更新、删除)操作,或者监测后者更新前者。
④ 你希望编写自动化组件来处理对对象的更新。
⑤ 你希望使用 KubernetesAPI对诸如 .spec、.status和 .metadata 等字段进行约定。
⑥ 你希望对象是对一组受控资源的抽象,或者对其他资源的归纳提炼。
(2) 如何定义一个 CRD?
我们通过代码清单 2-3中的 Yaml文件来创建一个 AppconfigCRD资源。
apiVersion:apiextensions.k8s.io/v1kind:CustomResourceDefinitionmetadata:
# 名称必须符合下⾯的格式 :<plural>.<group>
name:crontabs.stable.example.comspec:
# RESTAPI使⽤的组名称 :/apis/<group>/<version>
group:stable.example.com
# RESTAPI使⽤的版本号 :/apis/<group>/<version>versions:
-name:v1
# 可以通过served来开关每个版本
served:true
# 有且仅有⼀个版本开启存储
storage:trueschema:
openAPIV3Schema:
type:objectproperties:
spec:
type:objectproperties:
cronSpec:type:string
image:
type:stringreplicas:
type: integer# Namespaced或Cluster
scope:Namespacednames:
# URL中使⽤的复数名称: /apis/<group>/<version>/<plural>
plural:crontabs
# CLI中使⽤的单数名称
singular:crontab
# CamelCased格式的单数类型。在清单⽂件中使⽤
kind:CronTab
# CLI中使⽤的资源简称
shortNames:
-ct
首先我们解释一下创建的 CRD 的参数。
① 第一行和第二行我们定义了 CRD的版本。
② metadata定义了访问的 CRD资源的名称,名称必须与下面的 spec字段匹配。
③ Spec.group 定义了资源属于什么组,这里我们定义成 stable.example.com。
④ Spec.versions 定义了资源存储的版本,这里定义为 v1。
⑤ scope定义了我们创建的资源的作用范围?这里定义成Namespace范围。
⑥ pluralsingular 定义了资源的单复数形式,这个根据实际情况命名即可。
我们执行 kubectlapply-fcrd.yaml就可以创建名称为 appconfig 的 CRD 资源了。同时我们定义的 CRD资源 RESTfulAPI将会定义成 /apis/stable.example.com/v1/namespaces/*/crontabs/。
(3) 如何创建一个CRD 实例对象?
首先定义一个符合上面CRD资源的apiVersion和资源类型(kind)(见代码清单2-4)。
apiVersion:"stable.example.com/v1"kind:CronTab
metadata:
name:my-new-cron-objectspec:
cronSpec:"*****/5"
image:my-awesome-cron-image
创建 CRD对象后,可以创建自定义对象,自定义对象可包含自定义字段。这些字段可以包含任意 JSON。如代码清单2-4所示,cronSpec 和 image 自定义字段在自定义对象中设置 CronTab。CronTab类型来自上面创建的 CRD对象的规范,然后执行kubectleapply-fmy-crontab.yaml即可。