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

相关内容

热门资讯

身份证号码加名字大全-身份证号... 我是一个身份证号码加名字大全的收集者,多年来我一直在搜集各种有趣、奇特的身份证号码和名字。今天,我将...
windows8.1无法激活-... 首先,让我向大家介绍一下我自己,我是一名IT技术支持工程师,负责为用户提供技术支持和解决各种问题。最...
xp电脑开机后打不开软件-XP... 在我们日常使用电脑的过程中,有时候会遇到一些烦人的问题,比如xp电脑开机后打不开软件。这个问题让很多...
多个wifi合并网速增加-网速... 多个wifi合并,网速瞬间提速!这是令人振奋的消息,尤其是对于那些长期受困于低网速的用户来说。近日,...
ecshop模板二次开发:三步... 作为一名经验丰富的ecshop模板二次开发工程师,我将分享我在这个领域的宝贵经验。通过三个重点,我将...
安卓微信数据恢复软件,一键找回... 安卓微信数据恢复软件,你值得拥有!随着智能手机的普及,微信已经成为了我们日常生活中不可或缺的一部分。...
雨林木风u盘启动:故障排除新利... 雨林木风u盘启动是一款备受欢迎的电脑系统启动工具,其独特的特点和强大的功能使其在用户中享有盛誉。作为...
身份证号码查电信欠费-身份证号... 你有没有遇到过这样的情况?突然间收到一封短信,说你的身份证号码在电信处有欠费记录。是真的吗?该怎么办...
百度网盘纯净版全攻略,解锁高速... 百度网盘纯净版,我为你解答。作为一名资深IT工程师,我经常接到关于百度网盘的问题。今天,我将针对一些...
win764位主题包-Win7... 一、超强性能,让你畅享游戏乐趣作为一位电脑发烧友,我们都追求极致的性能和流畅的游戏体验。而今天我给大...
mallbuilderv-【超... 作为一名建筑师,我亲身体验了mallbuilderv这款强大的建筑模拟游戏。在游戏中,我扮演着一名建...
未来虚拟世界,与你互动的虚拟机... 虚拟机vpc 2023是一款引领未来科技发展的创新产品。作为全球首个具备人工智能交互功能的虚拟现实设...
libeay32dll下载到本... 1.功能丰富:libeay32dll是一个功能强大的动态链接库文件,它可以提供多种加密和解密算法,包...
电脑打不开软件闪退-电脑软件闪... 我是一名资深IT工程师,在这个数字时代,电脑成为我们生活中不可或缺的工具。但是,你有没有遇到过电脑打...
如何成为手机号查身份证号黑客?... 作为一名专业的手机号查身份证号黑客,我在这里分享一些我在工作中的经验和技巧。通过对手机号和身份证号的...
全时会议系统:稳定可靠,功能多... 全时会议系统是一款功能强大的在线会议平台,作为一名资深IT工程师,我在过去几个月中使用了多个在线会议...
电脑显示已连接上但是无法上网-... 近日,一则关于电脑连接上但无法上网的新闻引起了广大用户的关注。经过调查发现,造成这一问题的原因竟然是...
主机六核和八核的区别-六核vs... 主机六核和八核的区别是什么?这是一个经常被问到的问题。作为一名资深电脑硬件工程师,我将为大家详细解答...
生分证号码张林香-张林香:从普... 生分证号码张林香是一位普通的市民,但她的故事却非同寻常。在这个充满机遇和挑战的社会中,她用自己的努力...
sex little girl... 亲身体验:与“sex little girljapan”共度的日子在这个美丽的岛国,我作为一名旅行作...