controller-manager学习三部曲之三:deployment的controller启动分析

欢迎访问我的GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

《controller-manager学习三部曲》完整链接

  1. 通过脚本文件寻找程序入口
  2. 源码学习
  3. deployment的controller启动分析

本篇概览

  • 本文是《controller-manager学习三部曲》的终篇,前面咱们从启动到运行已经分析了controller-manager的详细工作,对controller-manager有了详细了解,也知道controller-manager最重要的任务是调用各controller的初始化方法,使它们进入正常的工作状态,也就是下面代码的黄色箭头位置
    在这里插入图片描述

  • 这些初始化方法又是哪来的呢?不得不再次提到前文多次遇到的NewControllerInitializers方法,这里面有所有controller的初始化方法
    在这里插入图片描述

  • 现在问题来了:controller有这么多,它们的初始化到底做了些什么?

  • 篇幅所限,自然不可能把每个controller的初始化方法都看一遍,所以咱们还是挑一个典型的来看看吧,就选deployment的controller,也就是上图黄色箭头指向的那行

register(names.DeploymentController, startDeploymentController)
  • 不过在正式阅读deployment的controller启动代码之前,先巩固一下基础,弄清楚register方法是什么

register方法

  • 所有controller都要通过register方法注册,所以这个register有必要了解一下
// controllers是个map,key就是controller的名称了,value是初始化方法
controllers := map[string]InitFunc{}
// register在此定义
register := func(name string, fn InitFunc) {
  // 同一个key不能注册多次 
  if _, found := controllers[name]; found {
    panic(fmt.Sprintf("controller name %q was registered twice", name))
  }
  controllers[name] = fn
}
  • 作为value的InitFunc也非常重要,它对初始化方法的入参和返回值做了定义,保证了一致性
type InitFunc func(ctx context.Context, controllerCtx ControllerContext) (controller controller.Interface, enabled bool, err error)
  • InitFunc会在StartControllers方法中被执行,每个InitFunc执行结束意味着对应controller初始化完成,来看看它的三个返回值
返回值说明
controller创建的controller对象,这是个接口定义,只要求实现Name方法
enabled用于描述创建的controller对象是否可用,如果可用就会做健康检查相关的判断和注册工作
err如果创建过程有错误发生就在此返回,此err一旦不为空就会导致整个controller-manager进程退出
  • 现在准备工作算是完成了,该研究deployment的启动代码了,也就是startDeploymentController方法

且看deployment的controller是如何创建的

  • 如果您看过欣宸之前的《client-go实战》系列,应该对自定义controller的套路非常熟悉,主要是下面这几件事情
  1. 创建队列,并指定处理队列数据的方法
  2. 监听指定类型的资源,待其发生变化的时候将其放入队列,由前面指定的方法来做具体的处理
  • 正因为熟悉了这个套路,才可以提前猜测deployment的controller做的也是这些事情,然后再来验证猜测
  • startDeploymentController方法的源码很简单,先创建对象再调用Run方法启动业务处理逻辑,要注意的是NewDeploymentController的入参,有deployment、replicaset、pod等三种Informer,所以controller会监听这三种资源的变更,然后还有个client在请求api-server时会用到
func startDeploymentController(ctx context.Context, controllerContext ControllerContext) (controller.Interface, bool, error) {
	// 实例化对象
	dc, err := deployment.NewDeploymentController(
		ctx,
		controllerContext.InformerFactory.Apps().V1().Deployments(),
		controllerContext.InformerFactory.Apps().V1().ReplicaSets(),
		controllerContext.InformerFactory.Core().V1().Pods(),
		controllerContext.ClientBuilder.ClientOrDie("deployment-controller"),
	)
	if err != nil {
		return nil, true, fmt.Errorf("error creating Deployment controller: %v", err)
	}
	go dc.Run(ctx, int(controllerContext.ComponentConfig.DeploymentController.ConcurrentDeploymentSyncs))
	return nil, true, nil
}
  • 打开方法,看看deployment的controller具体是如何创建的
func NewDeploymentController(ctx context.Context, dInformer appsinformers.DeploymentInformer, rsInformer appsinformers.ReplicaSetInformer, podInformer coreinformers.PodInformer, client clientset.Interface) (*DeploymentController, error) {
	eventBroadcaster := record.NewBroadcaster()
	logger := klog.FromContext(ctx)
	// 创建deployment的controller对象,注意queue被用来存入要监听的业务变更,然后有对应的processor来处理(这是套路),client也传进去了,里面请求api-server会用到(主要是资源的写操作)
	dc := &DeploymentController{
		client:           client,
		eventBroadcaster: eventBroadcaster,
		eventRecorder:    eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "deployment-controller"}),
		queue:            workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "deployment"),
	}
	// rsControl提供PatchReplicaSet方法,可用于ReplicaSet资源的patch操作
	dc.rsControl = controller.RealRSControl{
		KubeClient: client,
		Recorder:   dc.eventRecorder,
	}
	// 监听Deployment资源的变化,增删改都绑定了对应的处理方法
	dInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			dc.addDeployment(logger, obj)
		},
		UpdateFunc: func(oldObj, newObj interface{}) {
			dc.updateDeployment(logger, oldObj, newObj)
		},
		// This will enter the sync loop and no-op, because the deployment has been deleted from the store.
		DeleteFunc: func(obj interface{}) {
			dc.deleteDeployment(logger, obj)
		},
	})
	// 监听ReplicaSet资源的变化,增删改都绑定了对应的处理方法
	rsInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		AddFunc: func(obj interface{}) {
			dc.addReplicaSet(logger, obj)
		},
		UpdateFunc: func(oldObj, newObj interface{}) {
			dc.updateReplicaSet(logger, oldObj, newObj)
		},
		DeleteFunc: func(obj interface{}) {
			dc.deleteReplicaSet(logger, obj)
		},
	})
	// 监听Pod资源的变化,增删改都绑定了对应的处理方法
	podInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
		DeleteFunc: func(obj interface{}) {
			dc.deletePod(logger, obj)
		},
	})

	// 这是整个controller的核心业务代码,就是收到deployment资源的变化后所做的各种操作
	dc.syncHandler = dc.syncDeployment
	// 入参是对象,功能是将对象的key放入队列
	dc.enqueueDeployment = dc.enqueue

	// 这一堆lister都会用在各种查询的场景
	dc.dLister = dInformer.Lister()
	dc.rsLister = rsInformer.Lister()
	dc.podLister = podInformer.Lister()
	// 是否已经同步的标志
	dc.dListerSynced = dInformer.Informer().HasSynced
	dc.rsListerSynced = rsInformer.Informer().HasSynced
	dc.podListerSynced = podInformer.Informer().HasSynced
	return dc, nil
}
  • 在上面的代码中,果然看到了队列queue,这就是连接生产和消费的关键对象,至于dInformer.Informer().AddEventHandler、rsInformer.Informer().AddEventHandler等方面里面的AddFunc、UpdateFunc等,肯定是监听了deployment、pod的变化,然后将key放入deployment中,为了验证这个猜测,咱们挑一个看看,就看ReplicaSet的AddFunc中的(logger, obj)dc.addReplicaSet,果然,这些资源的变化都会导致相关的资源被放入队列queue
    在这里插入图片描述

  • 至此,咱们对deployment的controller创建算是了解了,接下来要了解controller如何运行,也就是下图黄色箭头所指的方法做了些什么,按照套路,这里面要做的就是让queue的生产和消费正常运转起来
    在这里插入图片描述

  • 方法的代码如下

func (dc *DeploymentController) Run(ctx context.Context, workers int) {
	defer utilruntime.HandleCrash()

	// Start events processing pipeline.
	dc.eventBroadcaster.StartStructuredLogging(0)
	dc.eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: dc.client.CoreV1().Events("")})
	defer dc.eventBroadcaster.Shutdown()

	defer dc.queue.ShutDown()

	logger := klog.FromContext(ctx)
	logger.Info("Starting controller", "controller", "deployment")
	defer logger.Info("Shutting down controller", "controller", "deployment")
	
	// 确保本地与api-server的同步已经完成
	if !cache.WaitForNamedCacheSync("deployment", ctx.Done(), dc.dListerSynced, dc.rsListerSynced, dc.podListerSynced) {
		return
	}

	// 多个协程并行执行,每个一秒钟执行一次dc.worker方法(其实就是消费queue的业务逻辑)
	for i := 0; i < workers; i++ {
		go wait.UntilWithContext(ctx, dc.worker, time.Second)
	}

	<-ctx.Done()
}
  • 可见是定时执行dc.worker方法,那就看看这个worker是啥吧,如下所示,其实就是processNextWorkItem,这个咱们在《client-go实战》系列中已经写了太多次了,就是消费queue的业务代码,也是整个controller的核心业务代码
func (dc *DeploymentController) worker(ctx context.Context) {
	for dc.processNextWorkItem(ctx) {
	}
}

// 这是整个deployment的controller的核心业务逻辑,对deployment资源的变化进行响应
func (dc *DeploymentController) processNextWorkItem(ctx context.Context) bool {
	// 从queue中取出对象的key
	key, quit := dc.queue.Get()
	if quit {
		return false
	}
	defer dc.queue.Done(key)
	
	// 对指定key对应的资源进行处理,也就是此deployment的主要工作
	err := dc.syncHandler(ctx, key.(string))
	dc.handleErr(ctx, err, key)

	return true
}
  • 读到这里,不知您是否有一种豁然开朗的感觉:kubernetes规范了queue、生产、消费的模式,并且在自身controller中践行此模式,这就使得开发controller和阅读controller代码都变得更加容易了,甚至在本文章,我也数次尝试在阅读代码前先猜测再验证,结果都和猜测的一致
  • 或许您可能会有疑问:代码都分析到这里了,咋不继续读dc.syncHandler的源码,把这个controller搞明白?
  • 呃…这里必须要打住了,本文的重点的controller-manager的学习,也就是controller是如何创建和启动的,而并非研究controller的具体业务,所以dc.syncHandler就不展开看了,毕竟每个controller都有自己独特的业务处理逻辑
  • 但我相信,现在的您已经可以轻松读懂dc.syncHandler,从而彻底掌握deployment的controller了,毕竟咱们一起经历了太多的套路,对这套逻辑已经熟悉
  • 至此,《controller-manager学习三部曲》就已经完成了,希望这个系列能够帮您梳理和熟悉kubernetes的controller管理和启动逻辑,让您能开发出更加契合原生kubernetes系统的controller

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/386223.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++初阶】第三站:类和对象(中) -- 类的6个默认成员函数

目录 前言 类的6个默认成员函数 构造函数 概念 特性 析构函数 概念 特性 拷贝构造函数 概念 特征 赋值运算符重载 运算符重载 赋值运算符重载 const成员 const修饰类成员函数 取地址及const取地址操作符重载 本章总结&#xff1a; 前言 有时候我们写好了一个栈&#xff0c;头脑…

C#中implicit和explicit

理解: 使用等号代替构造函数调用的效果以类似重载操作符的形式定义用于类型转换的函数前者类型转换时候直接写等号赋值语法,后者要额外加目标类型的强制转换stirng str -> object o -> int a 可以 int a (int)(str as object)转换通过编译,但没有转换逻辑所以运行会报错…

《UE5_C++多人TPS完整教程》学习笔记14 ——《P15 创建我们自己的子系统(Creating Our Own Subsystem)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P15 创建我们自己的子系统&#xff08;Creating Our Own Subsystem&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&…

G85银昆高速宝鸡天台山隧道群荣获交通运输部科技示范工程,北京恒星科通隧道无线通信与广播系统应用于该项目

2023年9月12日&#xff0c;全国交通运输科技示范工程现场推进会在河南省平顶山市召开&#xff0c;会上为全国已通过验收的10项科技示范工程进行了授牌&#xff0c;其中由陕西交控集团负责实施的“秦岭天台山超长隧道群安全绿色科技示范工程”名列其中。 【授牌仪式现场】 据了解…

我让ChatGPT帮我钓妹子,它一口气撩了5000人

来自俄罗斯的一名AI开发者、社交平台TenChat的产品经理 AleksandrZhadan于1月30日在推特上发布了自己的婚讯&#xff0c;他将要与自己的女友Karina Imranovna在今年的8月结婚。令人震惊的是Aleksandr Zhadan介绍的认识女友的窍门-ChatGPT 帮他找到了另一半&#xff0c;并且通过…

vue-进阶语法(四)

目录 v-model原理 v-model应用于组件 sync修饰符 ref 和 $refs&#xff08;重点&#xff09; $nextTick v-model原理 原理&#xff1a;v-model本质上是一个语法糖。例如应用在输入框上&#xff0c;就是 value属性 和 input事件 的合写。 作用&#xff1a;提供数据的双向…

测试西门子博途S7-PLCSIM Advanced V5.0的使用

原创 honeytree 西门子博途S7-PLCSIM Advanced V5.0能支持S7-1500&#xff0c;S7-1500R/H&#xff0c;ET200SP&#xff0c;ET200pro的仿真&#xff0c;用此仿真器可以模拟实际的PLC&#xff0c;用于其他软件的连接&#xff0c;比如上位机软件、触摸屏软件,自己用高级语音开发…

VUE学习之路——列表渲染

<p v-for"item in items">{{ item }}</p>使用v-for进行列表的渲染。 这仅仅是一个简单的demo&#xff0c;使用v-for可以用来遍历数组和对象&#xff0c;具体如下&#xff1a; 注意&#xff1a;遍历数组或对象的时候&#xff0c;&#xff08;&#xff09;…

java客运管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java客运管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&#…

几个好用的 iphone 手机模板贴图样机

整理了几个好用的 iphone 手机模板贴图&#xff0c;分享一下。 关注订阅号「设计师工作日常」&#xff0c;发送关键词 iphone mockup ,获取下载链接。 [1] 原文阅读 我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;求点赞求关注&#xff01;

问题:3【单选题】实现职业理想的一般步骤是()。 #媒体#媒体

问题&#xff1a;3【单选题】实现职业理想的一般步骤是()。 A、创业-立业-择业 B、择业-创业-立业 C、择业-立业-创业 D、立业-择业-创业 参考答案如图所示

Git分支和迭代流程

Git分支 feature分支&#xff1a;功能分支 dev分支&#xff1a;开发分支 test分支&#xff1a;测试分支 master分支&#xff1a;生产环境分支 hotfix分支&#xff1a;bug修复分支。从master拉取&#xff0c;修复并测试完成merge回master和dev。 某些团队可能还会有 reale…

分享76个行业PPT,总有一款适合您

分享76个行业PPT&#xff0c;总有一款适合您 76个行业PPT下载链接&#xff1a;https://pan.baidu.com/s/17zUV16XOg9uBfDTH7sURxw?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理更不易。知…

有趣儿的组件(HTML/CSS)

分享几个炫酷的组件&#xff0c;起飞~~ 评论区留爪&#xff0c;继续分享哦~ 文章目录 1. 按钮2. 输入3. 工具提示4. 单选按钮5. 加载中 1. 按钮 HTML&#xff1a; <button id"btn">Button</button>CSS&#xff1a; button {padding: 10px 20px;text-tr…

怎么使用ChatGPT提高工作效率?

怎么使用ChatGPT提高工作效率&#xff0c;这是一个有趣的话题。 相信不同的人有不同的观点&#xff0c;大家的知识背景和从事的工作都不完全相同&#xff0c;所以最终ChatGPT能起到的作用也不一样。 在编程过程中&#xff0c;如果我们要找一个库&#xff0c;我们最先做的肯定…

解决MAC连上wifi或热点却不能上网问题

解决MAC连上wifi或热点却不能上网问题 #新换的mac昨天还能连上wifi&#xff0c;今天就不好使了。 找到连接的wifi点击详细信息&#xff0c;选择TCP/IP 中的配置IPV4 选择关闭

【python学习篇1】python基本语法

一、第一个python程序 在控制台上面输出“你好 python”。 在venv目录下面&#xff0c;新建一个Main1.python的文件夹。 然后在文件当中使用print函数输出一句命令即可。 然后&#xff0c;在Main.py下面&#xff0c;右键一下&#xff0c;运行Main1.py&#xff1a;即可看到下…

港口码头航吊远距离相位测距仪|传感器PHR-120100配置使用说明

港口码头航吊远距离相位测距仪|传感器PHR-120100广泛应用于港口码头、航车、位移监测、形变监测、钢铁、堆垛机、龙门吊等领域。 本文重点介绍港口码头航吊远距离相位测距仪|传感器PHR-120100配置使用说明。 一、布局介绍 二、按键介绍 三、指示灯说明 四、显示屏操作说明 …

片上网络NoC(4)——直连拓扑

目录 一、前言 二、直连拓扑 三、总结 一、前言 本文中&#xff0c;我们将继续介绍片上网络中拓扑相关的内容&#xff0c;主要介绍直连拓扑&#xff0c;在此之前&#xff0c;我们已经介绍过了拓扑的指标&#xff0c;这将是继续阅读本文的基础&#xff0c;还没有了解相关内容…

[WinForm开源]概率计算器 - Genshin Impact(V1.0)

创作目的&#xff1a;为方便旅行者估算自己拥有的纠缠之缘能否达到自己的目的&#xff0c;作者使用C#开发了一款小型软件供旅行者参考使用。 创作说明&#xff1a;此软件所涉及到的一切概率与规则完全按照游戏《原神》(V4.4.0)内公示的概率与规则&#xff08;包括保底机制&…