TiDB操作符源代码读取(II):操作符模式

2021-05-27 谊文陈 工程

作者:谊文陈(TiDB营办商提交人)

Transcreator:黄了编辑器:汤姆政府高级官员

TiDB操作符源代码读取(II):操作符模式

我的最后一篇文章,我介绍了TiDB Operator的架构和它的功能。但是TiDB操作符代码是如何运行的?TiDB Operator如何管理TiDB集群中每个组件的生命周期?

在这篇文章中,我将介绍Kubernetes的操作符模式以及它是如何在TiDB操作符中实现的。更具体地说,我们将通过TiDB运营商的主要控制循环,从其入口点到生命周期管理的触发器

从控制器到操作员

因为TiDB操作符从kube-controller-manager,理解设计kube-controller-manager帮助您更好地理解TiDB Operator的内部逻辑。

在Kubernetes,各控制器管理资源的生命周期,如Namespace、Node、Deployment和StatefulSet。控制器监视集群资源的当前状态,将其与所需状态进行比较,并将集群移动到所需状态。Kubernetes的内置控制器在内部运行kube-controller-manager并被它管理。

为了允许用户自定义资源管理,Kubernetes提出了操作模式.用户可以创建自己的自定义资源(CRs)通过定义CustomResourceDefinitions(crd)对象,并使用自定义控制器监视相应crd的状态,完成相关的管理任务。Operator模式允许用户扩展Kubernetes行为,而无需修改其代码。

TiDB控制器管理器如何工作

TiDB操作符源代码读取(I):概述, TiDB Operator有一个核心组件,tidb-controller-manager,它运行一组自定义控制器来管理TiDB的crd。

入口点

cmd / controller-manager / main.gotidb-controller-manager首先加载kubeconfig以访问kube-apiserver。然后使用一系列NewController函数,用于加载每个控制器的init函数。

控制器:=控制器tidbclusterNewControllerdepsdmclusterNewControllerdeps备份NewControllerdeps恢复NewControllerdepsbackupscheduleNewControllerdepstidbinitializerNewControllerdepstidbmonitorNewControllerdeps

在执行init函数时,tidb-controller-manager初始化一组告密者,告密者与kube-apiserver交互以获取CRs和相关资源的变化。采取TidbCluster举个例子,在NewController函数,tidb-controller-manager初始化Informer对象:

tidbClusterInformer告密者AddEventHandler缓存ResourceEventHandlerFuncsAddFunccenqueueTidbClusterUpdateFunc函数坏蛋接口cenqueueTidbCluster坏蛋DeleteFunccenqueueTidbClusterstatefulsetInformer告密者AddEventHandler缓存ResourceEventHandlerFuncsAddFunccaddStatefulSetUpdateFunc函数坏蛋接口cupdateStatefulSet坏蛋DeleteFunccdeleteStatefulSet

事件的过程添加更新,删除事件都登记在告密者名下。这些eventhandler处理事件并向队列添加相关的CR键。

控制器的内部逻辑

初始化后,tidb-controller-manager启动InformerFactory并等待缓存同步完成:

informerFactories:=InformerFactorydepsInformerFactorydepsKubeInformerFactorydepsLabelFilterKubeInformerFactory_f:=范围informerFactoriesf开始ctx完成v同步:=范围fWaitForCacheSync等待NeverStop如果同步klogFatalf" %v的错误同步通知器"v

接下来,tidb-controller-manager调用每个控制器的Run函数,并在循环中执行控制器的内部逻辑:

//为所有控制器启动syncLoop。_控制器:=范围控制器c:=控制器等待永远函数c运行cliCfg工人ctx完成cliCfgWaitDuration

再次,以TidbCluster以控制器为例。Run函数启动工作队列:

//运行控制器tidbcluster。函数c控制器运行工人intstopCh<-结构体推迟utilruntimeHandleCrash推迟c队列关闭klog信息“开始tidbcluster控制器”推迟klog信息"关闭tidbcluster控制器":=0<工人++等待直到c工人时间第二个stopCh<-stopCh

工人叫processNextWorkItem函数,将项从队列中取出,并调用同步函数同步CR:

// worker运行一个调用processNextWorkItem的worker goroutine,直到控制器队列关闭。函数c控制器工人cprocessNextWorkItem// processNextWorkItem将项目从队列中取出,处理它们,并标记它们已完成。它强制syncHandler永远不存在//使用相同的键并发调用。函数c控制器processNextWorkItem保龄球关键辞职:=c队列得到如果辞职返回推迟c队列完成关键如果犯错:=c同步关键字符串犯错! =如果perror找到犯错控制器IsRequeueError! =klogInfof"TidbCluster: %v, still need sync: %v, requeing "关键字符串犯错其他的utilruntimeHandleErrorfmtErrorf"TidbCluster: %v, sync failed %v, requeing "关键字符串犯错c队列AddRateLimited关键其他的c队列忘记关键返回真正的

基于密钥,同步函数获取相应的CR对象(例如TidbCluster对象)并同步它:

// sync同步给定的tidbcluster。函数c控制器同步关键字符串错误开始时间:=时间现在推迟函数klogV4Infof"已完成同步TidbCluster %q (%v)"关键时间开始时间ns的名字犯错:=缓存SplitMetaNamespaceKey关键如果犯错! =返回犯错tc犯错:=cdepsTiDBClusterListerTidbClustersns得到的名字如果错误IsNotFound犯错klogInfof"TidbCluster已被删除%v"关键返回如果犯错! =返回犯错返回csyncTidbClustertcDeepCopy函数c控制器syncTidbClustertcv1alpha1TidbCluster错误返回c控制UpdateTidbClustertc

syncTidbCluster函数调用的updateTidbCluster函数,它进一步调用一系列组件同步功能,完成对整个TiDB集群的管理。

包裹/控制器/ tidbcluster / tidb_cluster_control.go,可以检查实现情况updateTidbCluster函数,其中有注释描述了每个函数执行的生命周期管理同步函数。通过这些注释,您可以了解协调每个组件所需的操作。例如,在放置驱动程序(PD)中:

//使pd集群的当前状态匹配期望的状态:// -创建或更新pd服务//创建或更新pd headless服务// -如果不存在,则创建pd statefulset//同步pd集群状态从pd到TidbCluster对象// -升级pd集群// -在pd集群中扩展/// -切换pd集群如果犯错:=cpdMemberManager同步tc犯错! =返回犯错

现在就讲到这里。

总结

在这篇文章中,我们介绍了TiDB Operator的入口点cmd / controller-manager / main.go介绍了控制器的实现,并说明了控制器的内部逻辑.现在,您已经熟悉了控制回路是如何触发的。唯一的问题是如何完善控制回路,并在其中注入TiDB的特殊操作逻辑。这样,您就可以根据需要部署TiDB并在Kubernetes中运行它。

对于那些想要开发一个资源管理系统的人,我们推荐两个脚手架项目:Kubebuilder运营商框架.这些项目生成的代码模板基于controller-runtime,允许您关注CRD对象的协调循环。

在下一篇文章中,我将讨论如何细化控制循环和实现组件协调循环.如果你有任何问题,请通过我们的松弛通道或在pingcap / tidb-operator

TiDB运营商 Kubernetes

准备好开始使用TiDB了吗?