kubelet启动pod的源码分析

2024-05-10 17:58
文章标签 分析 源码 启动 pod kubelet

本文主要是介绍kubelet启动pod的源码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果看过之前的blog,大家都肯定都已经知道kubelet是负责真正启动容器的干活的,其实k8s的代码里面最复杂的其实是kubelet,而不是无脑的大脑apiserver,它基本是依靠etcd完成很多工作。
那么kubelet怎么去启动pod,何时去启动pod呢?我先从kubelet启动的地方说起。
这里写图片描述
先看上面这张图,这张图详细的介绍了kubelet启动pod的三个来源,分别是apiserver、URL和本地文件,篇幅有限我们已最常用的apiserver为例,其实其他两个也是一样的,譬如本地本机就是notify manifest下面下的static pod文件,发现有变化则发动到change的管道。回到apiserver的这个源上面来pkg/kubelet/kubelet.go

if kubeDeps.KubeClient != nil {glog.Infof("Watching apiserver")config.NewSourceApiserver(kubeDeps.KubeClient, nodeName, cfg.Channel(kubetypes.ApiserverSource))}

上面的代码是创建apiserver的watch。具体实现在下面
pkg/kubelet/config/apiserver.go

func NewSourceApiserver(c clientset.Interface, nodeName types.NodeName, updates chan<- interface{}) {lw := cache.NewListWatchFromClient(c.Core().RESTClient(), "pods", metav1.NamespaceAll, fields.OneTermEqualSelector(api.PodHostField, string(nodeName)))newSourceApiserverFromLW(lw, updates)
}// newSourceApiserverFromLW holds creates a config source that watches and pulls from the apiserver.
func newSourceApiserverFromLW(lw cache.ListerWatcher, updates chan<- interface{}) {send := func(objs []interface{}) {var pods []*v1.Podfor _, o := range objs {pods = append(pods, o.(*v1.Pod))}updates <- kubetypes.PodUpdate{Pods: pods, Op: kubetypes.SET, Source: kubetypes.ApiserverSource}}cache.NewReflector(lw, &v1.Pod{}, cache.NewUndeltaStore(send, cache.MetaNamespaceKeyFunc), 0).Run()
}

上面的代码有两个地方需要注意,第一是watch哪些pod呢?答案是所以命名空间下面,和该主机绑定的pod。第二需要注意的是,这里把所以pod的变化都分装到了一个kubetypes.PodUpdate结构体里面,虽然叫做update但其实并并不只是update,Op: kubetypes.SET这个设置在后面还会用到,当然源自然是kubetypes.ApiserverSource。
那么将变化放到update管道之后,接下来怎么处理呢?就是上面图片所说的merge方法去处理。pkg/kubelet/config/config.go
这个merge方法的功能就是通过比较确定到底应该是创建pod还是删除pod等操作主要返回下面这几个值

    addPods := []*v1.Pod{}updatePods := []*v1.Pod{}deletePods := []*v1.Pod{}removePods := []*v1.Pod{}reconcilePods := []*v1.Pod{}

具体到apiserver看下面代码

case kubetypes.SET:glog.V(4).Infof("Setting pods for source %s", source)s.markSourceSet(source)// Clear the old map entries by just creating a new mapoldPods := podspods = make(map[types.UID]*v1.Pod)updatePodsFunc(update.Pods, oldPods, pods)for uid, existing := range oldPods {if _, found := pods[uid]; !found {// this is a deleteremovePods = append(removePods, existing)}}

这里的kubetypes.SET和上面的对应上去了。主要是通过updatePodsFunc去处理,

if existing, found := oldPods[ref.UID]; found {pods[ref.UID] = existingneedUpdate, needReconcile, needGracefulDelete := checkAndUpdatePod(existing, ref)if needUpdate {updatePods = append(updatePods, existing)} else if needReconcile {reconcilePods = append(reconcilePods, existing)} else if needGracefulDelete {deletePods = append(deletePods, existing)}continue}recordFirstSeenTime(ref)pods[ref.UID] = refaddPods = append(addPods, ref)

上面的代码很简单,如果发现本地的oldPods已经存在则更新(checkAndUpdatePod去判断具体更新的内容,如果状态不一致则needReconcile,如果DeletionTimestamp不为空则needGracefulDelete其它更新如label、annotation等变化则needUpdate),更新包括删除和同步,如果不存在则加入到addPods的切片中去。
这个这个merge方法就可以返回需要创建、删除或者更新的pods了。
上面图Merge方法,调用merge返回了所以需要操作的pod之后,放入到updates的channel里面

case PodConfigNotificationIncremental:if len(removes.Pods) > 0 {s.updates <- *removes}if len(adds.Pods) > 0 {s.updates <- *adds}if len(updates.Pods) > 0 {s.updates <- *updates}if len(deletes.Pods) > 0 {s.updates <- *deletes}if firstSet && len(adds.Pods) == 0 && len(updates.Pods) == 0 && len(deletes.Pods) == 0 { // Send an empty update when first seeing the source and there are // no ADD or UPDATE or DELETE pods from the source. This signals kubelet that // the source is ready.s.updates <- *adds} // Only add reconcile support here, because kubelet doesn't support Snapshot update now.if len(reconciles.Pods) > 0 {s.updates <- *reconciles}

上面的创建删除更新等都放到s.updates里面。这样就kubelet就把需要变化的内容放到s.updates管道里面。
当kubelet启动的时候cmd/kubelet/app/server.go

go wait.Until(func() { k.Run(podCfg.Updates()) }, 0, wait.NeverStop)

上面的Updates()方法就是获取之前的s.updates。传给kubelet启动的Run方法里面pkg/kubelet/kubelet.go

func (kl *Kubelet) Run(updates <-chan kubetypes.PodUpdate) {}

那么kubelet里面就可以获取这写需要变化的pod了。然后通过kubelet.go里面syncLoopIteration这个方法去创建

kl.syncLoopIteration(updates, handler, syncTicker.C, housekeepingTicker.C, plegCh)

这个方法有四个输入源,我们上面分析的update只是其中之一,下面的blog将会继续分析启动过程。

这篇关于kubelet启动pod的源码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/977154

相关文章

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Python 迭代器和生成器概念及场景分析

《Python迭代器和生成器概念及场景分析》yield是Python中实现惰性计算和协程的核心工具,结合send()、throw()、close()等方法,能够构建高效、灵活的数据流和控制流模型,这... 目录迭代器的介绍自定义迭代器省略的迭代器生产器的介绍yield的普通用法yield的高级用法yidle

Redis在windows环境下如何启动

《Redis在windows环境下如何启动》:本文主要介绍Redis在windows环境下如何启动的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Redis在Windows环境下启动1.在redis的安装目录下2.输入·redis-server.exe

解决SpringBoot启动报错:Failed to load property source from location 'classpath:/application.yml'

《解决SpringBoot启动报错:Failedtoloadpropertysourcefromlocationclasspath:/application.yml问题》这篇文章主要介绍... 目录在启动SpringBoot项目时报如下错误原因可能是1.yml中语法错误2.yml文件格式是GBK总结在启动S

C++ Sort函数使用场景分析

《C++Sort函数使用场景分析》sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变,如果某些场景需要保持相同元素间的相对顺序,可使... 目录C++ Sort函数详解一、sort函数调用的两种方式二、sort函数使用场景三、sort函数排序

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO