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(二)

相关内容

热门资讯

我来教大家“掼蛋大师辅助器ap... 亲,掼蛋大师这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,掼蛋大师的开挂软件,名...
我来教大家“开心联盟辅助器ap... 您好,开心联盟这款游戏可以开挂的,确实是有挂的,需要了解加微{7198902}很多玩家在这款游戏中打...
我来教大家“友愉棋牌辅助器ap... 您好,友愉棋牌这款游戏可以开挂的,确实是有挂的,需要了解加微{7198902}很多玩家在这款游戏中打...
我来教大家“全盛棋牌辅助器ap... 亲,全盛棋牌这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,全盛棋牌的开挂软件,名...
我来教大家“情怀三三麻将辅助器... 我来教大家“情怀三三麻将辅助器app官方下载最新版本更新”详细分享开挂一、情怀三三麻将AI软件牌型概...
我来教大家“无锡好运麻将辅助器... 亲,无锡好运麻将这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,无锡好运麻将的开挂...
我来教大家“推筒子辅助器app... 您好,推筒子这款游戏可以开挂的,确实是有挂的,需要了解加微{7198902}很多玩家在这款游戏中打牌...
我来教大家“比奇堡辅助器app... 我来教大家“比奇堡辅助器app官方下载最新版本更新”详细分享开挂1、让任何用户在无需AI插件第三方神...
我来教大家“新兴茶苑辅助器ap... 我来教大家“新兴茶苑辅助器app官方下载最新版本更新”详细分享开挂1、让任何用户在无需AI插件第三方...
我来教大家“欢乐互动辅助器ap... 我来教大家“欢乐互动辅助器app官方下载最新版本更新”详细分享开挂1、让任何用户在无需AI插件第三方...
我来教大家“东方互娱辅助器ap... 亲,东方互娱这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,东方互娱的开挂软件,名...
我来教大家“天天乐清麻将辅助器... 我来教大家“天天乐清麻将辅助器app官方下载最新版本更新”详细分享开挂一、天天乐清麻将AI软件牌型概...
我来教大家“唐三彩辅助器app... 我来教大家“唐三彩辅助器app官方下载最新版本更新”详细分享开挂一、唐三彩AI软件牌型概率发牌机制”...
我来教大家“Y0辅助器app官... 我来教大家“Y0辅助器app官方下载最新版本更新”详细分享开挂一、Y0AI软件牌型概率发牌机制”必胜...
我来教大家“天天互娱辅助器ap... 亲,天天互娱这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,天天互娱的开挂软件,名...
我来教大家“悟空竞技麻将辅助器... 亲,悟空竞技麻将这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,悟空竞技麻将的开挂...
我来教大家“情怀开化麻将辅助器... 我来教大家“情怀开化麻将辅助器app官方下载最新版本更新”详细分享开挂一、情怀开化麻将AI软件牌型概...
我来教大家“龙炎互娱辅助器ap... 我来教大家“龙炎互娱辅助器app官方下载最新版本更新”详细分享开挂一、龙炎互娱AI软件牌型概率发牌机...
我来教大家“闲逸碰胡辅助器ap... 亲,闲逸碰胡这款游戏可以开挂的,确实是有挂的,。但是开挂要下载第三方辅助软件,闲逸碰胡的开挂软件,名...
我来教大家“友聚麻将辅助器ap... 我来教大家“友聚麻将辅助器app官方下载最新版本更新”详细分享开挂一、友聚麻将AI软件牌型概率发牌机...