Kubernetes 源码分析之 kubelet(二)

2021-01-06 15:41

Version

k8s 版本 v1.18.3 (后续系列都以这个版本)


Pod Config Update

本文顺着前文的思路分析一下 <-chan kubetypes.PodUpdate 以及相关的代码。故名思义,PodUpdate 定义了 pod 的相关更新,具体结构如下

type PodUpdate struct {  Pods   []*v1.Pod  Op     PodOperation  Source string}

其中 PodOperation 有如下几种类型

  • SET 全量更新,类似 RESTful 中 PUT 的含义

  • ADD 发现一个新的 pod 被添加

  • DELETE 发现 pod 准备要被删除,进入 gracefully deleted 阶段

  • REMOVE 发现 pod 已经被删除

  • UPDATE 发现 pod 合理的更新

  • RECONCILE 发现 pod 某些 status 不是预期状态时

  • RESTORE checkpoint restore 时

同时定义了三种 source:

  • api

  • file

  • http

api 是指 watch apiserver 获得的更新,除此外剩余的两种 source 都是为支持 static pod 设计的。

各个 source 的 update 事件如何获取,如何合并多个 source 的 update 事件等逻辑都在 /pkg/kubelet/config 文件夹下。其中 apiserver.gohttp.gofile.go 分别是上述三种 source 的实现。

阅读 /pkg/kubelet/config 下的代码,我们可以发现从 source 中触发的 PodOperation 都是 SET 的操作,而没有其他的 PodOperation

然后在 /pkg/kubelet/config/config.go 中,将 pod 的更新和本地 cache 比较,分类为不同的 PodOperation (详见 merge 函数)

可以特别注意是否分类到 RECONCILE 类型,是根据 checkAndUpdatePod 和 podsDifferSemantically 两个函数调用来决定的。简单来说就是如果 pod 的 metadata(部分字段,如 label) 和 spec 等没被修改,而 status 被修改了,就会触发 RECONCILE

另外,config.go 里定义了 PodConfigNotificationMode,上述拆分发生在 mode 为 PodConfigNotificationIncremental 时,但是直到目前 mode 都只能是 PodConfigNotificationIncremental (仅在 /pkg/kubelet/kubelet.go 中调用 NewPodConfig 时指定)

sync handler

再聊一聊上一篇文章中提到的 SyncHandler 接口,接口定义如下

// SyncHandler is an interface implemented by Kubelet, for testabilitytype SyncHandler interface {  HandlePodAdditions(pods []*v1.Pod)  HandlePodUpdates(pods []*v1.Pod)  HandlePodRemoves(pods []*v1.Pod)
HandlePodReconcile(pods []*v1.Pod) HandlePodSyncs(pods []*v1.Pod)
HandlePodCleanups() error}

可以简单将 SyncHandler 分为三个部分:

  1. 增删改:AdditionsRemovesUpdates

  2. 状态同步:ReconcileSyncs

  3. 清理:Cleanups

其中,增删改比较好理解,不再赘述。而清理的作用就是将 pod 残留的数据删除干净。由于 pod 的删除在很多环节都有可以出问题,因此需要一个 Cleanups 的操作去处理这些出问题的环节,清理数据。

至于状态同步可以理解为当 API 中的 status 和 kubelet 所获取的真实 status 不同时,kubelet 会更新 API 中的 status 以向实际的 status 靠近 (kubernetes 著名的设计模式,通过更新不断将当前状态向期望状态靠近直到结果收敛)。

而 Reconcile 和 Syncs 的差别则在于

  1. Reconcile 的主要目的是防止 pod status 的意外修改,而 Syncs 是真正处理 pod 生命周期的核心逻辑。

  2. 由于添加了 ReadinessGate 的 feature, Reconcile 在一定条件下也会触发 sync 操作。

PS: 从实现上可以看出来 sync 和 reconcile 的定义差别,reconcile 是 kubernetes 开放 API (即无内部 API 调用,所有 API 均可外部调用) 所带来的固有问题的解决方案。而 sync 是 kubernetes 核心设计模式中 actual 向 expected 收敛这一过程的描述。不过现阶段二者的界限已经模糊了,特别在 operator 的设计中已经普遍使用了 reconcile 的说法。

最后整个 SyncHandler 的实现涉及到两个关键部分,一个是 podManager,一个是 podWorkers


podManager

podManager管理 kubelet 对 pod 的访问,见 pkg/kubelet/pod/pod_manager.go。由于 mirror pod (mirror pod 和 static pod 的关系可以理解为: kubelet 发现一个 static pod 后会在 apiserver 中创建一个 mirror pod) 的存在整个 podManager 显得有些复杂。总的来说 podManager 就是实现了一个内存数据库,用于 cache 多个 source (见上文的 3 种来源) 的 pod,并提供了一些 pod 的查询功能,如:

  • 从 namespace 和 name 查 pod

  • 从 uid 查 pod

  • 根据 pod 查 mirror pod

  • 根据 mirror pod 查 pod


podWorkers

podWorkers 定义在 /pkg/kubelet/pod_workers.go,用于分发对 pod 的操作任务,譬如上文中的 SyncHandler 的很多操作最终会调用 dispatchWork 交给 podWorkers 来执行。

查看 podWorkers 的代码,发现核心逻辑在 syncPodFn 的调用,而这个 syncPodFn 则是在 /pkg/kubelet/kubelet.go中调用 newPodWorkers 时初始化的,其实际上就是 pkg/kubelet/kubelet.go 下的 syncPod 函数。

如果这个时候你正在看 kubelet 的代码,就会发现 syncPod 上面有很长很长的注释 – 这说明这是一个至关重要的函数。

最后

本次分析回答了之前的一些问题,譬如
  • <-chan kubetypes.PodUpdate 到底是怎么触发的,对应的四个操作都做了什么
  • HandlePodSyncs 和上述四个操作什么关系(凭什么你叫 sync)

  • HandlePodCleanups 和 HandlePodRemoves 的区别

也带来了新的问题

  • syncPod 做了一些什么

最后遗留了这些问题

  • 为什么需要定时触发 syncCh

  • 为什么需要 housekeeping

  • pleg 模块到底做了什么

  • syncPod 做了一些什么


敬请期待 Kubernetes 源码分析之 kubelet(三)




 点击屏末  | 即刻学习


浏览 46
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报