K8S源码剖析之statefulset

statefulset源码

Posted by lwk on January 1, 2020

在微服务盛行时代,不深入了解下K8S怎么行!

上一章我们已经通过二进制方法搭建出了一个K8S集群。本章将通过剖析statefulset controller源码,了解statefulset过程。【网上也有对statefulset的分析,不过都是别人的,自己分析一遍比较过瘾】

学习之前,先介绍下statefulset,statefulset是K8S其中一种控制器(controller),K8S1.12版本共有20+种controller,所有的controller由kube-controller-manager这个进程启动控制的。

首先,在我们的测试集群master上看下对应的kube-controller-manager image Kube-controller-manager是独立的组件,对应的K8S源码在kubernetes->cmd->kube-controller-manager image Statefulset整体的流程图如下所示:

image 找到main函数入口: image

进入NewControllerManagerCommand函数,该函数调用Run函数,Run函数会负责启动所有的controller

image NewControllerInitializers主要负责将所有controller加到map中,例如statefulsetcontroller,map存储的key是statefuset,value类型是InitFunc的函数startStatefulSetController

image image StartControllers遍历mapcontrollers,执行对应的initFn,例如statefulset对应的initFn是startStatefulSetController。

image

startStatefulSetController会创建一个goroutine,负责执行statefulset. NewStatefulSetController().Run()。NewStatefulSetController实现对pod和statefulset的add/update/delete事件的注册,并加入到statefulset队列中。

image 在goroutine中,创建完StatefulSetController之后,执行Run函数,包含两个参数:workers数1和只读的channel变量Stop

image

Run函数体里遍历worker数,针对每个worker开启一个goroutine,执行ssc.worker

image processNextWorkItem从队列取出statefulset,并调用sync函数进行同步。

image

Sync参数是key,类型是string。Key到底是什么呢?长啥一样呢?

image

有源码,又搭建了测试集群,那就加点log重新编译出二进制,替换线上版本看看呗。修改statefulset代码,并对kube-controller-manager重新编译(编译指引请参考网上教程)。

image 编译生成新的二进制,替换master的kube-controller-manager并重启kube-controller-manager。

重启后,从/var/log/message可以看到对应的日志输出信息:key值是default/nginx-with-pvc image default/nginx-with-pvc是在测试集群上创建的一个statefulset,默认所在namespace是default

image

所以,sync参数的值是namespace_name+statefulset_name。

Sync函数的主要逻辑是:重新获取statefulset对象,获取和该statefulset对象相关的ControllerRevisions;遍历revisions,检查是否有OwnerReference为空的,如果有说明存在Orphaned的revisions,并认领这些Orphanedrevisions;获取和该statefulset对象相关的所有pod;调用ClaimPods检查statefulset和pod的label以及Selector、controllerRef匹配关系。

image

image

接下来是调用syncStatefulSet,核心逻辑是StatefulSetControlInterface.UpdateStatefulSet

image

UpdateStatefulSet核心逻辑:获取和该statefulset相关的revisions并进行排序(升序),SortControllerRevisions对revisions的排序是通过byRevision实现sort的接口(Len、Less、Swap)达到对ControllerRevision的排序。

image

getStatefulSetRevisions获取currentRevision和updateRevision。

updateStatefulSet是更新statefulset的核心逻辑:将当前statefulset所拥有的pod进行分组,超出副本集replicaCount的pod被扔进condemned等待销毁;对当前pod数不足情况进行扩容操作;获取副本数组中第一个不健康的Pod;根据副本的序列号检查各个副本的状态(对失败的POD进行重启,);按照降序删除condemned中的副本;按照降序删除replicas中的副本。

image image image image image

演示效果:创建statefulset,副本数为2 image 扩容:副本数更新到10

kubectl scale statefulset nginx-with-pvc–replicas=10 image POD序列号Ordinal从2开始扩容到9。

缩容:kubectl patch statefulset nginx-with-pvc -p’{“spec”:{“replicas”:2}}’ image 按照POD序列号从大到小依次删除。

至此,整个K8S的statefulset流程分析完毕。由于不知专业搞K8S开发的,所以可能有不足的地方,请大家及时指出。