kubelet启动pod的源码分析
来源:互联网 发布:淘宝卖家怎么设置淘宝客推广 编辑:程序博客网 时间:2024/05/22 08:10
如果看过之前的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.Pod for _, 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 map oldPods := pods pods = make(map[types.UID]*v1.Pod) updatePodsFunc(update.Pods, oldPods, pods) for uid, existing := range oldPods { if _, found := pods[uid]; !found { // this is a delete removePods = append(removePods, existing) } }
这里的kubetypes.SET和上面的对应上去了。主要是通过updatePodsFunc去处理,
if existing, found := oldPods[ref.UID]; found { pods[ref.UID] = existing needUpdate, 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] = ref addPods = 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的源码分析
- kubelet启动pod源码分析(二)
- kubelet启动pod源码分析(三)
- k8s源码分析-----kubelet pod处理流程
- kubelet源码分析-pod新建流程
- 【原创】k8s源码分析-----kubelet(8)pod管理
- k8s源码分析--kubelet中pod处理流程(续)
- k8s源码分析-----kubelet启动流程分析
- Kubelet源码分析(一) 启动流程分析
- k8s源码分析-----kubelet启动流程分析(续)
- kubelet源码分析
- kubelet gc源码分析
- kubernetes组件kubelet之源码分析 启动流程
- kubernetes源码分析 -- kubelet组件
- kubelet源码分析(未完成)
- Kubelet源码分析(二) DockerClient
- Kubelet源码分析(四) diskSpaceManager
- kubelet之DockerClient源码分析
- dash + alfred 初试
- Python 3从入门到精通01-环境搭建
- 如何看待中通讯42岁员工坠楼事件?背后深层原因剖析!
- Spring启动后再执行
- Windows下安装Redis服务
- kubelet启动pod的源码分析
- nodejs读写文件
- 写在开始之前
- Django框架学习笔记(10.基于ORM实现简单的用户登录)
- “平板之父”Jerry Kaplan:未来最困难的是让 AI 融入社会及社交生活
- MAC--L2TP教程
- C++primer学习 12.18
- 深度学习环境搭建
- mybatis-xml配置