k8s

kubelet总结

背景

下面我将以这个思维导图来总结一下kubelet。
file

介绍

kubelet是node的守护神,维护了node上应用的生命周期,让node可以正常运行。

每个节点上都运行一个 kubelet 服务进程,默认监听 10250 端口。

  • 接收并执行 master 发来的指令;
  • 管理 Pod 及 Pod 中的容器;
  • 每个 kubelet 进程会在 API Server 上注册节点自身信息,定期向 master 节点汇报节点的资源使用情况,并通过 cAdvisor监控节点和容器的资源。

file

节点管理

节点管理主要是节点自注册和节点状态更新:

  • kubelet 可以通过设置启动参数 — register-node 来确定是否向 API Server 注册自己;
  • 如果 kubelet 没有选择自注册模式,则需要用户自己配置 Node 资源信息,同时需要告知 kubelet集群上的 API Server 的位置;
  • kubelet 在启动时通过 API Server 注册节点信息,并定时向 API Server 发送节点新消息,APIServer 在接收到新消息后,将信息写入 etcd。

Pod 管理

获取 Pod 清单方式:

  • 文件:启动参数 –config 指定的配置目录下的文件即静态pod。(默认 /etc/Kubernetes/manifests/)。该文件每20秒重新检查一次(可配置)。
    ps aux | grep kubelet
    cat /var/lib/kubelet/config.yaml

    file

  • HTTP endpoint (URL):启动参数–manifest-url 设置。每20 秒检查一次这个endpoint(可配置)。
  • API Server:通过 API Server 监听 etcd 目录,同步 Pod 清单。
  • HTTP Server:kubelet 侦听 HTTP 请求,并响应简单的 API 以提交新的 Pod 清单。

kubelet 架构

  • API:10250负责和客户端交互,10255负责只读,10248负责自身的探活。
    file
  • ProbeManager:livenessProbe,readnessProbe,startupProbe,由kubelet发起负责node上的pod的探活。
  • OOMWatcher:监听进程是否触发了OOM并上报给kubelet。
  • GPUManager:管理node上的GPU。
  • CAdvisor:内嵌于kubelet,基于cgroup获取node上运行的应用资源情况。
  • DiskSpaceManager:检测pod的磁盘空间大小。
  • StatusManager:管理node的状态。
  • EvictionManager:检测node资源使用情况,当到达一定水位时,它会按照既定策略把低优先级的pod驱逐掉。
  • Volume Manager:负责pod的存储。
  • Image GC:扫描node上不活跃的镜像,把这些镜像删除掉。
  • Container GC:清除Exited状态的容器。
  • ImageManager:负责镜像管理。
  • CertificateManager:kubelet是可以签证书的,负责证书管理。
  • syncLoop:watch api对象。
  • PodWorker:当syncLoop接收到pod变更通知,PodWorker就会去处理这些事件。比如看pod是否启动,如果没有就会把pod通过CRI启动。
  • CRI:容器运行时接口。可以通过kubelet的启动命令指定。
    • docker shim:基于docker,目前最新版已被k8s废弃。
    • remote container runtime:基于containerd或者cri-o。
      file

file

kubelet管理Pod的核心流程

  • 通过apiserevr监听pod的状态变化即 pod update或者add事件。
  • sycnLoop接收到事件后,会把事件存到UpdatePodOptions中。
  • 不同的worker都会从队列中获取pod变更事件的清单。
  • 针对每一个pod都会进行syncPod,然后会执行computePodActions,即对于这个pod需要执行什么行为。它会对比node上已经启动的容器进程,如果pod是新的,就会create,如果已经存在了,就会delete或者update。
  • 通过CRI启动或者删除pod。
  • PLEG:上报pod的状态信息。维护了一个本地的pod cache,定期的向CRI发起一个relist的操作来获取当前node上的正在运行的pod清单。最后再通过pod lifecycle events上报给apiserver。

file

注意

这里可以清晰的看到,如果runtime挂了,relist操作就会失败,pod状态无法上报,k8s就会认为这个node挂了,导致pod驱逐。

如果node上的容器进程过多,比如exited状态容器过多,relist就会一直遍历这些容器,导致耗时过长,没有在规定的时间内返回pod状态信息,PLEG就会超时,导致node状态变为Unknown,pod驱逐。

pod启动流程

我环境用的是containerd,这里也以containerd为例介绍pod的启动流程。

  • 用户发送创建pod请求到apiserver。
  • apiserver收到请求后会把对象存储到etcd中。存储完成后会返回给apiserver。
  • scheduler 是watch apiserver的,watch到这个pod创建事件,找到一个合适的node完成调度,绑定pod。
  • apiserver再把pod的信息存储到etcd中。
  • kubelet watch到node上绑定的pod,首先会去启动SandboxContainer。
  • containerd调用cni的插件去创建pod,即配置网络。
  • cni插件把pod的ip返回给containerd,再返回给kubelet。
  • kubelet调用containerd拉取镜像,创建主容器,启动主容器。
  • kubelet上报pod状态给apiserver。
  • apiserver再把pod状态存储到etcd中。

file

SandboxContainer

kubelet启动容器的时候,启动的是多个容器进程。

比如这里的nginx pod,不仅有一个nginx主容器,还有一个pause容器,这个pause容器,在k8s中就叫做SandboxContainer。pause是一个永远sleep,不会退出,不消耗任何资源的进程。

nerdctl -n k8s.io ps | grep nginx | grep -v ingress

file

为什么要有SandboxContainer

容器技术依靠的是namespace,cgroup,rootfs。容器启动后可以和某个网络namespace关联,就可以有独立的网络配置。容器本身进程可能不稳定,如果每一次容器退出都需要重新配置网络,就会对系统产生一定的压力,效率也不高。SandboxContainer就可以提供一个底座,让容器退出也不会更改其网络存储等配置。

某些容器进程启动是需要网络就绪的,比如java进程,或者某些需要获取第三方token的进程。这样就需要一个额外的容器来提前启动网络。把主容器的网络namespace挂载在这个sandbox即可。

kubelet 启动 Pod 的流程

这里是更详细的pod启动流程图。

  • 首先会做一个准入:看pod的资源需求是否满足node上的资源状况。
  • 检查网络插件状态:如果cni挂了,pod是起不来的。
  • 配置pod的cgroup。
  • 创建pod数据目录。
  • 等待pod存储就绪,这里就通过CSI来attach and mount pod的存储目录。
  • syncPod:计算sandbox和容器的变化,如果发生了变化,就需要重新启动容器了。即上文中的ComputePodActions。
  • 如果是创建pod:首先会生成sandbox的配置文件,然后创建数据目录,然后再创建sandbox。
  • sandbox通过grpc接口调用CRI创建pod,过程中再调用CNI创建网络。
  • 其他流程都是一致的。
    file
分类: k8s
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x