kubelet循环

image.png
从图中可以看到kubelet就是在一个循环中通过主动轮训或者事件通知的方式不断的监测pod,将pod调整到预期的状态。

  • pod的创建来源可以有多种,可以是api-server将一个pod调度到本节点,可以是一个本地的文件目录,也称作mirror pod或static pod(/etc/kubernetes/manifests)。
  • 如果pod配置了liveness,当探针检查失败时,会重启pod。
  • PLEG,如果pod中的container因为某些原因退出了,kubelet可以通过查询和对比新旧pod数据感知到pod的变化,并调整pod到预期状态。
  • 为了分离任务,抽象出了PodWorkers这一层,pod的状态由kubelet通过dispatchWork接口将任务分配到PodWorkers中去处理。

kubelet创建pod

image.png
当kubelet接受到新建pod的请求后,开始做一系列的处理,涉及到kubelet本身,podWorker,kubeGenericRuntimeManager等多个组件,最后调用CRI真正的去启动pod中的容器。这里要梳理清楚pod所需的资源是哪些组件负责的,如拉取镜像是由CRI完成的,sandbox相关的网络是由CRI调用CNI完成的,cgroup目录是由kubelet本身完成的等等。
其中SyncPod是pod状态同步中一个比较重要的函数,创建删除更新等都会调用到这个函数,为方便理解,放上代码中的注释,注释中的流程说明浅显易懂且清晰。

  1. pkg/kubelet/kuberuntime/kuberuntime_manager.go
  2. // SyncPod syncs the running pod into the desired pod by executing following steps:
  3. //
  4. // 1. Compute sandbox and container changes.
  5. // 2. Kill pod sandbox if necessary.
  6. // 3. Kill any containers that should not be running.
  7. // 4. Create sandbox if necessary.
  8. // 5. Create ephemeral containers.
  9. // 6. Create init containers.
  10. // 7. Create normal containers.
  11. func (m *kubeGenericRuntimeManager) SyncPod(pod *v1.Pod, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, backOff *flowcontrol.Backoff) (result kubecontainer.PodSyncResult) {
  12. }

PLEG

PLEG全称Pod lifecycle event generator,准确的翻译应该是Pod生命周期事件生成器。我把它叫做Pod生命周期管理,因为它是Pod的生命周期管理中的重要的一部分,是产生Pod变更事件的来源。
kubelet的pleg模块不断的检查Pod中的sandbox和container的状态变化,如果有变化,则产生事件,kubelet读取事件,并将pod状态调整到期望的状态。例如Pod中的container的1号进程因为内存超限触发oom导致容器退出,pleg通过对比新旧pod数据,生成一个事件,kubelet感知到容器退出就可以重启失败的容器。这里要注意区分被oom的进程是容器的1号进程还是容器内的普通进程,1号进程很重要,可以清理僵尸进程,可以实现容器内子进程的优雅退出等等,专门有一个tini项目来实现容器中的1号进程,新版本的docker中也增加了参数—init来启动专门的1号进程
检查的时间间隔g.relistPeriod是可以配置的,默认值是1s。

image.png

kubelet中的那些manager

kubelet中有很多的manager,这些manager根据名字就可以判断出它的作用,这些功能独立的manager相互协作,穿插在pod的生命周期中,实现了kubelet的完整功能。或者说podSpec中有很多的字段,这些manager就是处理这些podSpec中的字段的。例如statusManager负责缓存pod的状态并更新到apiserver,evictionManager负责pod的驱逐,imageManager负责gc,通过调用CRI的image接口删除不再使用的镜像等等。
了解了这些manager,在看kubelet的代码时,就可以快速的把握住主线,不会迷失在纷繁复杂的代码中。如果关注configmap在创建pod时如何生效,就可以重点看下configMapManager。
这些manager运行的套路基本都是一致的,先是通过包装的New()函数初始化一个Manager对象,在调用manager的Start或者Run方法开始做具体的工作。
image.png

通过记录这些入口函数,也可以很快速的找到具体功能的代码片段。如查看node的update更新节点状态,就可以查看syncNodeStatus函数。

  1. kl.imageManager.Start()
  2. go kl.volumeManager.Run(kl.sourcesReady, wait.NeverStop)
  3. kl.oomWatcher.Start(kl.nodeRef)
  4. kl.cadvisor.Start()
  5. kubeInformers.Start(wait.NeverStop)
  6. kl.containerLogManager.Start()
  7. kl.pleg.Start()
  8. kl.runtimeClassManager.Start(wait.NeverStop)
  9. kl.statusManager.Start()
  10. kl.containerManager.Start(node, kl.GetActivePods, kl.sourcesReady, kl.statusManager, kl.runtimeService)
  11. kl.evictionManager.Start(kl.StatsProvider, kl.GetActivePods, kl.podResourcesAreReclaimed, evictionMonitoringPeriod)
  12. go kl.pluginManager.Run(kl.sourcesReady, wait.NeverStop)
  13. go wait.Until(kl.syncNodeStatus, kl.nodeStatusUpdateFrequency, wait.NeverStop) -> defaultNodeStatusFuncs
  14. go kl.fastStatusUpdateOnce()
  15. go kl.nodeLeaseController.Run(wait.NeverStop)
  16. go wait.Until(kl.updateRuntimeUp, 5*time.Second, wait.NeverStop)
  17. go k.Run(podCfg.Updates()) -> syncLoop -> syncLoopIteration

podWorkers

podWokers对象可以看做是kubelet的pod数据结构与CRI接口之间的一个桥梁。如创建pod会调用到klet.syncPod。

  1. klet.podWorkers = newPodWorkers(
  2. klet.syncPod,
  3. klet.syncTerminatingPod,
  4. klet.syncTerminatedPod,
  5. kubeDeps.Recorder,
  6. klet.workQueue,
  7. klet.resyncInterval,
  8. backOffPeriod,
  9. klet.podCache,
  10. )

metrics

云原生组件一般都提供了metrics接口来获取服务的一些细节的状态,kubelet除了提供metrics可供prometheus采集外,还提供了stats接口来获取运行时信息,包括pod,container等。
访问10250端口 需要证书,10255端口 不需要证书
另外kubelet还开放了其他几个有意义的http接口

  • /stats/
  • /stats/summary
  • /stats/container
  • 127.0.0.1:10255/pods
  • /{podName}/{containerName}
  • /{namespace}/{podName}/{uid}/{containerName}
    相关代码入口如下: ```c func (s *Server) InstallDefaultHandlers(enableCAdvisorJSONEndpoints bool) { s.addMetricsBucketMatcher(“healthz”) healthz.InstallHandler(s.restfulCont, healthz.PingHealthz, healthz.LogHealthz, healthz.NamedCheck(“syncloop”, s.syncLoopHealthCheck), )

s.addMetricsBucketMatcher(“pods”) ws := new(restful.WebService) ws. Path(“/pods”). Produces(restful.MIME_JSON) ws.Route(ws.GET(“”). To(s.getPods). Operation(“getPods”)) s.restfulCont.Add(ws)

s.addMetricsBucketMatcher(“stats”) s.restfulCont.Add(stats.CreateHandlers(statsPath, s.host, s.resourceAnalyzer, enableCAdvisorJSONEndpoints))

s.addMetricsBucketMatcher(“metrics”) s.addMetricsBucketMatcher(“metrics/cadvisor”) s.addMetricsBucketMatcher(“metrics/probes”) s.addMetricsBucketMatcher(“metrics/resource/v1alpha1”) ```