Kubernetes 源码分析之 kubelet(二)
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.go
,http.go
,file.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 testability
type 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
分为三个部分:
增删改:
Additions
,Removes
,Updates
状态同步:
Reconcile
,Syncs
清理:
Cleanups
其中,增删改比较好理解,不再赘述。而清理的作用就是将 pod 残留的数据删除干净。由于 pod 的删除在很多环节都有可以出问题,因此需要一个 Cleanups
的操作去处理这些出问题的环节,清理数据。
至于状态同步可以理解为当 API 中的 status 和 kubelet 所获取的真实 status 不同时,kubelet 会更新 API 中的 status 以向实际的 status 靠近 (kubernetes 著名的设计模式,通过更新不断将当前状态向期望状态靠近直到结果收敛)。
而 Reconcile
和 Syncs
的差别则在于
Reconcile
的主要目的是防止 pod status 的意外修改,而Syncs
是真正处理 pod 生命周期的核心逻辑。由于添加了
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(三)