欢送拜访我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,波及Java、Docker、Kubernetes、DevOPS等;

系列文章链接

  1. kubebuilder实战之一:筹备工作
  2. kubebuilder实战之二:首次体验kubebuilder
  3. kubebuilder实战之三:基础知识速览
  4. kubebuilder实战之四:operator需要阐明和设计
  5. kubebuilder实战之五:operator编码
  6. kubebuilder实战之六:构建部署运行
  7. kubebuilder实战之七:webhook
  8. kubebuilder实战之八:知识点小记

本篇概览

  • 作为《kubebuilder实战》系列的第四篇,经验了后面的充分准备,从本篇开始,咱们来开发一个有理论作用的operator,该operator名为<font color="blue">elasticweb</font>,既弹性web服务;
  • 这将是一次残缺的operator开发实战,设计、编码、部署等环节都会参加到,与《kubebuilder实战之二:首次体验kubebuilder》的不同之处在于,elasticweb从CRD设计再到controller性能都有明确的业务含意,能执行业务逻辑,而《kubebuilder实战之二》仅仅是一次开发流程体验;
  • 为了做好这个operator,本篇不急于编码,而是认真的做好设计工作,咱们的operator有什么性能,解决了什么问题,有哪些核心内容,都将在本篇整顿分明,有了这样的筹备,能力在下一章写出符合要求的代码;
  • 接下来咱们先聊一些背景常识,以便更好的进入正题;

需要背景

  • QPS:Queries-per-second,既每秒查问率,就是说服务器在一秒的工夫内解决了多少个申请;
  • 背景:做过网站开发的同学对横向扩容应该都理解,简略的说,假如一个tomcat的QPS下限为500,如果内部拜访的QPS达到了600,为了保障整个网站服务质量,必须再启动一个同样的tomcat来独特摊派申请,如下图所示(简略起见,假如咱们的后盾服务是无状态的,也就是说不依赖宿主机的IP、本地磁盘之类):

  • 以上是横向扩容惯例做法,在kubernetes环境,如果内部申请超过了单个pod的解决极限,咱们能够减少pod数量来达到横向扩容的目标,如下图:

  • 以上就是背景信息,接下来咱们聊聊elasticweb这个operator的具体性能;

需要阐明

  • 为了说分明需要,这里虚构一个场景:小欣是个java开发者,就是下图这个妹子:

  • 当初小欣要将springboot利用部署到kubernetes上,她的现状和面临的问题如下:
  • springboot利用已做成docker镜像;
  • 通过压测得出单个pod的QPS为500;
  • 估算得出上线后的总QPS会在800左右;
  • 随着经营策略变动,QPS还会有调整;
  • 总的来说,小欣手里只有三个数据:docker镜像、单个pod的QPS、总QPS,她对kubernetes不理解,须要有个计划来帮她将服务部署好,并且在运行期间能撑持内部的高并发拜访;

以上就是小欣的需要了,咱们来小结一下:

  1. 咱们为小欣开发一个operator(名为<font color="blue">elasticweb</font>),对小欣来说,她只有将手里的三个参数(docker镜像、单个pod的QPS、总QPS)通知elasticweb就完事儿了;
  2. elasticweb在kubernetes创立pod,至于pod数量当然是主动算进去的,要确保能满足QPS要求,以后面的状况为例,须要两个pod能力满足800的QPS;
  3. 单个pod的QPS和总QPS都随时可能变动,一旦有变,elasticweb也要主动调整pod数量,以确保服务质量;
  4. 为了确保服务能够被内部调用,咱们再顺便帮小欣创立好service(她对kubernetes理解不多,这事儿咱们就棘手做了吧);

自保申明

  • 看过上述需要后,聪慧的您肯定会对我投来鄙视的眼光,其实kubernetes早就有现成的QPS调节计划了,例如批改deployment的正本数、单个pod纵向扩容、autoscale等都能够,本次应用operator来实现仅仅是为了展现operator的开发过程,并不是说自定义operator是惟一的解决方案;
  • 所以,如果您感觉我这种用operator实现扩容的形式很low,<font color="red">请不要把我骂得太惨</font>,我这也只是为了展现operator开发过程而已,况且咱这个operator也不是一无是处,用了这个operator,您就不必关注pod数量了,只有聚焦单实例QPS和总QPS即可,这两个参数更贴近业务;
  • 为了不把事件弄简单,<font color="blue">假如每个pod所需的CPU和内存是固定的</font>,间接在operator代码中写死,其实您也能够本人改代码,改成能够在内部配置,就像镜像名称参数那样;
  • 把需要都交代分明了,接下来进入设计环节,先把CRD设计进去,这可是外围的数据结构;

CRD设计之Spec局部

Spec是用来保留用户的期望值的,也就是小欣手里的三个参数(docker镜像、单个pod的QPS、总QPS),再加上端口号:

  1. image:业务服务对应的镜像
  2. port:service占用的宿主机端口,内部申请通过此端口拜访pod的服务
  3. singlePodQPS:单个pod的QPS下限
  4. totalQPS:以后整个业务的总QPS
  5. 对小欣来说,输出这四个参数就完事儿了;

CRD设计之Status局部

  • Status用来保留理论值,这里设计成只有一个字段<font color="blue">realQPS</font>,示意以后整个operator理论能反对的QPS,这样无论何时,只有小欣用<font color="blue">kubectl describe</font>命令就能晓得以后零碎实际上能反对多少QPS;

CRD源码

  • 把数据结构说明确的最好办法就是看代码:
package v1import (    "fmt"    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"    "strconv")// 冀望状态type ElasticWebSpec struct {    // 业务服务对应的镜像,包含名称:tag    Image string `json:"image"`    // service占用的宿主机端口,内部申请通过此端口拜访pod的服务    Port *int32 `json:"port"`    // 单个pod的QPS下限    SinglePodQPS *int32 `json:"singlePodQPS"`    // 以后整个业务的总QPS    TotalQPS *int32 `json:"totalQPS"`}// 理论状态,该数据结构中的值都是业务代码计算出来的type ElasticWebStatus struct {    // 以后kubernetes中理论反对的总QPS    RealQPS *int32 `json:"realQPS"`}// +kubebuilder:object:root=true// ElasticWeb is the Schema for the elasticwebs APItype ElasticWeb struct {    metav1.TypeMeta   `json:",inline"`    metav1.ObjectMeta `json:"metadata,omitempty"`    Spec   ElasticWebSpec   `json:"spec,omitempty"`    Status ElasticWebStatus `json:"status,omitempty"`}func (in *ElasticWeb) String() string {    var realQPS string    if nil == in.Status.RealQPS {        realQPS = "nil"    } else {        realQPS = strconv.Itoa(int(*(in.Status.RealQPS)))    }    return fmt.Sprintf("Image [%s], Port [%d], SinglePodQPS [%d], TotalQPS [%d], RealQPS [%s]",        in.Spec.Image,        *(in.Spec.Port),        *(in.Spec.SinglePodQPS),        *(in.Spec.TotalQPS),        realQPS)}// +kubebuilder:object:root=true// ElasticWebList contains a list of ElasticWebtype ElasticWebList struct {    metav1.TypeMeta `json:",inline"`    metav1.ListMeta `json:"metadata,omitempty"`    Items           []ElasticWeb `json:"items"`}func init() {    SchemeBuilder.Register(&ElasticWeb{}, &ElasticWebList{})}

业务逻辑设计

  • CRD的实现代表外围数据结构曾经确定,接下来是业务逻辑的设计,次要是理分明controller的Reconcile办法外面做些啥,其实外围逻辑还是非常简单的:算出须要多少个pod,而后通过更新deployment让pod数量达到要求,在此外围的根底上再把创立deployment和service、更新status这些琐碎的事件做好,就完事儿了;
  • 这里将整个业务逻辑的流程图给进去如下所示,用于领导开发:

  • 至此,咱们实现了整个elasticweb的需要和设计,聪慧的您必定曾经胸有成竹,而且急不可待的想启动开发了,好的,下一篇咱们正式开始编码!

参考资料

  • 您可能会奇怪,小欣对kubernetes不理解,怎么会晓得docker镜像的制作,还有单个pod的QPS她是怎么测的呢?
  • 其实她是程序员欣宸的粉丝,曾经浏览过以下博客:
  • 《SpringBoot-2.3镜像计划为什么要做多个layer》
  • 《体验SpringBoot(2.3)利用制作Docker镜像(官网计划)》
  • 《详解SpringBoot(2.3)利用制作Docker镜像(官网计划)》
  • 《Kubernetes下web服务的性能测试三部曲之一:筹备工作》
  • 《Kubernetes下web服务的性能测试三部曲之二:纵向扩容》
  • 《Kubernetes下web服务的性能测试三部曲之三:横向扩容》

你不孤独,欣宸原创一路相伴

  1. Java系列
  2. Spring系列
  3. Docker系列
  4. kubernetes系列
  5. 数据库+中间件系列
  6. DevOps系列

欢送关注公众号:程序员欣宸

微信搜寻「程序员欣宸」,我是欣宸,期待与您一起畅游Java世界...
https://github.com/zq2599/blog_demos