Kubelet 是 kubernetes 工作节点上的一个代理组件,运行在每个节点上。




kubelet 默认链接docker kubelet配置文件_kubelet配置cni插件


Kubelet是工作节点上的主要服务,定期从kube-apiserver组件接收新的或修改的Pod规范,并确保Pod及其容器在期望规范下运行。同时该组件作为工作节点的监控组件,向kube-apiserver汇报主机的运行状况。

架构

Kubelet 的组件架构图,如下所示,Kubelet 由许多内部组件构成

  • Kubelet API,包括 10250 认证API、4194 端口的 cAdvisor API、10255 端口的只读 API 以及 10248 端口的健康检查 API
  • syncLoop:从 API 或者 manifest 目录接收 Pod 更新,发送到 podWorkers 处理,大量使用 channel 处理来处理异步请求
  • 辅助的 manager,如 Volume Manager 等,处理 syncLoop 以外的其他工作
  • CRI:遵循CRI规范,通过封装的两个服务(Remote Runtime Service 和 Remote Image Service)以CRI gRPC Client角色与高级容器运行时进行交互


kubelet 默认链接docker kubelet配置文件_垃圾回收_02


由于kubernetes 已经开始废弃docker,所以本文分析去掉了docker 部分。

下面我们介绍几个核心组件:

PLEG

PLEG,即Pod Lifecycle Event Generator。其维护着存储Pod 信息的cache,从运行时获取容器的信息,并根据前后两次信息对比,生成对应的PodLifecycleEvent,通过eventChannel发送到kubelet syncLoop进行消费,最终由kubelet syncPod完成Pod的同步,维护着用户的“期望”。


kubelet 默认链接docker kubelet配置文件_kubelet 默认链接docker_03


CAdvisor

集成在 Kubelet 中的容器监控工具,用于收集本节点和容器的监控信息。

oomWatcher

kubelet的oomwatcher从cadvisor监听事件,如果出现了system oom则记录一个event事件。 对于容器的oom状态,k8s使用docker的状态State.OOMKilled判断是否经历oom事件。

GCManager

垃圾回收是 kubelet 的一个有用功能,它将清理未使用的镜像和容器。 Kubelet 将每分钟对容器执行一次垃圾回收,每五分钟对镜像执行一次垃圾回收。

不建议使用外部垃圾收集工具,因为这些工具可能会删除原本期望存在的容器进而破坏 kubelet 的行为。

CPUManager

默认情况下,kubelet 使用 CFS 配额 来执行 Pod 的 CPU 约束。 当节点上运行了很多 CPU 密集的 Pod 时,工作负载可能会迁移到不同的 CPU 核, 这取决于调度时 Pod 是否被扼制,以及哪些 CPU 核是可用的。 许多工作负载对这种迁移不敏感,因此无需任何干预即可正常工作。

然而,有些工作负载的性能明显地受到 CPU 缓存亲和性以及调度延迟的影响。 对此,kubelet 提供了可选的 CPU 管理策略,来确定节点上的一些分配偏好。

CPU 管理策略通过 kubelet 参数 --cpu-manager-policy 来指定。支持两种策略:

  • none: 默认策略,表示现有的调度行为。
  • static: 允许为节点上具有某些资源特征的 pod 赋予增强的 CPU 亲和性和独占性。

CPU 管理器定期通过 CRI 写入资源更新,以保证内存中 CPU 分配与 cgroupfs 一致。 同步频率通过新增的 Kubelet 配置参数 --cpu-manager-reconcile-period 来设置。 如果不指定,默认与 --node-status-update-frequency 的周期相同。

static策略针对具有整数型 CPUrequestsGuaranteedPod ,它允许该类 Pod 中的容器访问节点上的独占 CPU 资源。这种独占性是使用cpuset cgroup 控制器来实现的。

该策略管理一个共享 CPU 资源池,最初,该资源池包含节点上所有的 CPU 资源。可用 的独占性 CPU 资源数量等于节点的 CPU 总量减去通过--kube-reserved--system-reserved参数保留的 CPU 。从1.17版本开始,CPU保留列表可以通过 kublet 的 '--reserved-cpus' 参数显式地设置。 通过 '--reserved-cpus' 指定的显式CPU列表优先于使用 '--kube-reserved' 和 '--system-reserved' 参数指定的保留CPU。 通过这些参数预留的 CPU 是以整数方式,按物理内 核 ID 升序从初始共享池获取的。 共享池是BestEffortBurstablepod 运行 的 CPU 集合。Guaranteedpod 中的容器,如果声明了非整数值的 CPUrequests,也将运行在共享池的 CPU 上。只有Guaranteedpod 中,指定了整数型 CPUrequests的容器,才会被分配独占 CPU 资源。

GuaranteedPod 调度到节点上时,如果其容器符合静态分配要求, 相应的 CPU 会被从共享池中移除,并放置到容器的 cpuset 中。 因为这些容器所使用的 CPU 受到调度域本身的限制,所以不需要使用 CFS 配额来进行 CPU 的绑定。 换言之,容器 cpuset 中的 CPU 数量与 Pod 规约中指定的整数型 CPUlimit相等。 这种静态分配增强了 CPU 亲和性,减少了 CPU 密集的工作负载在节流时引起的上下文切换。

ProberManager

ProberManager 实现对容器的健康检查。目前有三种 probe 探针:

  • liveness: 让Kubernetes知道你的应用程序是否健康,如果你的应用程序不健康,Kubernetes将删除Pod并启动一个新的替换它(与RestartPolicy有关)。Liveness 探测可以告诉 Kubernetes 什么时候通过重启容器实现自愈。
  • readiness: readiness与liveness原理相同,不过Readiness探针是告诉 Kubernetes 什么时候可以将容器加入到 Service 负载均衡中,对外提供服务。
  • startupProbe:1.16开始支持的新特性,检测慢启动容器的状态。

Kubelet 定期调用容器中的探针来诊断容器的健康状况。 包含如下三种实现方式:

  • ExecAction:在容器内部执行一个命令,如果该命令的退出状态码为 0,则表明容器健康;
  • TCPSocketAction:通过容器的 IP 地址和端口号执行 TCP 检查,如果端口能被访问,则表明容器健康;
  • HTTPGetAction:通过容器的 IP 地址和端口号及路径调用 HTTP GET 方法,如果响应的状态码大于等于 200 且小于 400,则认为容器状态健康。

StatusManager

StatusManager 的主要功能是将 pod 状态信息同步到 apiserver,statusManage 并不会主动监控 pod 的状态,而是提供接口供其他 manager 进行调用。比如 probeManager。probeManager 会定时去监控 pod 中容器的健康状况,一旦发现状态发生变化,就调用 statusManager 提供的方法更新 pod 的状态。

EvictionManager

EvictionManager 会监控资源的使用情况,并使用驱逐机制防止计算和存储资源耗尽。关于更加详细的驱逐内容,参见官方文档。

VolumeManager

volumeManager通过actualStateOfWorld和desiredStateOfWorld来表明当前的volume挂载状态和期望的volume挂载状态。然后由desiredStateOfWorldPopulator维护desireedStateOfWorld和podManager的一致性;由reconcile维护actualStateOfWorld和desiredStateOfWorld的一致性及磁盘volume挂载和actualStateOfWorld的一致性。通过这些机制,volumeManager完成了volume挂载生命周期的管理。

PluginManager

PluginManager 可以用将系统硬件资源发布到kubelet。供应商可以实现设备插件,由你手动部署或作为 DaemonSet 来部署,而不必定制 Kubernetes 本身的代码。目标设备包括 GPU、高性能 NIC、FPGA、 InfiniBand 适配器以及其他类似的、可能需要特定于供应商的初始化和设置的计算资源。

工作原理

如上面所说,Kubelet 的工作主要是围绕一个 SyncLoop 来展开,借助 go channel,各组件监听 loop 消费事件,或者往里面生产 pod 相关的事件,整个控制循环由事件驱动运行。可以用下图来表示:


kubelet 默认链接docker kubelet配置文件_kubelet配置cni插件_04


  1. 用户从http,静态文件以及APIServer对pod的修改通过PodConfigchannel传递到syncLoop;
  2. 另外一方面,PLEG会周期(默认1s)通过relist从CRI获取所有pod当前状态并且跟之前状态对比产生Pod的event发送到syncLoop;
  3. syncLoop的syncLoopIteration从各种chan中取出update的内容,一方面会通过podManger里更新pod状态,另一方面会通过dispatchWork将更新内容通过PodWoker更新pod状态,调用的是syncPod这个接口(由Kubelet.syncPod实现);
  4. 而syncPod这里通过podStatusChannel 更新状态到statusManager, 再patch Status到APIServer;
  5. syncPod一方面通过containerManager更新non-runtime的信息,例如QoS,Cgroup信息;另外一方面通过CRI更新pod的状态;

总结

Kubelet 作为Kubernetes的执行器,几乎Kubernetes支持的所有功能,都在Kubelet中有具体的实现方式。因而掌握kubelet至关重要。

以下4篇文章,推荐给大家,对理解kubelet有一定的帮助。

  1. 正确配置Kubelet可一定程度防止K8S集群雪崩
  2. 了解Kubernet中的“ PLEG is not healthy”问题
  3. kubectl 创建 Pod 背后到底发生了什么?
  4. 了解Kubelet核心执行框架