浅析Kubelet如何上报状态

2023-10-31

浅析Kubelet如何上报状态

1 kubelet上报节点状态

在K8S集群中,由运行在每个节点的Kubelet定期上报心跳到ApiServer,以此来判断Node是否存活,若Node超过一定时间没有上报心跳,则该节点的状态会被设置为NotReady,同时运行在该节点的容器状态也会被设置为Unknown状态。

1.1 Kubelet上报哪些状态

在K8S中,一个Node的状态包含以下信息:
 Addresses
 Condition
 Capacity
 Info
Address主要包含以下几个字段:
 HostName:即主机名,可以通过kubelet的–hostname-override参数进行覆盖。
 ExternalIP:通常是可以外部路由的Node IP(从集群外可访问)。
 InternalIP:通常是仅可以在集群内部路由的Node IP地址。
Condition主要包含以下内容:
 Ready:如果节点是健康的并已经准备好接收接收Pod则为True;False表示节点不健康而且不能接收Pod;Unknow则表示节点控制器最近node-monitor-grace-period期间(默认40秒)没有收到节点的消息。
 DiskPressure:True表示节点存在磁盘压力,即磁盘可用量低,否则为False。
 MemoryPressure:True表示节点存在内存压力,即内存可用量低,否则为False。
 PIDPressure:True表示节点存在进程压力,即节点上进程过多;否则为False。
Capacity:述节点上的可用资源:CPU、内存和可以调度到节点上的 Pod 的个数上限。
 capacity:表示节点拥有的资源总量。
 allocatable:表示节点上可供普通Pod消耗的资源量
Info:描述节点的一般信息,如内核版本、Kubernetes 版本(kubelet 和 kube-proxy 版本)、 容器运行时详细信息,以及 节点使用的操作系统。

2 Kubelet状态异常时的影响

当一个Node处于非Ready状态超过Pod-eviction-timeout的值(默认为5分钟,在kube-controller-manager中定义),kube-controller-manager不会force delete pod,运行在该节点的Pod会一直处于Terminating或者Unknow状态,直到Node从集群中删除,或者kubelet状态变为Ready,在Node NotReady期间,不同的控制器处理方式不同,依次如下:
 Daemonset:Pod的状态变为Nodelost
 Deployment:先变为Nodelost,然后变成Unknown,最后会在其他正常的节点重新创建。
 StaticPod:先变为Nodelost,然后一直处于Unknown(staticPod即为/etc/kubernetes/manifest下的yaml文件)
 Statefulset:先变为Nodelost,然后一直处于Unknown
当Kubelet再次变为Ready状态时,以上控制器的处理方式如下:
 Daemonset:Pod不会重新创建,旧Pod的状态直接变为Running。
 Deployment:则会将运行在该节点的旧Pod删除。
 Statefulset:会将Pod重新进行创建。
 Static Pod:则会被删除。

3 Kubelet状态上报的实现

Kubelet上报状态有两种方式,分别是NodeStatus和NodeLease。具体实现方式如下:
 NodeStatus:由Kubelet定期向Apiserver上报心跳,超时没有上报则会将Node标记为UnReady,Node上的Pod也会标记为NodeLost或者Unknow。默认更新时间5分钟。
 NodeLease上报:在命名空间kube-node-lease会为每个节点都关联一个Lease对象,由节点定期更新Lease对象。默认每隔更新周期为10S。
状态的信息依靠NodeLease来实现上报,减少apiserver的压力,并且其上传的信息相对于Node的信息少很多,比较轻量。

4 Kubelet Not Ready分析

宿主机是否Ready取决于很多条件,包含运行时判定、网络判定、基本资源判定等。源码内容如下:
func (kl *Kubelet) defaultNodeStatusFuncs() []func(*v1.Node) error {
// if cloud is not nil, we expect the cloud resource sync manager to exist
var nodeAddressesFunc func() ([]v1.NodeAddress, error)
if kl.cloud != nil {
nodeAddressesFunc = kl.cloudResourceSyncManager.NodeAddresses
}
var validateHostFunc func() error
if kl.appArmorValidator != nil {
validateHostFunc = kl.appArmorValidator.ValidateHost
}
var setters []func(n *v1.Node) error
setters = append(setters,
nodestatus.NodeAddress(kl.nodeIPs, kl.nodeIPValidator, kl.hostname, kl.hostnameOverridden, kl.externalCloudProvider, kl.cloud, nodeAddressesFunc),
nodestatus.MachineInfo(string(kl.nodeName), kl.maxPods, kl.podsPerCore, kl.GetCachedMachineInfo, kl.containerManager.GetCapacity,
kl.containerManager.GetDevicePluginResourceCapacity, kl.containerManager.GetNodeAllocatableReservation, kl.recordEvent),
nodestatus.VersionInfo(kl.cadvisor.VersionInfo, kl.containerRuntime.Type, kl.containerRuntime.Version),
nodestatus.DaemonEndpoints(kl.daemonEndpoints),
nodestatus.Images(kl.nodeStatusMaxImages, kl.imageManager.GetImageList),
nodestatus.GoRuntime(),
)
// Volume limits
setters = append(setters, nodestatus.VolumeLimits(kl.volumePluginMgr.ListVolumePluginWithLimits))

setters = append(setters,
	nodestatus.MemoryPressureCondition(kl.clock.Now, kl.evictionManager.IsUnderMemoryPressure, kl.recordNodeStatusEvent),
	nodestatus.DiskPressureCondition(kl.clock.Now, kl.evictionManager.IsUnderDiskPressure, kl.recordNodeStatusEvent),
	nodestatus.PIDPressureCondition(kl.clock.Now, kl.evictionManager.IsUnderPIDPressure, kl.recordNodeStatusEvent),
	nodestatus.ReadyCondition(kl.clock.Now, kl.runtimeState.runtimeErrors, kl.runtimeState.networkErrors, kl.runtimeState.storageErrors, validateHostFunc, kl.containerManager.Status, kl.shutdownManager.ShutdownStatus, kl.recordNodeStatusEvent),
	nodestatus.VolumesInUse(kl.volumeManager.ReconcilerStatesHasBeenSynced, kl.volumeManager.GetVolumesInUse),
	// TODO(mtaufen): I decided not to move this setter for now, since all it does is send an event
	// and record state back to the Kubelet runtime object. In the future, I'd like to isolate
	// these side-effects by decoupling the decisions to send events and partial status recording
	// from the Node setters.
	kl.recordNodeSchedulableEvent,
)
return setters

}
大部分情况下,我们只需要关注运行时的判定,即runtimeErrors,而runtimeErrors的判定条件有两个,分别如下:
 距离最近一次运行时同步操作的时间间隔超过指定阈值(默认是30s)
 运行时健康检查未通过。
对应的源码如下:
func (s *runtimeState) runtimeErrors() error {
s.RLock()
defer s.RUnlock()
errs := []error{}
if s.lastBaseRuntimeSync.IsZero() {
errs = append(errs, errors.New(“container runtime status check may not have completed yet”))
} else if !s.lastBaseRuntimeSync.Add(s.baseRuntimeSyncThreshold).After(time.Now()) {
errs = append(errs, errors.New(“container runtime is down”))
}
for _, hc := range s.healthChecks {
if ok, err := hc.fn(); !ok {
errs = append(errs, fmt.Errorf(“%s is not healthy: %v”, hc.name, err))
}
}
if s.runtimeError != nil {
errs = append(errs, s.runtimeError)
}

return utilerrors.NewAggregate(errs)

}

4.1 lastBaseRuntimeSync

正常情况下,kubelet 每隔 5s 会将 lastBaseRuntimeSync 设置为当前时间,而宿主状态异常时,这个时间戳一直未被更新。也即 updateRuntimeUp 一直被阻塞在设置 lastBaseRuntimeSync 之前的某一步。
具体的函数调用链为:
initializeRuntimeDependentModules -> kl.cadvisor.Start -> cc.Manager.Start -> self.createContainer -> m.createContainerLocked -> container.NewContainerHandler -> factory.CanHandleAndAccept -> self.client.ContainerInspect

4.2 healthChecks

暂无,后期更新

5 判断节点是否就绪的重要指标PLEG

PLEG是Pod Lifecycle Events Generator的缩写,基本上它的执行逻辑,是定期检查节点上Pod运行情况,如果发现感兴趣的变化,PLEG就会把这种变化包装成Event发送给Kubelet的主同步机制syncLoop去处理。但是,在PLEG的Pod检查机制不能定期执行的时候,NodeStatus机制就会认为,这个节点的状况是不对的,从而把这种状况同步到API Server。
5.1 PLEG的工作流程

kubelet中的NodeStatus机制会定期检查集群节点状况,并把节点状况同步到API Server。而NodeStatus判断节点就绪状况的一个主要依据,就是PLEG。
PLEG定期检查节点上Pod运行情况,并且会把pod 的变化包装成Event发送给Kubelet的主同步机制syncLoop去处理。但是,在PLEG的Pod检查机制不能定期执行的时候,NodeStatus机制就会认为这个节点的状况是不对的,从而把这种状况同步到API Server,我们就会看到 not ready 。
PLEG有两个关键的时间参数,一个是检查的执行间隔,另外一个是检查的超时时间。以默认情况为准,PLEG检查会间隔一秒,换句话说,每一次检查过程执行之后,PLEG会等待一秒钟,然后进行下一次检查;而每一次检查的超时时间是三分钟,如果一次PLEG检查操作不能在三分钟内完成,那么这个状况,会被NodeStatus机制当做集群节点NotReady的凭据,同步给API Server。
PLEG Start就是启动一个协程,每个relistPeriod(1s)就调用一次relist,根据最新的PodStatus生成PodLiftCycleEvent。relist是PLEG的核心,它从container runtime中查询属于kubelet管理containers/sandboxes的信息,并与自身维护的 pods cache 信息进行对比,生成对应的 PodLifecycleEvent,然后输出到 eventChannel 中,通过 eventChannel 发送到 kubelet syncLoop 进行消费,然后由 kubelet syncPod 来触发 pod 同步处理过程,最终达到用户的期望状态。
从 Docker 1.11 版本开始,Docker 容器运行就不是简单通过 Docker Daemon 来启动了,而是通过集成 containerd、runc 等多个组件来完成的。虽然 Docker Daemon 守护进程模块在不停的重构,但是基本功能和定位没有太大的变化,一直都是 CS 架构,守护进程负责和 Docker Client 端交互,并管理 Docker 镜像和容器。现在的架构中组件 containerd 就会负责集群节点上容器的生命周期管理,并向上为 Docker Daemon 提供 gRPC 接口。

PLEG在每次迭代检查中会调用runc的 relist() 函数干的事情,是定期重新列出节点上的所有容器,并与上一次的容器列表进行对比,以此来判断容器状态的变换。相当于docker ps来获取所有容器,在通过docker Inspect来获取这些容器的详细信息。

5.2 PLEG排查指南

5.2.1 Docker夯死导致PLEG is not health

当Node节点的某个容器状态异常时,kubelet执行docker inspect操作也会被夯死。从而会导致PLET is not health。此时docker 无法进行任何操作。
我们需要借助pprof工具来进行深入分析,通过socat结合pprof工具输出docker的堆栈信息,进一步分析,使用方法如下:
1、 在异常节点安装socat命令
yum install socat -y

2、 执行如下命令,bind填写本机暴露的地址,端口自定义
socat -d -d TCP-LISTEN:18080,fork,bind=192.168.36.13 UNIX:/var/run/docker.sock

3、 通过页面访问http://192.168.36.13:18080/debug/pprof/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

浅析Kubelet如何上报状态 的相关文章

随机推荐

  • 《CTFshow-Web入门》03. Web 21~30

    Web 21 30 索引 web21 题解 原理 web22 题解 原理 web23 题解 原理 web24 题解 原理 web25 题解 原理 web26 题解 web27 题解 web28 题解 web29 题解 原理 web30 题解
  • 【C#基础】C# 文件与IO

    序号 系列文章 9 C 基础 C 异常处理操作 10 C 基础 C 正则表达式 11 C 基础 C 预处理器指令 文章目录 前言 1 文件和IO的概念 2 文本文件操作 2 1 File 类 2 2 FileInfo 类 2 3 FileS
  • 不要消费信任

    消费是一种用来满足人们各种需求的过程 人们可以通过消费来满足吃 穿 住 行等物质上的需求 同样的 人们也可以通过消费来满足非物质需求 如 消费人情 权力等 当今世界 消费 是一种需要 而会消费 是一种艺术 但无论怎样 有一种 物品 是绝对经
  • xctf攻防世界 MISC高手进阶区 low

    1 进入环境 下载附件 给出的一张bmp图片 没有其他信息 2 问题分析 扔进binwalk中 没有发现有用信息 使用zsteg 没有有用信息 塞入StegSolve中 发现有点猫腻 如图 有点二维码的感觉 emmm 需要像素处理 但不知道
  • css 获取当前类的子类,删除子类列表项的CSS类属性

    我一直试图在Html中创建一个无序列表 css类将附加 ul 元素及其子元素 li 元素 问题是如果另一个 无序列表 成为这个父无序列表的子元素 删除子类列表项的CSS类属性 我创建了下面的示例 以显示我的问题 的Javascript fu
  • 超详解“二分法查找”,一看就会!

    目录 一 二分法概念用途 二 超详思维图解 三 超详使用方法实现代码运行操作 四 总结 五 结语 一 二分法概念用途 什么是二分法 有什么作用 一般用在何处 概念 二分查找法算法 也叫折半查找算法 对半处理会提高寻找目标数字的效率 作用 在
  • 计算机视觉——图像增强

    图像增强的定义非常广泛 一般来说 图像增强是有目的地强调图像的整体或局部特性 例如改善图像的颜色 亮度和对比度等 将原来不清晰的图像变得清晰或强调某些感兴趣的特征 扩大图像中不同物体特征之间的差别 抑制不感兴趣的特征 提高图像的视觉效果 传
  • “范式杯”2023牛客暑期多校训练营10

    K First Last 一共有n个人 然后每一局拿到第一名或者最后一名的概率为2 n 然后连续m局拿到第一名或者最后一名的概率为pow 2 n m 特判一下当n为1时 拿第一名或者最后一名的概率为1 注意 输出1时要写1 0 写1的话就w
  • Jinja 2模板引擎

    如何使用Flask渲染摸板 在模板中传递一个或多个参数 if 语句在摸板中的使用 for 语句在模板中的使用 Flask 提供了Jiaja 2模板引擎渲染模板 下面逐步介绍其模板渲染机制 templates index html user
  • Phpstorm 插件

    Symfony Plugin 支持 Symfony 2 3 4 Laravel Plugin 支持 Laravel env files support 支持 env 文件BashSupport 支持 BashEditorConfig 支持
  • 【低功耗蓝牙】⑤ 蓝牙HID协议

    摘要 本文章主要介绍了蓝牙HID协议的实现方法 基于ESP32平台实现了蓝牙键盘 蓝牙鼠标 蓝牙自拍杆和蓝牙游戏手柄等设备 是初学者学习BLE HID协议很好的参考文章 HID设备 HID Human Interface Device 人体
  • golang 判断 interface{} 是否为nil

    问题描述 当函数返回值是interface 时 需要判断是不是返回值是不是nil func check interface return nil func main c check if c nil reflect ValuOf c IsN
  • IDEA Android用户登录页面、登录验证、页面跳转演示示例全部源码

    开发工具 IDEA 2022 3 2 未连接数据库 验证用的用户名和密码为内置硬编码 演示程序运行效果 设计器中的用户登录页面布局 登录验证容错提示如下 1 用户名不能为空 2 密码不能为空 3 用户名不存在 4 用户密码错误 5 登录验证
  • lol峡谷之巅区服务器位置,LOL峡谷之巅专区申请地址一览 峡谷之巅介绍

    峡谷之巅 超级专区是英雄联盟官方搭建的 只提供给钻石I 超凡大师 最强王者的玩家及现役战队选手的公平竞技大区 在 峡谷之巅 中 各个服务器的顶级强者及现役战队选手将会共同进行召唤师峡谷的单人排位角逐 该大区的核心宗旨 进一步提升英雄联盟高端
  • 低频能不能采到高频?采样定理指导硬件设计

    原文来自公众号 工程师看海 香浓采样定理或者说奈奎斯特采样定理告诉我们 要以信号频率2倍以上的采样率对该信号进行采样 否则会出现频率混叠 比如对1Khz信号进行采样的话 采样率要高于2Ksps 采样定理与傅里叶变换的具体原理请见往期文章 h
  • Could not create task ‘:app:minifyReleaseWithR8‘. Cannot query the value of this provider because it

    重新部署AndroidStudio发现项目报错 Could not create task app minifyReleaseWithR8 Cannot query the value of this provider because it
  • 性能测试工具LoadRunner —— 性能测试流程及结果分析

    性能测试目的 1 什么是性能测试 性能测试是通过性能的测试工具模拟多种正常 峰值以及异常负载条件来对系统的各项性能指标进行测试 负载测试和压力测试都属于性能测试 两者可以结合进行 通过负载测试 确定在各种工作负载下系统的性能 目标是测试当负
  • mac环境下Maven实现ProtoBuf编译

    mac环境下Maven实现protobuf编译 1 Maven项目创建 File gt new gt Project gt 输入项目名称 gt finish 2 在项目中创建proto目录 该目录用来保存 proto文件 此处将proto目
  • cpp: Memento Pattern

    file ActorMemento h brief 备忘录模式 Memento Pattern亦称 快照 Snapshot Memento C 14 2023年6月6日 涂聚文 Geovin Du Visual Studio 2022 ed
  • 浅析Kubelet如何上报状态

    浅析Kubelet如何上报状态 1 kubelet上报节点状态 在K8S集群中 由运行在每个节点的Kubelet定期上报心跳到ApiServer 以此来判断Node是否存活 若Node超过一定时间没有上报心跳 则该节点的状态会被设置为Not