kubelet源码 删除pod(二)

news2024/11/27 12:41:23

kubelet源码 删除pod(二)

本文中含有k8s的一个bug,我也正在努力提交PR,不过会不会被merge就不清楚了。

kubernetes PR地址

pod_workers.go是主要处理pod变化的文件,在1.22版本后对这个文件进行了比较大的修改。把属于pod处理的工作都放在了这个文件里。并且对pod分段处理,如审查、标记状态、处理状态等。

1、options为pod的一些基本信息。runningPod是运行中 的pod,如果runningPod存在,并且pod配置不存在,则代表是孤儿pod,只能进行删除。如果pod和runningPod都存在,则代表都会被更新,所以只保留pod即可。
在这里插入图片描述
2.对整个结构体进行加锁,避免污染数据。
根据uid取出当前pod状态,12行中,如果pod是不是个孤儿pod并且状态是失败或者已完成的,则记录他的状态。13行是从本地缓存中获得运行时的pod状态(不是这次要更新的状态)这里14行的函数,判断的是pod下的容器是否运行状态。流程3介绍。

  p.podLock.Lock()
	defer p.podLock.Unlock()

	now := time.Now()
	status, ok := p.podSyncStatuses[uid]
	if !ok {
		klog.V(4).InfoS("Pod is being synced for the first time", "pod", klog.KObj(pod), "podUID", pod.UID)
		status = &podSyncStatus{
			syncedAt: now,
			fullname: kubecontainer.GetPodFullName(pod),
		}
		if !isRuntimePod && (pod.Status.Phase == v1.PodFailed || pod.Status.Phase == v1.PodSucceeded) {
			if statusCache, err := p.podCache.Get(pod.UID); err == nil {
				if isPodStatusCacheTerminal(statusCache) {
					status = &podSyncStatus{
						terminatedAt:       now,
						terminatingAt:      now,
						syncedAt:           now,
						startedTerminating: true,
						finished:           true,
						fullname:           kubecontainer.GetPodFullName(pod),
					}
				}
			}
		}
		p.podSyncStatuses[uid] = status
	}

3.判断pod是否已经停止了。遍历容器查看是否有运行中的容器。还要判断“sb"是否有运行中的。如果都为0,则代表pod已经运行完成。然后代码2中的30行,将状态存到pod的状态流的map中

func isPodStatusCacheTerminal(status *kubecontainer.PodStatus) bool {
	runningContainers := 0
	runningSandboxes := 0
	for _, container := range status.ContainerStatuses {
		if container.State == kubecontainer.ContainerStateRunning {
			runningContainers++
		}
	}
	for _, sb := range status.SandboxStatuses {
		if sb.State == runtimeapi.PodSandboxState_SANDBOX_READY {
			runningSandboxes++
		}
	}
	return runningContainers == 0 && runningSandboxes == 0
}

4.第一行判断为该pod是否已经停止了。如果已经停止了,并且这次的更新又是创建,则标记pod状态为重启启动。这个场景一般是静态pod才会出现,通常是具有相同UID。如果是此情况则后续会重新启动。
第9行判断是pod状态是否是已完成了。不归pod_workers管了,后续housekeeping会去清除他。

	if status.IsTerminationRequested() {
		if options.UpdateType == kubetypes.SyncPodCreate {
			status.restartRequested = true
			klog.V(4).InfoS("Pod is terminating but has been requested to restart with same UID, will be reconciled later", "pod", klog.KObj(pod), "podUID", pod.UID)
			return
		}
	}

	if status.IsFinished() {
		klog.V(4).InfoS("Pod is finished processing, no further updates", "pod", klog.KObj(pod), "podUID", pod.UID)
		return
	}

特殊,下面流程的5.6需要这几个函数,在这里标注一下

func (s *podSyncStatus) IsWorking() bool              { return s.working }
func (s *podSyncStatus) IsTerminationRequested() bool { return !s.terminatingAt.IsZero() }
func (s *podSyncStatus) IsTerminationStarted() bool   { return s.startedTerminating }
func (s *podSyncStatus) IsTerminated() bool           { return !s.terminatedAt.IsZero() }
func (s *podSyncStatus) IsFinished() bool             { return s.finished }
func (s *podSyncStatus) IsEvicted() bool              { return s.evicted }
func (s *podSyncStatus) IsDeleted() bool              { return s.deleted }

5.上面的一些特殊场景的处理都做完了,到这开始对当前pod进行标记状态了。

  • 先给becameTerminating标定为false,这个变量或许会用做是否这个pod杠开始进行删除。
  • 第4行case判断是否是孤儿pod,如果是孤儿pod,标记删除(这个标记是apiserver上也删除了),删除初始时间是现在,标记pod刚开始删除
  • 第9行case判断的是是否为优雅的删除(DeletionTimestamp就是grace period的时间,如果未传,默认30s)
  • 第14行,如果pod的状态是失败或者运行完成,只更新删除初始时间和刚开始删除,但是不会标记apiserver上已删除
  • 第18行,如果这个pod是删除。如果还是一个被驱逐的pod,则标记驱逐状态(KillPodOptions为pod的终止行为)
	var becameTerminating bool
	if !status.IsTerminationRequested() {
		switch {
		case isRuntimePod:
			klog.V(4).InfoS("Pod is orphaned and must be torn down", "pod", klog.KObj(pod), "podUID", pod.UID)
			status.deleted = true    //如果为true,代表apiserver上也已经删除
			status.terminatingAt = now   //删除的开始时间
			becameTerminating = true     //刚开始进入删除流程
		case pod.DeletionTimestamp != nil:
			klog.V(4).InfoS("Pod is marked for graceful deletion, begin teardown", "pod", klog.KObj(pod), "podUID", pod.UID)
			status.deleted = true
			status.terminatingAt = now
			becameTerminating = true
		case pod.Status.Phase == v1.PodFailed, pod.Status.Phase == v1.PodSucceeded:
			klog.V(4).InfoS("Pod is in a terminal phase (success/failed), begin teardown", "pod", klog.KObj(pod), "podUID", pod.UID)
			status.terminatingAt = now
			becameTerminating = true
		case options.UpdateType == kubetypes.SyncPodKill:
			if options.KillPodOptions != nil && options.KillPodOptions.Evict {
				klog.V(4).InfoS("Pod is being evicted by the kubelet, begin teardown", "pod", klog.KObj(pod), "podUID", pod.UID)
				status.evicted = true
			} else {
				klog.V(4).InfoS("Pod is being removed by the kubelet, begin teardown", "pod", klog.KObj(pod), "podUID", pod.UID)
			}
			status.terminatingAt = now
			becameTerminating = true
		}
	}

6.workType标记这个pod声明周期的状态(sync同步、terminating终止中、terminated清理)
wasGracePeriodShortened代表是否缩短优雅删除时间;例,第一次优雅删除(grace period)时间是30s,第二次是10s,则代表缩短)。这个官方存在bug,无法成功缩短优雅删除时间 后面会介绍bug原因

  • 第4行case判断是否pod已经删除完成了,第5行判断是否是孤儿pod(可能是旧缓存)直接忽略就可以。第12行验证一下是否是completed状态,如果是的话,关闭这个管道并且置空。
  • 第19行,如果pod刚刚开始准备删除,如果是cpmpleted状态,暂存到notifyPostTerminating(后续会停止成功后统一关闭管道)PodStatusFunc记录的是kill pod的状态。然后判断优雅删除的时间(流程7)
  • 第39行同理
  var workType PodWorkType 
	var wasGracePeriodShortened bool
	switch {
	case status.IsTerminated():
		if isRuntimePod {
			klog.V(3).InfoS("Pod is waiting for termination, ignoring runtime-only kill until after pod worker is fully terminated", "pod", klog.KObj(pod), "podUID", pod.UID)
			return
		}

		workType = TerminatedPodWork

		if options.KillPodOptions != nil {
			if ch := options.KillPodOptions.CompletedCh; ch != nil {
				close(ch)
			}
		}
		options.KillPodOptions = nil

	case status.IsTerminationRequested():
		workType = TerminatingPodWork
		if options.KillPodOptions == nil {
			options.KillPodOptions = &KillPodOptions{}
		}

		if ch := options.KillPodOptions.CompletedCh; ch != nil {
			status.notifyPostTerminating = append(status.notifyPostTerminating, ch)
		}
		if fn := options.KillPodOptions.PodStatusFunc; fn != nil {
			status.statusPostTerminating = append(status.statusPostTerminating, fn)
		}

		gracePeriod, gracePeriodShortened := calculateEffectiveGracePeriod(status, pod, options.KillPodOptions)

		wasGracePeriodShortened = gracePeriodShortened
		status.gracePeriod = gracePeriod

		options.KillPodOptions.PodTerminationGracePeriodSecondsOverride = &gracePeriod

	default:
		workType = SyncPodWork

		if options.KillPodOptions != nil {
			if ch := options.KillPodOptions.CompletedCh; ch != nil {
				close(ch)
			}
			options.KillPodOptions = nil
		}
	}

7.优雅时间只能缩短,如果不是缩短则不用更改时间。优雅删除时间不能为0

  • 第3.4行的判断就是验证新的请求时间是否缩短。
  • 9行判断一下pod的删除状态(可能存在驱逐)
  • 15行判断优雅时间是否为0,如果为0并且pod的配置文件删除时间不为空,则替换
  • 最终的优雅删除时间如果还小于1,则等于1**(这里还存在一个bug,因为强制删除–force的删除时间就是0,如果这里强行判断等于1,那等于强制删除会采用默认的30s,导致apiserver和kubelet不同步)**
func calculateEffectiveGracePeriod(status *podSyncStatus, pod *v1.Pod, options *KillPodOptions) (int64, bool) {
   gracePeriod := status.gracePeriod
   if override := pod.DeletionGracePeriodSeconds; override != nil {
      if gracePeriod == 0 || *override < gracePeriod {
         gracePeriod = *override
      }
   }
   if options != nil {
      if override := options.PodTerminationGracePeriodSecondsOverride; override != nil {
         if gracePeriod == 0 || *override < gracePeriod {
            gracePeriod = *override
         }
      }
   }
   if gracePeriod == 0 && pod.Spec.TerminationGracePeriodSeconds != nil {
      gracePeriod = *pod.Spec.TerminationGracePeriodSeconds
   }
   if gracePeriod < 1 {
      gracePeriod = 1
   }
   return gracePeriod, status.gracePeriod != 0 && status.gracePeriod != gracePeriod
}

8.到此,pod的status状态记录就都完成了,该准备一下pod的期望状态然后进行处理了。

  • 6行根据uid获取一下这个pod是否有一个更新的处理管道请求。如果没有则创建,管道长度为1,同时只能更新一个请求。
  • 11行如果是静态pod,确保静态pod按照UpdatePod收到的顺序启动
  • 16行的无作用,测试使用临时加的。
  • 25行,给一个pod初始化成功(能走到这一流程,说明kubelet刚重新启动或pod第一次创建)
    每个pod有一个自己的goroutine专门处理自己的更新,并且同时间只能处理一个

9、完成这个函数的工作。此函数的任务就是对pod进行一些审查,并且对status状态链路进行更新,然后标记一下状态

  • 第一行,如果没在工作工作中,把上面配置好的work结构体推入到管。
  • 如果pod正在进行更新中,则进入第7行,如果已经存在一次为成功更新的pod请求,覆盖一下时间。并且第13行覆盖上次的更新,因为多次更新时,只采用最新的一次。
  • 15行,如果(正在删除中或者优雅删除缩短了)并且pod链路的退出信号已经被注册(这个注册是在managePodLoop函数中,下一篇会说到)。则直接关闭信号(为了是关闭上一次正在处理的更新)这里和流程6的bug相呼应,这里用context来取消阻塞的goroutine,但是后续并没有监听ctx.Done()导致cancel失败
if !status.IsWorking() {
		status.working = true
		podUpdates <- work
		return
	}

	if undelivered, ok := p.lastUndeliveredWorkUpdate[pod.UID]; ok {
		if !undelivered.Options.StartTime.IsZero() && undelivered.Options.StartTime.Before(work.Options.StartTime) {
			work.Options.StartTime = undelivered.Options.StartTime
		}
	}

	p.lastUndeliveredWorkUpdate[pod.UID] = work

	if (becameTerminating || wasGracePeriodShortened) && status.cancelFn != nil {
		klog.V(3).InfoS("Cancelling current pod sync", "pod", klog.KObj(pod), "podUID", pod.UID, "updateType", work.WorkType)
		status.cancelFn()
		return
	}

上一篇kubelet源码 删除pod(一)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/27118.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[附源码]SSM计算机毕业设计基于SSM的酒店管理系统JAVA

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

QT 字符串操作常用接口函数

目录常见字符串处理函数空白字符串处理函数查询字符串数据字符串比较字符串的转换QT版本的STLQLinkedList和QVector的区别QT提供的STL命名风格的迭代器QMap和QHash经过该简单设置可以防止msvc环境下使用qdebug打印输出时出现中文乱码的问题。 #include "learn.h" #i…

长话短说:学习网络安全自学好还是报培训班?

无论你是大学生还是在职人员&#xff0c;想学网络安全时&#xff0c;都会面临两个选择&#xff0c;自学或者报班。报班通常太费钱&#xff0c;时间又不自由&#xff1b;自学又不知道如何下手&#xff0c;担心自己坚持不下来。怎么办&#xff1f; 我们先分析一下自学和培训班的…

【文本分类】《融合注意力和剪裁机制的通用文本分类模型》

阅读摘要&#xff1a;   针对实际场景中长短文本大量的情况&#xff0c;提出了双通道注意力机制与长文本裁剪机制来改进文本分类模型&#xff0c;最终提高了精度。 参考文献&#xff1a;   [1] 融合注意力和剪裁机制的通用文本分类模型 参考论文信息 论文名称&#xff1a;《…

第三版全球干旱指数和潜在蒸散数据发布

Robert J. Zomer &#xff1b;JianchuXu&#xff1b;AntonioTrabucco(Kunming Institute of Botany, Chinese Academy of Science&#xff1b;Euro-Mediterranean Center on Climate Change, IAFES Division, Sassari, Italy) 摘要 潜在蒸散(Potential evapotranspiration&…

Linux Shell 自动交互功能实现

1. EOF 多文本输入 需求案例 1 新交付了一批机器&#xff0c;每台机器只分配了一块落盘 &#xff0c;现在根据需求对该盘进行分区并实现挂载&#xff0c;如何实现&#xff1f; 需求分析&#xff1a; 对于一个盘&#xff0c;实现分区挂载到不同目录&#xff0c;通常思路有两…

灯具行业MES解决方案,实现产品的正反向追溯

灯具照明行业产业链主要包括上游原材料、中游照明产品生产及封装、下游照明细分应用领域。产业链上游、中游多为资本密集与技术密集型行业&#xff0c;产品高度标准化&#xff0c;市场相对集中。而产业链下游产品需求相对个性化&#xff0c;多品类、多SKU&#xff0c;市场集中度…

探索性数据分析

有目的性的探索数据集以获取具体的优化方向和思路。 Intuition 探索性数据分析 (EDA) 以了解数据集的信号和细微差别。这是一个循环过程&#xff0c;可以在开发过程的各个阶段&#xff08;标记之前/之后、预处理等&#xff09;完成&#xff0c;具体取决于问题的定义程度。例如&…

【Proteus仿真】【STM32单片机】蔬菜大棚温湿度控制系统设计

文章目录一、主要功能二、硬件资源三、软件设计四、实验现象联系作者一、主要功能 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用LCD1602液晶、DHT11温湿度、蜂鸣器、按键、LED、继电器、电机模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示DH…

setup获取props和自定义事件、通过expose暴露给ref获取属性和方法、setup顶层async、setup返回函数

文章目录1. setup获取props和自定义事件2. 通过expose暴露给ref获取属性和方法3. setup顶层async4. setup返回函数1. setup获取props和自定义事件 child 组件&#xff1a; <template><div><h3>我是child组件 -- {{ title }}</h3><button click&qu…

We have awesome remote U.S. jobs waiting for engineers like you.

发件人&#xff1a;Turing - U.S. Software Jobs <hiringturing.com> Hi I saw your profile online and wanted to reach out! You might be a great fit for many high-paying remote U.S. software engineering opportunities on Turing.com. Turing is based in …

steam搬砖,长期稳定副业,附防坑指南助你不掉坑

大家伙&#xff0c;我是阿阳 今天给大家拆解一个冷门项目&#xff0c;国外steam游戏搬砖项目&#xff0c;这个项目也是自己正在做的第二个项目&#xff0c;虽然冷门&#xff0c;不暴利&#xff0c;做了这么久赚钱一直很稳定。站在一个搞钱人的角度来说&#xff0c;这个项目作为…

Docker部署单节点Kafka

文章目录Docker部署单节点Kafka参考镜像wurstmeister/zookeeper Overviewwurstmeister/kafka Overview部署单Brokerkafka 环境变量&#xff1a;启动与停止命令测试验证&#xff1a;参考文章Docker部署单节点Kafka 参考镜像 wurstmeister/zookeeper Overview docker pull wur…

Hadoop总结——HDFS

一、HDFS概述 1.1 HDFS产生背景 随着数据量越来越大&#xff0c;在一个操作系统管辖的范围内存不下了&#xff0c;那么就分配到更多的操作系统管理的磁盘中&#xff0c;但是不方便管理和维护&#xff0c;迫切需要一种系统来管理多台机器上的文件&#xff0c;这就是分布式文件…

记一次自定义starter引发的线上事故复盘

前言 本文素材来源于业务部门技术负责人某次线上事故复盘分享。故事的背景是这样&#xff0c;该业务部门招了一个技术挺不错的小伙子小张&#xff0c;由于小张技术能力在该部门比较突出&#xff0c;在入职不久后&#xff0c;他便成为这个部门某个项目组的team leader&#xff…

计算机外设:显示器是如何工作的?

本节我们将了解计算机的外设之一&#xff1a;显示器的底层工作原理。通过本节&#xff0c;你会知道电脑显示器是如何实时展示我们在计算机上的操作的&#xff0c;比如显示出一张“E”的字符。最后总结了计算机编程的本质&#xff0c;就是人们是通过设计&#xff0c;让字节代表不…

超迷你机械臂机器人,YYDS

真正的大师,永远都怀着一颗学徒的心&#xff01; 一、项目简介 超迷你机械臂机器人&#xff0c;YYDS 核心板&#xff1a; REF核心板 REF底板&#xff08;机械臂底座里面的控制器电路板&#xff09; 步进电机驱动 Peak示教器 文件&#xff1a; 3D模型设计源文件。 20步进…

Python机器学习 | AI芯片调研

AI芯片调研 1、 概念 AI芯片又叫AI加速器,专门用于处理人工智能应用中的大量计算任务的模块。 注意:其他非计算任务仍由CPU处理 2、 背景 神经网络需要大量的矩阵运算,CPU和传统计算架构无法满足对于并行计算能力的需求,需要特殊定制的AI芯片(GPU、TPU、NPU、DPU等等)…

Go Web项目学习之项目结构

风离不摆烂学习日志 Day4 — Go Web项目学习之项目结构 创建项目配置代理 下载加速 go 包代理 GOPROXYhttps://goproxy.cn,direct 本项目学习自&#xff1a; [github.com](https://github.com/gnimli/go-web-mini) 项目结构分层 ├─common # casbin mysql zap validator 等公…

web概述18

JSP JSP是Sun为了解决动态生成HTML文档的技术&#xff0c;通过Servlet输出简单html页面信息都非常不方便。如果要输出一个复杂页面的时候&#xff0c;就更加的困难&#xff0c;而且不利于页面的维护和调试。所以sun公司推出一种叫做jsp的动态页面技术来实现对页面的输出繁锁工…