浅析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/

浅析Kubelet如何上报状态相关推荐

  1. un9.9:实现上报及上报状态修改功能。

    项目中,我们经常会遇到上报数据的功能,今天小编就和大家从数据库到后端,再从后端到前端页面,一起实现这一功能. 逻辑:首先我需要查询表中的数据,查询到后再进行修改,修改的同时,状态也会修改. 一.我们首 ...

  2. 【网络同步】浅析帧同步和状态同步

    前言 谈到网络游戏,不可避免要谈到现有两种比较常见的网游同步技术:帧同步和状态同步 说到这两个名词,大家夸夸奇谈,都能讲上些许自己的见解,我反正啥也不懂 这篇文章就打算着重学习一下这两种技术的基础和原 ...

  3. linux检查防火墙是否阻挡端口,浅析linux查看防火墙状态和对外开放的端口状态...

    1.查看防火墙状态 查看防火墙状态 systemctl status firewalld 开启防火墙 systemctl start firewalld 关闭防火墙 systemctl stop fi ...

  4. Kubernetes Kubelet 状态更新机制

    Kubernetes Kubelet 状态更新机制 tags: kubelet 文章目录 Kubernetes Kubelet 状态更新机制 1. 概览 2. 配置 2.1 社区默认的配置 2.2 快 ...

  5. kubelet启动pod源码分析(三)

    之前的blog分析了kubelet启动pod的流程,那么pod一旦启动了,谁去上报状态呢?还是回到之前代码syncLoopIteration,这个里面有四个输入源,第一次创建接受到configch a ...

  6. ceph原理及工作流程浅析

    ceph工作原理及工作流程浅析 其命名和UCSC(Ceph诞生地)的吉祥物有关,这个吉祥物是"Sammy",一个香蕉色的蛞蝓,就是头足类中无壳的软体动物.这些有多触角的头足类动物, ...

  7. 容器编排技术 -- Kubernetes 重新配置活动集群中节点的 Kubelet

    容器编排技术 -- Kubernetes 重新配置活动集群中节点的 Kubelet 1 Before you begin 2 重新配置集群活动节点上的 Kubelet 2.1 基本工作流程概览 2.2 ...

  8. kubernetes kubelet参数

    全栈工程师开发手册 (作者:栾鹏) 架构系列文章 概要 kubelet 是运行在每个节点上的主要的"节点代理",每个节点都会启动kubelet进程,用来处理Master节点下发到本 ...

  9. pod 排错----Pod 一直处于 Pending 状态

    Pending 状态说明 Pod 还没有被调度到某个节点上,需要看下 Pod 事件进一步判断原因,比如: ... Events:Type Reason Age From Message---- --- ...

最新文章

  1. C4D+ PS打造城市场景 Create a Cityscape with Cinema 4D + Photoshop
  2. 常见荧光定量 PCR 检测方法比较
  3. 兰州大学第一届 飞马杯 体育课排队 二分 + 最大流 + 输出路径
  4. 【Codeforces #130 Div2】Solutions
  5. discuz数据从godaddy主机中导出的mysql数据乱码变问号???的解决方法
  6. 【POJ】2065 SETI
  7. python下载文件保存_从URL下载文件并将其保存在Python文件夹中
  8. 数据结构之内部排序算法总结笔记
  9. python保留sqrt_python:quot;因式分解quot;引出的知识盲点
  10. 【Java】位运算符:左移右移
  11. Unity 打包微信
  12. “四大神兽”拆机指北
  13. 年度案例大数据盘点之Spark篇
  14. 移动硬盘无法在ubuntu显示
  15. linux下 Apache 配置虚拟主机三种方式
  16. 电极电阻测量,防雷接地电极设计原理和测试方案
  17. 建设一个SaaS平台需要知道什么,做什么
  18. Spring boot 实战指南(二):Mybatis、动态绑定、多数据源、分页插件、Mybatis-Plus
  19. in_array 二维数组
  20. hbuilderx 使用总结

热门文章

  1. 微信域名防封,微信网址域名防封的几种方法
  2. 选择数据中心的位置,需要从这五大方面考虑
  3. 服务器如何 建立远程连接?
  4. 无处不数据的时代 三大运营商如何变现大数据价值?
  5. 用vuejs仿网易云音乐(实现听歌以及搜索功能)
  6. java后台报错cant found font [times New Roman] installed on the system
  7. 简单面试题,但是容易忘记
  8. Android 返回桌面的操作
  9. 2012意大利之行3:罗马的路和车_我是亲民_新浪博客
  10. mac搭建win10虚拟机并对磁盘分区