kubernetes源码-DaemonSet Controller 原理和源码分析
DaemonSet Controller 原理和源码分析,源码为 kubernetes 的 release-1.22 分支 .
写在前面
个人觉得 DaemonSet 控制器相比 Deployment 控制器逻辑要绕一点,它不用 ReplicaSet 去控制 pod 数量 ,pod 的数量是按节点的数量为依据的。
跟 Deployment 控制器一样,它的入口函数位于 kubernetes/cmd/kube-controller-manager/app/apps.go 里面。
NewDaemonSetsController
我们废话不多说,直接看它的 NewDaemonSetsController 结构。
|
|
可以发现,除了监听自身对象和 pod 对象以外,还监听 node 对象 和 历史版本对象,它的回滚是通过更新历史版本来做。
监听函数
跟其他控制器一样,它也设置了很多的事件监听,我们看看其中一些比较有用的。
Daemonset 对象
监听后做一些常规判断后,加入队列,没什么特殊的,我们了解一下,知道有这些函数就可以。
-
addDaemonset
-
updateDaemonset
-
deleteDaemonset
History 对象
这里比较需要关注的就是 updateHistory ,它检测到历史版本变化后,会把对应的 Daemonset 对象滚到到对应的历史版本去。
-
addHistory
-
updateHistory
-
deleteHistory
Node 对象
在 Deployment 控制器,是没看到有监听节点事件的,这是 Daemonset 控制器的特色。
addNode
监听节点新增事件。
-
监听到节点添加进来的事件后,会使用 nodeShouldRunDaemonPod() 方法判断 Daemonset 对象 pod 应不应该跑在该节点上面,如果当前 Daemonset 对象可以跑在新加进来的节点,则将 Daemonset 对象丢进队列做进一步的调谐。
-
nodeShouldRunDaemonPod() 原理是先根据 Daemonset 对象 New 一个 pod 对象,给这个 pod 加一堆污点容忍度,然后去比对新加入的节点身上的污点,如果比对到第一个不容忍的污点则返回首个不匹配的污点。
|
|
updateNode
监听节点更新事件。
-
对比 2 个节点的 NodeCondition ,如果一致,则判断 2 个节点是否其他配置也一样,是的话就跳过 Daemonset 对象同步。
-
如果不一致,则对比 old 和 new Daemonset 对象能不能在新加入的节点上面跑 pod,如果旧 Daemonset 和新的 Daemonset 出现不一样的比对结果,则需要重新同步 Daemonset 对象。
|
|
我们发现这里没有监听 deleteNode 事件,我个人认为,节点如果删除, pod 会重新发生调度,然后根据 manage 的逻辑,会判断 pod 该不该运行在其他节点上,不该运行则删除,所以这里才没做对应的事件监听和处理。
pod 对象
没什么特别的,了解一下即可。
-
addPod
-
updatePod
-
deletePod
enqueue
跟其他控制器一样,也是延迟入列和立即入列,没什么特殊的。
|
|
Run
默认2个线程,多了个 failedPodsBackoff.GC 函数,用于周期性重启失败的 pod 的。
|
|
syncDaemonSet
控制器的核心逻辑在这里实现。
-
获取 DaemonSet cur old 历史版本对象,获取 cur.Labels[apps.DefaultDaemonSetUniqueLabelKey] 的值,用于后面的同步操作。
-
还没满足期望则继续等待期望达成,在此期间只同步 DaemonSet status 状态。
-
满足期望则先执行 manage 和 syncNodes 维持 pod 数量。
-
再根据策略类型执行 rollingUpdate ,维护 DaemonSet 对象的版本和其他信息的同步。如果更新策略是 OnDelete ,则等手动删除 pod 的时候再创建新 pod ,如果是 RollingUpdate ,则根据 maxSurge, maxUnavailable 的值,做相应的动作(如果 maxSurge, maxUnavailable 都是默认值,根据 rollingUpdate 方法的逻辑,默认是删除1个 pod ,等 pod 删完后再新建一个新的 pod ,以此类推)。
-
清理历史版本。
-
同步 DaemonSet Status 状态字段。
|
|
manage
-
获取 DaemonSet 对象所有 pod ,并以 nodename 分组。
-
检查所有节点,如果节点条件不允许上面跑 DaemonSet 的 pod ,则删除 pod ,反之则新建 pod 。同时,如果 pod 处于失败状态,会尝试周期性 kill 掉(间隔:从 1s 开始,指数级增长, dsc.failedPodsBackoff.GC 一分钟执行一次,将重启超过 30min 还失败的 pod 的重启间隔重置为 1s)。
-
检查 DaemonSet 的滚动策略,如果 pod 大于 1,且 maxSurge > 0 ,则删除节点上所有 pod ,重新创建(因为这种策略在更新期间,同时只允许一个 pod 运行)
-
调度到不存在的节点的 pod 也需要删除。
-
manage 核心逻辑是统计需要新建 pod 的节点和需要删除的 pod ,并把结果交给 syncNodes 方法执行。
|
|
syncNodes
-
计算要新建和删除的 pod 数量,设置期望。
-
新建的之前先给 pod 添加亲和性相关的字段,再执行新建。
-
删除 pod 。
|
|
总结
-
DaemonSet 不用 replicaset 去管理 pod 的数量。
-
根据历史版本 hash 来做版本管理。
-
周期性重启失败的 pod 。