kubelet源码分析 创建/更新/调谐 pod
admin
2024-02-15 16:11:38
0

kubelet源码 创建/更新/协调pod

这篇写的就是创建、更新、调谐、同步时触发的函数变化。
一、调谐(Reconcile)

一、调谐(Reconcile)

写过CRD的应该对这个函数很熟悉,当CRD有变化的时候或每过2s都是通过触发这个函数进行比对,调谐pod的状态
但是这个调谐和CRD的不一样,这里只是调谐READY和被驱逐或者失败的pod
kubectl apply -f demo.yaml
1.类似于kubelet删除pod中的流程2

		case kubetypes.RECONCILE:klog.V(4).InfoS("SyncLoop RECONCILE", "source", u.Source, "pods", klog.KObjs(u.Pods))handler.HandlePodReconcile(u.Pods)

这里触发了reconcile函数

2.这个函数主要三个流程步骤

  • 先判断是否是静态pod,如果是静态pod,更新一下静态pod的缓存
  • 判断这个pod是否需要调谐(流程3)
  • 这个pod是否是已经完成或者失败的,如果是,则进行清理(流程8)
func (kl *Kubelet) HandlePodReconcile(pods []*v1.Pod) {start := kl.clock.Now()for _, pod := range pods {kl.podManager.UpdatePod(pod)if status.NeedToReconcilePodReadiness(pod) {mirrorPod, _ := kl.podManager.GetMirrorPodByPod(pod)kl.dispatchWork(pod, kubetypes.SyncPodSync, mirrorPod, start)}****//流程8}
}

3.验证是否需要调谐

  • 第二行查看是否设置了readinessGates,如果没设置,直接返回。
  • 第5行开始是检测设定这个条件的实际状态(流程4)
  • 第7行是检测运行中为ready类型的conditions(就是验证一下是否就绪了)。这里可以简单说一下,如果用户添加了readinessGates,那readinessGates必须通过检查,否则ready类型的conditions会变为false(流程6)
  • 如果运行中的和实际的条件不符,则是需要调谐
func NeedToReconcilePodReadiness(pod *v1.Pod) bool {if len(pod.Spec.ReadinessGates) == 0 {return false}podReadyCondition := GeneratePodReadyCondition(&pod.Spec, pod.Status.Conditions, pod.Status.ContainerStatuses, pod.Status.Phase)i, curCondition := podutil.GetPodConditionFromList(pod.Status.Conditions, v1.PodReady)if i >= 0 && (curCondition.Status != podReadyCondition.Status || curCondition.Message != podReadyCondition.Message) {return true}return false
}

4.验证一下实际状态

  • 前四行是获得状态,后续会验证状态(流程5)
  • 从GenerateContainersReadyCondition函数开始
  • 如果containerStatuses(容器状态)为空,则代表肯定没有ready,直接status返回false
  • 如果有容器,但是!containerStatus.Ready容器没有运行中。则也是没有ready的
  • 如果容器都没有,肯定也是没ready
  • 第29行,如果容器已经运行完成了(源码中会显示Succeeded,如果kubectl会显示Completed)并且没有没启动的容器,则返回未就绪,原因是已完成
  • 第36行开始,是把没有容器和容器未ready的汇总一下,拼接成一个字符串。如果错误不为空,则返回的是没有ready
  • 如果没有任何错误,返回的是ready
func GeneratePodReadyCondition(spec *v1.PodSpec, conditions []v1.PodCondition, containerStatuses []v1.ContainerStatus, podPhase v1.PodPhase) v1.PodCondition {containersReady := GenerateContainersReadyCondition(spec, containerStatuses, podPhase)*******
}func GenerateContainersReadyCondition(spec *v1.PodSpec, containerStatuses []v1.ContainerStatus, podPhase v1.PodPhase) v1.PodCondition {if containerStatuses == nil {return v1.PodCondition{Type:   v1.ContainersReady,Status: v1.ConditionFalse,Reason: UnknownContainerStatuses,}}unknownContainers := []string{}unreadyContainers := []string{}for _, container := range spec.Containers {if containerStatus, ok := podutil.GetContainerStatus(containerStatuses, container.Name); ok {if !containerStatus.Ready {unreadyContainers = append(unreadyContainers, container.Name)}} else {unknownContainers = append(unknownContainers, container.Name)}}if podPhase == v1.PodSucceeded && len(unknownContainers) == 0 {return v1.PodCondition{Type:   v1.ContainersReady,Status: v1.ConditionFalse,Reason: PodCompleted,}}unreadyMessages := []string{}if len(unknownContainers) > 0 {unreadyMessages = append(unreadyMessages, fmt.Sprintf("containers with unknown status: %s", unknownContainers))}if len(unreadyContainers) > 0 {unreadyMessages = append(unreadyMessages, fmt.Sprintf("containers with unready status: %s", unreadyContainers))}unreadyMessage := strings.Join(unreadyMessages, ", ")if unreadyMessage != "" {return v1.PodCondition{Type:    v1.ContainersReady,Status:  v1.ConditionFalse,Reason:  ContainersNotReady,Message: unreadyMessage,}}return v1.PodCondition{Type:   v1.ContainersReady,Status: v1.ConditionTrue,}
}

5.重新回到上面的函数,获取了容器实际状态后,要做返回值判断了

  • 第4行,如果容器未能ready,则返回pod未ready
  • 如果容器都ready了,需要验证用户自定义的readinessGates了
  • 第14行开始循环它,如果未找到,则输入错误,如果找到了但是为ready,也是输入错误
  • 如果错误不为空,则返回pod未ready
  • 如果错误为空,代表pod是ready状态的
func GeneratePodReadyCondition(spec *v1.PodSpec, conditions []v1.PodCondition, containerStatuses []v1.ContainerStatus, podPhase v1.PodPhase) v1.PodCondition {containersReady := GenerateContainersReadyCondition(spec, containerStatuses, podPhase)if containersReady.Status != v1.ConditionTrue {return v1.PodCondition{Type:    v1.PodReady,Status:  containersReady.Status,Reason:  containersReady.Reason,Message: containersReady.Message,}}unreadyMessages := []string{}for _, rg := range spec.ReadinessGates {_, c := podutil.GetPodConditionFromList(conditions, rg.ConditionType)if c == nil {unreadyMessages = append(unreadyMessages, fmt.Sprintf("corresponding condition of pod readiness gate %q does not exist.", string(rg.ConditionType)))} else if c.Status != v1.ConditionTrue {unreadyMessages = append(unreadyMessages, fmt.Sprintf("the status of pod readiness gate %q is not \"True\", but %v", string(rg.ConditionType), c.Status))}}if len(unreadyMessages) != 0 {unreadyMessage := strings.Join(unreadyMessages, ", ")return v1.PodCondition{Type:    v1.PodReady,Status:  v1.ConditionFalse,Reason:  ReadinessGatesNotReady,Message: unreadyMessage,}}return v1.PodCondition{Type:   v1.PodReady,Status: v1.ConditionTrue,}
}

6.这里比较简单,找到conditions中为ready类型的返回。然后返回流程3的最后一步

func GetPodConditionFromList(conditions []v1.PodCondition, conditionType v1.PodConditionType) (int, *v1.PodCondition) {if conditions == nil {return -1, nil}for i := range conditions {if conditions[i].Type == conditionType {return i, &conditions[i]}}return -1, nil
}

7.这是流程3的代码,如果需要调谐,则进入到dispatchWork函数,然后触发了podworkers.updatepod。之后的就可以参考kubelet源码 删除pod(二)

		if status.NeedToReconcilePodReadiness(pod) {mirrorPod, _ := kl.podManager.GetMirrorPodByPod(pod)kl.dispatchWork(pod, kubetypes.SyncPodSync, mirrorPod, start)}func (kl *Kubelet) dispatchWork(pod *v1.Pod, syncType kubetypes.SyncPodType, mirrorPod *v1.Pod, start time.Time) {// Run the sync in an async worker.zkl.podWorkers.UpdatePod(UpdatePodOptions{Pod:        pod,MirrorPod:  mirrorPod,UpdateType: syncType,StartTime:  start,})*****
}

8.接下来要看pod是不是被驱逐和失败的状态,从缓存中取到pod信息,进行删除

		if eviction.PodIsEvicted(pod.Status) {if podStatus, err := kl.podCache.Get(pod.UID); err == nil {kl.containerDeletor.deleteContainersInPod("", podStatus, true)}}

二、添加

1触发HandlePodAdditions函数进行创建

  • 对pod根据时间戳升序排序
  • 如果是静态pod,走静态pod处理
  • 第17行,如果这个pod不是在停止中,就需要进行特殊处理。(pod是否能在node上创建的校验)
  • 第18行,流程2
  • 第19行,流程3
  • 第20行,rejectPod函数如果不能创建,则记录一下原因。
  • 通过校验后。dispatchWork触发,执行和上述一样的函数进行创建pod
  • 最后一行,把这个pod增加到定时探测中
case kubetypes.ADD:klog.V(2).InfoS("SyncLoop ADD", "source", u.Source, "pods", klog.KObjs(u.Pods))handler.HandlePodAdditions(u.Pods)func (kl *Kubelet) HandlePodAdditions(pods []*v1.Pod) {start := kl.clock.Now()sort.Sort(sliceutils.PodsByCreationTime(pods))for _, pod := range pods {existingPods := kl.podManager.GetPods() kl.podManager.AddPod(pod)if kubetypes.IsMirrorPod(pod) {kl.handleMirrorPod(pod, start)continue}if !kl.podWorkers.IsPodTerminationRequested(pod.UID) {activePods := kl.filterOutTerminatedPods(existingPods)if ok, reason, message := kl.canAdmitPod(activePods, pod); !ok {kl.rejectPod(pod, reason, message)continue}}mirrorPod, _ := kl.podManager.GetMirrorPodByPod(pod)kl.dispatchWork(pod, kubetypes.SyncPodCreate, mirrorPod, start)kl.probeManager.AddPod(pod)}
}

2.把所有pod进行校验,验证一下新创建的pod是否允许创建。

  • 第4行和7行,如果pod停止完成了或者运行完成和失败的并且不是停止中。就跳过
  • 否则记录存入切片里返回。获得已经正在成功运行的pod后续好计算CPU和内存
func (kl *Kubelet) filterOutInactivePods(pods []*v1.Pod) []*v1.Pod {filteredPods := make([]*v1.Pod, 0, len(pods))for _, p := range pods {if kl.podWorkers.IsPodKnownTerminated(p.UID) {continue}if kl.isAdmittedPodTerminal(p) && !kl.podWorkers.IsPodTerminationRequested(p.UID) {continue}filteredPods = append(filteredPods, p)}return filteredPods
}

3.校验是否能在node上创建
第四行为函数校验,这里情况比较多,不全部贴代码,大概是验证一下pod的可创建型,有以下几种函数

  • node是否已经ready,如果没有ready,可以根据pod的优先级是否可以创建(2000000000优先级可以直接创建)
  • sysctl是否是有效的
  • node节点上的资源是否足够
func (kl *Kubelet) canAdmitPod(pods []*v1.Pod, pod *v1.Pod) (bool, string, string) {attrs := &lifecycle.PodAdmitAttributes{Pod: pod, OtherPods: pods}for _, podAdmitHandler := range kl.admitHandlers {if result := podAdmitHandler.Admit(attrs); !result.Admit {return false, result.Reason, result.Message}}return true, "", ""
}

上面的验证都通过,就会创建pod了

三、更新

1.同上原理

	case kubetypes.UPDATE:klog.V(2).InfoS("SyncLoop UPDATE", "source", u.Source, "pods", klog.KObjs(u.Pods))handler.HandlePodUpdates(u.Pods)

2.因为触发的是updates函数,所以和删除是一个道理,参考kubelet源码 删除pod(二)

相关内容

热门资讯

安卓系统苹果手机识别,跨界融合... 你知道吗?在科技飞速发展的今天,手机已经成为了我们生活中不可或缺的一部分。而说到手机,安卓系统和苹果...
harmonyos系统是不是安... 亲爱的读者,你是否曾好奇过HarmonyOS系统与安卓系统之间的关系?是不是安卓的“亲戚”?今天,就...
手机怎么装系统安卓,安卓系统安... 手机卡顿了?想给安卓系统来个大变身?别急,跟着我一步步来,保证让你的手机焕然一新!一、准备工作在开始...
安卓Linux系统内网穿透,A... 你有没有想过,你的安卓手机里那些看似普通的APP,其实可能正在悄悄地帮你打通网络世界的任督二脉呢?没...
win怎么安装安卓系统,Win... 亲爱的读者,你是不是对Win系统上的安卓应用垂涎已久,但又苦于不知道如何安装安卓系统呢?别急,今天我...
升级小米平板安卓系统,畅享全新... 你有没有发现,你的小米平板用久了,是不是感觉有点卡呢?别急,今天就来教你怎么给它来个系统升级,让它焕...
捷豹安卓系统车载,捷豹安卓系统... 哇,你有没有想过,当你的手机和汽车融为一体,会是怎样的体验呢?想象你正驾驶着你的捷豹,车窗外的风景如...
安卓1到10系统,安卓1.0至... 你有没有想过,手机里的安卓系统就像是我们生活中的好朋友,从青涩的少年成长为稳重的青年呢?从安卓1.0...
安卓8.0停用系统应用,提升使... 你知道吗?最近安卓系统又来了一次大动作,那就是安卓8.0系统开始停用一些系统应用了。这可真是让人有点...
安卓系统修改mtu值,轻松提升... 你有没有想过,你的安卓手机其实是个小小的电脑呢?它里面藏着许多可以自定义的秘密功能,就像修改MTU值...
安卓平板改window系统,探... 你有没有想过,你的安卓平板其实可以摇身一变,变成一个Windows系统的电脑呢?没错,就是那种可以运...
时空猎人安卓苹果系统,探索无尽... 你知道吗?最近在手机游戏圈里,有一款叫做《时空猎人》的游戏可是火得一塌糊涂呢!不管是安卓用户还是苹果...
安卓9.0系统的电视,新一代电... 亲爱的读者们,你是否也像我一样,对科技新玩意儿充满好奇?今天,我要和你聊聊一个让人眼前一亮的话题——...
小pc安装安卓系统,轻松安装安... 你有没有想过,你的小PC也能变身成为安卓系统的超级玩家呢?没错,就是那个平时默默无闻的小家伙,现在也...
高通备份安卓系统,全方位数据安... 你知道吗?在这个科技飞速发展的时代,手机备份可是个不得不提的话题。尤其是对于安卓用户来说,选择一个靠...
谷歌安卓系统有多少,从诞生到全... 你有没有想过,那个无处不在的谷歌安卓系统,究竟在全球有多少用户呢?它就像一个神秘的数字,每天都在悄悄...
fc黄金传说安卓系统,畅享复古... 你有没有听说最近安卓系统上的一款超酷的游戏——《FC黄金传说》?这款游戏可是让不少玩家都沉迷其中,今...
变小的我安卓系统,安卓系统演变... 你有没有发现,最近你的手机好像变轻了?没错,说的就是你,那个陪伴你多年的安卓系统。它悄无声息地进行了...
vivo安卓系统小彩蛋,体验科... 你知道吗?在vivo的安卓系统中,竟然隐藏着一些超有趣的小彩蛋!这些小彩蛋就像是在手机里埋下的宝藏,...
安卓系统如何强制重启,安卓系统... 手机突然卡壳了,是不是又该给它来个“大保健”了?没错,今天就来聊聊安卓系统如何强制重启。别小看这个看...