从零开始设计一个CRD
前言
经过前面的铺垫,相信现在对kubebuilder的工作模式已初具了解,那么从本篇开始,正式设计一个CRD。本文对于Unit的设计,是基于我的个人场景下的需求提炼出来的,不一定适合你,但着重点在于思路,希望能有帮助。
面临的现状
在我的场景下,应该也是大多数人的场景下,通常一个运行服务(姑且这么称呼),使用一系列build-in 类型资源进行组合,来保障运行和提供服务,例如,最常用的组合有:StatefulSet/Deployment/Ingress/Service/Ingress这几种资源的按需组合,如下图:
这些资源类型每一种都是可选项,根据使用需求的不同,来灵活(弱绑定?)进行组合。
例如:
- 非web服务不需要Ingress资源
- 自发现和注册的应用不需要Service
- 无状态的应用选用Deployment,有状态的应用选用StatefulSet
- 有的应用无需持久存储,有的应用需求PVC来实现持久存储
按需组合,不一而同
这样的弱绑定关系在个人认为管理上不足够的友好,每种资源的增删改查等逻辑,需要分别操作,没有整体的连贯性和协同性,需要分而治之。
想要实现什么
与市面上大多数专属于某个应用或者某类应用的CRD不同,我这里想要实现的CRD目标是:每一个运行服务,所用到的的各类资源,以强申明将它们绑定在一起,进行统一的生命周期管理
因此,我给这个CRD的命名是Unit,这意味着,StatefulSet/Deployment/Ingress/Service/Ingress这些可选的build-in资源,由原本松散组合构成一个运行服务的模式,变为集合在一个Unit单元里,形成统一的管理生命周期。如下图:
设计的目标已经设定了,下面就开始实际设计和填充Unit结构体。
结构设计
如同所有的build-in GVR一样,结构体的构成除了主要分为两个部分,一个是Spec,一个是Status,声明式的目标即是Status满足Spec的声明要求。因此,Unit的结构体设计也围绕Spec和Status两部分来。下面直接贴代码,代码中会有注释。
按照上面的描述,Unit总共可管理这5种资源:StatefulSet/Deployment/Ingress/Service/Ingress,为了结构清晰,将它们各自的结构体分别放在不同的文件中:
原本的build-in资源结构体,以Deployment举例,Deployment结构体字段非常多,不够精简,因此我不想每种资源的每个字段都完整声明,而是在前端以最精简地方式声明,只提供必要的字段,而最后填充出完整的Deployment的结构体的方法放在后端来进行,尽可能地保证前端使用用户的友好度。
Spec
直接贴代码
UnitSpec
1 | // UnitSpec defines the desired state of Unit |
UnitRelationResourceSpec
1 | type UnitRelationResourceSpec struct { |
这里指定OwnService/OwnIngress/OwnPVC,至于具体的ownDeployment / ownStatefulSet,由于限制二种部署方式只能取其一,因此会结合UnitSpec.Category和UnitSpec.Template来动态生成,怎么生成放在后面说,先来看看结构体。
OwnStatefulSet
1 | type OwnStatefulSet struct { |
OwnDeployment
1 | type OwnDeployment struct { |
OwnService
1 | // svc的端口映射关系 |
OwnIngress
1 | // ingress信息 |
OwnPVC
1 | // pvc声明信息 |
大部分都是利用原resource.Spec字段,这样在精简的同时,生成resource object的时候也可以比较方便。
Status
Unit.Status设计就比较天马行空了,例如我希望在状态里面看到与Service和Pod自动关联的Endpoints逻辑资源,因此把部分Endpoint的信息也加了进来。
UnitStatus
1 | // UnitStatus defines the observed state of Unit |
UnitRelationServiceStatus
1 | type UnitRelationServiceStatus struct { |
UnitRelationEndpointStatus
1 | type UnitRelationEndpointStatus struct { |
原ServiceStatus信息量太少,就用了一个自定义的status填充了一下,其余的资源类型的Status,如DeploymentStatus/StatefulSetStatus/PersistentVolumeClaimStatus 信息量已经足够了,偷下懒直接利用。
总结
Unit的实现目标确定后,设计和填充了它的结构体,同时为了保持结构体的精简,简化出了一层ownResource,同样也设计和填充ownResources的Spec和Status结构。基础已经铺垫好,下一篇开始设计和实现Unit Reconciler的控制逻辑,以管理Unit和ownResources之间的生命周期的联动。