在微服务盛行时代,不深入了解下K8S怎么行!
上一章我们已经通过二进制方法搭建出了一个K8S集群。本章将通过剖析statefulset controller源码,了解statefulset过程。【网上也有对statefulset的分析,不过都是别人的,自己分析一遍比较过瘾】
学习之前,先介绍下statefulset,statefulset是K8S其中一种控制器(controller),K8S1.12版本共有20+种controller,所有的controller由kube-controller-manager这个进程启动控制的。
首先,在我们的测试集群master上看下对应的kube-controller-manager Kube-controller-manager是独立的组件,对应的K8S源码在kubernetes->cmd->kube-controller-manager Statefulset整体的流程图如下所示:
找到main函数入口:
进入NewControllerManagerCommand函数,该函数调用Run函数,Run函数会负责启动所有的controller
NewControllerInitializers主要负责将所有controller加到map中,例如statefulsetcontroller,map存储的key是statefuset,value类型是InitFunc的函数startStatefulSetController
StartControllers遍历mapcontrollers,执行对应的initFn,例如statefulset对应的initFn是startStatefulSetController。
startStatefulSetController会创建一个goroutine,负责执行statefulset. NewStatefulSetController().Run()。NewStatefulSetController实现对pod和statefulset的add/update/delete事件的注册,并加入到statefulset队列中。
在goroutine中,创建完StatefulSetController之后,执行Run函数,包含两个参数:workers数1和只读的channel变量Stop
Run函数体里遍历worker数,针对每个worker开启一个goroutine,执行ssc.worker
processNextWorkItem从队列取出statefulset,并调用sync函数进行同步。
Sync参数是key,类型是string。Key到底是什么呢?长啥一样呢?
有源码,又搭建了测试集群,那就加点log重新编译出二进制,替换线上版本看看呗。修改statefulset代码,并对kube-controller-manager重新编译(编译指引请参考网上教程)。
编译生成新的二进制,替换master的kube-controller-manager并重启kube-controller-manager。
重启后,从/var/log/message可以看到对应的日志输出信息:key值是default/nginx-with-pvc default/nginx-with-pvc是在测试集群上创建的一个statefulset,默认所在namespace是default
所以,sync参数的值是namespace_name+statefulset_name。
Sync函数的主要逻辑是:重新获取statefulset对象,获取和该statefulset对象相关的ControllerRevisions;遍历revisions,检查是否有OwnerReference为空的,如果有说明存在Orphaned的revisions,并认领这些Orphanedrevisions;获取和该statefulset对象相关的所有pod;调用ClaimPods检查statefulset和pod的label以及Selector、controllerRef匹配关系。
接下来是调用syncStatefulSet,核心逻辑是StatefulSetControlInterface.UpdateStatefulSet
UpdateStatefulSet核心逻辑:获取和该statefulset相关的revisions并进行排序(升序),SortControllerRevisions对revisions的排序是通过byRevision实现sort的接口(Len、Less、Swap)达到对ControllerRevision的排序。
getStatefulSetRevisions获取currentRevision和updateRevision。
updateStatefulSet是更新statefulset的核心逻辑:将当前statefulset所拥有的pod进行分组,超出副本集replicaCount的pod被扔进condemned等待销毁;对当前pod数不足情况进行扩容操作;获取副本数组中第一个不健康的Pod;根据副本的序列号检查各个副本的状态(对失败的POD进行重启,);按照降序删除condemned中的副本;按照降序删除replicas中的副本。
演示效果:创建statefulset,副本数为2 扩容:副本数更新到10
kubectl scale statefulset nginx-with-pvc–replicas=10 POD序列号Ordinal从2开始扩容到9。
缩容:kubectl patch statefulset nginx-with-pvc -p’{“spec”:{“replicas”:2}}’ 按照POD序列号从大到小依次删除。
至此,整个K8S的statefulset流程分析完毕。由于不知专业搞K8S开发的,所以可能有不足的地方,请大家及时指出。