版本:v1.23
别人的阅读笔记:https://github.com/gosoon/source-code-reading-notes
app.NewKubeletCommand
app.loadConfigFile #加载配置文件
app.Run
app.run
app.UnsecuredDependencies #初始化相关依赖,这些依赖是kubelet需要的,比如TLS/mount/subpath/hostutil/dockeroptions等
app.InitializeTLS #初始化tls选项
mount.New #实现mount功能,可以实现不同的mount类来为mount动作提供不同的行为,默认的mount动作是linux平台的mount动作,这里就是kubelet只能运行在linux上的原因之一
subpath.New #对mount的封装
hostutil.NewHostUtil #linux平台的hostutil
exec.New #用来运行插件的执行器,默认是linux平台
app.ProbeVolumePlugins #探测有哪些存储插件,会返回一系列的插件对象
app.GetDynamicPluginProber #volumn插件的探针,用来探测volumn插件是否正常
nodeutil.GetHostname
app.getNodeName
#1:创建clientset和认证
clientset.NewForConfig #通用clientset
v1.NewForConfig #为事件准备一个单独的clientset
clientset.NewForConfig #为healthz准备一个client
app.BuildAuth #构建认证器(authenticator)和授权器(authorizer)
app.runAuthenticatorCAReload
#2:获取cgroup
cm.NodeAllocatableRoot #获取节点可分配资源的根cgroup,确保容器可以获得足够的资源,资源指cpu、memory,下略
cm.GetKubeletContainer #获取kubelet将要使用的cgroup,可以使用这个cgroup来确保系统繁忙的时候kubelet也能得到足够的cpu,因为kublet也是一个进程
cm.GetRuntimeContainer #获取containerRuntime使用的cgroup ,可以用这个cgroup来调整containerRuntime进程使用的资源,因为containerRuntime也是一个进程
#3:创建metrics服务
cadvisor.NewImageFsInfoProvider
cadvisor.New
app.makeEventRecorder #事件记录器,供排查bug、审计等
#4:创建containerManager,这是kubelet中的一个重要组件,用于管理容器的资源限制和调度
cadvisor.cadvisorClient.MachineInfo #获取节点资源
app.getReservedCPUs #--reserved-cpus参数不为空,表明要保留一些cpu给系统,也就是这部分cpu不能用于kubelet
eviction.ParseThresholdConfig #解析evictionManager资源阈值,evictionManger用这些值来决定是否驱逐某些pod
cm.ParseQOSReserved #解析-qos-reserve-requests参数
utilfeature.DefaultFeatureGate.Enabled(features.CPUManager) #cpuManager用来管理cpu分配和调度,比如默认的是CFS调度,但是pod可能有cpu亲和性等
cm.NewContainerManager #创建ContainerMangaer
#5:run kubelete之前初始化containerRuntime service
kubelet.PreInitRuntimeService
kubelet.runDockershim #会判断是docker还是cri,如果是docker,那么kublet使用cri的时候,cri还需要通过dockershim才能管理容器
remote.NewRemoteRuntimeService #启动cri服务
remote.NewRemoteImageService #启动镜像服务
cadvisor.UsingLegacyCadvisorStats #判断是否需要启动cadvisor来监听
#6:启动kubelet
app.RunKubelet #运行kublet
nodeutil.GetHostname
app.getNodeName
app.makeEventRecorder
netutils.ParseIPSloppy #解析--node-ip参数
capabilities.Initialize #设置容器的默认权限
credentialprovider.SetPreferredDockercfgPath #设置docker配置文件的路径
app.createAndInitKubelet
kubelet.NewMainKubelet #创建kubelet
kubelet.makePodSourceConfig #创建podconfig,会创建一个chan,这个chan是syncLoop中syncLoopIteration监听的数据源之一
config.NewPodConfig #创建podConfig,内部有一个podStorage,podStorage对象含有一个chan和map,这个chan会收到来自多个源发来的podupdate对象,map保存chan收到的对象
#podUpdate{op,pods,source},op记录操作(增删改),pods记录变动的pod信息,source记录来源(file/http/apiserver)
#file:即static-pod所在目录
config.PodConfig.Channel #创建一个channel,这个channel内含有一个chan,channel负责接收发送到这个chan的信息并把处理后的结果发往内部保存的一个updatesChan
#这个updatesChan就是syncLoop中监听的configChan,因为这个对象叫podConfig,所以对应的chan在syncLoop里就叫configChan
#一个channel对应一个chan,所有channel收到的对象经过处理后最终都会统一发往configChan,就是上面podConfig里的那个chan
sets.String.Insert #保存source名字到podConfig内部的数组
config.Mux.Channel #创建一个新的chan,然后开一个线程监听这个新的chan,然后对收到的事件进行处理和包装后发往内部保存的updatesChan(即syncLoop里的configChan)
go config.Mux.listen 一个死循环:监听新chan->阻塞->收到事件->处理和包装->发送事件到updatesChan->继续监听新chan......如此循环
config.podStorage.Merge
config.podStorage.merge #监听新创建的chan并把事件拆分成adds/updates/deletes/removes/reconciles podUpdate对象集合
updatesChan <- adds/updates/deletes/removes/reconciles 把上面解析出的podUpdate对象发送到updatesChan
config.NewSourceFile #创建一个监听static-pod文件所在目录的监听器,然后把收到的事件发往我们刚才通过channel函数创建的chan
config.newSourceFile #把刚创建的chan和一个文件路径保存到一个sourceFile对象内部,路径由--pod-manifest-path参数指定,默认为/etc/kubernetes/manifests
cofig.sourceFile.Run #开一个线程去监听目录变化事件,然后把事件发往新创建的chan。除了监听事件外还会定时去刷新一遍目录看是否有变更
config.PodConfig.Channel #创建一个新chan
config.NewSourceURL #创建一个http服务器,定时去请求指定url来获取pod变动信息并发送到刚创建的chan
config.PodConfig.Channel #创建一个新chan
config.NewSourceApiserver #通过listAndWatch来监听来自apiserver的pods变化并发送到updatesChan
SharedInformerFactory.Core().V1().Nodes() #监听node
kubecontainer.GCPolicy{} #这是一个对象,包含了容器gc设置
v1.DaemonEndpoint{Port: kubeCfg.Port} #这是一个对象,包含了kubelet端口,kubelet是以守护进程的形式运行
images.ImageGCPolicy{} #这是一个对象,包含了镜像gc设置
eviction.ParseThresholdConfig #解析eviction配置参数
eviction.Config{} #这是一个eviction配置对象
SharedInformerFactory.Core().V1().Services() #监听service
oomwatcher.NewWatcher #创建一个oom事件监听器
oomparser.New
kmsgparser.NewParser #解析/dev/kmsg文件,这个文件对应的是内核日志
netutils.ParseIPSloppy #从配置文件获取集群dnsip地址
kubelet.Kubelet{} #这是一个kubelet对象
cloudresource.NewSyncManager #如果是云厂商提供服务,那么SyncManager负责定时收集云厂商的资源信息(这里仅仅是同步云节点地址信息)
flowcontrol.NewBackOff #创建一个指数退避对象,用来处理image拉取失败时再次拉取的间隔
results.NewManager #创建livenessProbMangaer
results.NewManager #创建readinessProbMangaer
results.NewManager #创建startupProbMangaer
container.NewCache #创建podcache
pod.NewBasicMirrorClient #创建mirrorClient用来同步mirrorpod和internalpod
pod.NewBasicPodManager #创建podManager
status.NewManager #创建statusMangaer,用来更新apiserver上中pod的status字段
status.NewResourceAnalyzer #创建资源分析器,统计资源使用情况
status.newFsResourceAnalyzer #这里仅统计文件系统资源使用情况
status.NewSummaryProvider #提供kubelet的统计信息
runtimeclass.NewManager #创建runtimeclassManager,内部会启动一个informer监听apiserver的runtimeclass资源
#原理:可以在pod.spec.runtimeClassName指定pod的runtimeClass,当kubelet收到一个pod时,在syncPod函数内会检查该pod的runtimeClass字段
#对应的资源是否已经在集群中声明了,如果没有,则拒绝,然后会把runtimeClassName发给cri(当然,会有一个准入控制插件来判断该node是否支持该runtimeClass,
#如果不支持,那么准入插件就会拒绝该pod)
logs.NewContainerLogManager #创建日志管理器
kubelet.NewReasonCache #创建cache,缓存container failed原因
queue.NewBasicWorkQueue #创建工作队列
kubelet.newPodWorkers #创建podworker,处理pod的生命周期比如创建删除
kuberuntime.NewKubeGenericRuntimeManager #创建containerRuntimeManager,负责管理容器
credentialprovider.NewDockerKeyring #创建image拉取凭证
images.NewImageManager #用来拉取image,如果设置了qps,那么会限制拉取速率,根据配置决定是并发拉取还是串行拉取
lifecycle.NewHandlerRunner #容器lifecycle hook,支持exec钩子/httpGet钩子
kuberuntime.newContainerGC #容器gc
kubecontainer.NewRuntimeCache #创建了一个pod cache,对于每一个pod信息,都会用一个时间戳来表示pod最近一次更新的时间
stats.NewHostStatsProvider #用来查看pod在主机上的文件系统使用情况
stats.NewCadvisorStatsProvider #创建一个provider,来提供node和container的信息
pleg.NewGenericPLEG #创建pleg
kubelet.newRuntimeState #创建一个state记录kublet状态
runtimeState.addHealthCheck #添加pleg健康检查
kubelet.updatePodCIDR #更新pod cidr
kubecontainer.NewContainerGC #创建containerGC,实际就是前面创建runtimeManager时创建的哪个containergc
kubelet.newPodContainerDeletor #创建container删除器,就是一个线程不断从一个chan读取要删除的pod,然后删除,另一个线程把要删除的pod信息写入这个chan
images.NewImageGCManager #创建imageGC
kubeletcertificate.NewKubeletServerCertificateManage #创建一个用于 kubelet 的证书管理器,用于检索服务器证书,或者返回一个错误
prober.NewManager #创建一个探针管理器,用来管理前面创建的liveness/rediness/startup探针
token.NewManager #创建一个管理pod serviceAccount的token管理器
kubelet.NewInitializedVolumePluginMgr #创建一个volumn插件管理器,可以用来管理多种volumn插件,如emptydir/hostpath/nfs/glusterfs/aws/gce等
SharedInformerFactory.Storage().V1().CSIDrivers() #监听api的csidrivers资源,同runtimeclassManager,都是判断pod的csi字段是不是有效地,如果有效,就接受,否则就拒绝
volumn.VolumePluginMgr.InitPlugins #初始化所有存储插件
flexvolumn.flexVolumeProber.Init #创建plugin对应的目录,并创建一个watcher监视这个目录的增删改
flexvolumn.flexVolumeProber.createPluginDir #如果不存在则创建volumnplugin可执行文件存放的目录,默认路径为/usr/lib/kubernetes/kubelet-plugins/volumn/exec
flexvolumn.flexVolumeProber.initWatcher #初始化watcher
volume.VolumePlugin.Init #调用对应插件对应的init函数来初始化volume插件,比如ceph插件就是简单的把init函数参数保存到自己内部,插件实现类似调度器,实现指定接口即可
kubelet.Kubectl.getPluginsRegistrationDir #获取插件根目录,插件根目录默认为/var/lib/kubelet/plugin_registry
pluginmanager.NewPluginManager #创建一个插件管理器,管理所有类型的插件(校验插件、注册插件、删除插件),比如csi
volumemanager.NewVolumeManager #用来管理volumn的,前面的volumnPluginMgr是用来管理volume插件的,这个地方还不太懂
reconciler.NewReconciler #创建一个reconclier,用来驱使volume的实际状态和volume的期望状态一致
flowcontrol.NewBackOff #创建一个backoff定时器,用于控制容器失败以后的重启间隔
eviction.NewManager #创建evictionMangaer,定时驱逐pod
lifecycle.PodAdmitHandlers.AddPodAdmitHandler(evictionManager) #添加准入处理器,如果一个pod加入以后会超过阈值,那么就拒绝该pod
lifecycle.PodAdmitHandlers.AddPodAdmitHandler(sysctlsAllowlist) #添加准入控制器,sysctl表示系统调用白名单,如果一个pod的某些系统调用不在允许的名单内就拒绝该pod
kubelet.newActiveDeadlineHandler #添加handler,用来处理一个pod是否超过了他的截止期(超过截止期的pod可以算作死亡)
kubelet.Kubelet.AddPodSyncLoopHandler #把activeDeadlineHandler添加到sync loop中,调用ShouldSync来判断pod是否需要同步
kubelet.Kubelet.AddPodSyncHandler #把activeDeadlineHandler添加到sync loop中,调用shouldEvict来判断pod是否需要驱逐
cm.containerManager.GetAllocateResourcesPodAdmitHandler #获取资源准入插件,在批准pod之前预分配资源,如果分配失败(比如资源不足)就拒绝该pod
lifecycle.PodAdmitHandlers.AddPodAdmitHandler #添加刚才的资源准入handler
preemption.NewCriticalPodAdmissionHandler #创建抢占准入handler,如果一个pod是因为资源不足而被拒绝,那么这个抢占handler尝试抢占一批pod来释放资源
lifecycle.NewPredicateAdmitHandler #创建谓词准入控制。不大懂
lifecycle.NewAppArmorAdmitHandler #创建准入控制,判断一个具有armor配置文件(linux的一种安全配置文件)的pod是否允许运行
lifecycle.NewNoNewPrivsAdmitHandler #创建准入控制,检查Pod中的容器是否需要在没有新权限的情况下运行。如果不需要,那么该 Pod 将被接受
lifecycle.NewProcMountAdmitHandler #创建准入控制,执行ProcMount的验证。ProcMount是Linux 中的一种安全特性,用于指定挂载进程的挂载选项
lease.NewController #创建node lease资源,通过heartbeat来定时更新leases资源,来告知apiserver本node还是ready的
nodeshutdown.NewManager #创建manager,在节点关闭的时候正确停止所有container
kubelet.Kubelet.defaultNodeStatusFuncs #获取一系列设置节点状态的函数
kubelet.Kubelet.BirthCry #发送kubelet正在启动事件到一个chan
kubelet.Kubelet.StartGarbageCollection #启动垃圾收集
go container.realContainerGC.GarbageCollect #开一个go route,定时启动GarbageCollect来移除所有死亡的容器
kuberuntime.containerGC.GarbageCollect
kuberuntime.containerGC.evictContainers #移除可驱逐的容器,一组具有相同垃圾回收条件的容器会被组织成一个evictUnit
kuberuntime.containerGC.evictableContainers #如果一个容器状态不为running且该容器存在时间超过了一个阈值,那么该容器就是可删除的,是可删除,不一定能够删除,因为还要看pod
kubelet.podWorkers.ShouldPodContentBeRemoved #如果一个容器对应的pod的状态为evicted/deleted/terminated,那么该容器就可以删除,反之该容器就不能删除
kuberuntime.containerGC.removeOldestN #移除最老的n个容器
kuberuntime.kubeGenericRuntimeManager.killContainer #如果容器状态为未知,那么就先尝试kill该容器
cm.internalContainerLifecycleImpl.PreStopContainer
kuberuntime.kubeGenericRuntimeManager.executePreStopHook #调用用户自定义的钩子函数,kubelet支持preStop和postStart两种用户可自定义的钩子
cri.ContainerManager.StopContainer #调用cri停止该容器
kuberuntime.kubeGenericRuntimeManager.removeContainer
cm.internalContainerLifecycleImpl.PostStopContainer #调用相应的容器钩子函数,目前是topologyManager.RemoveContainer即成功topology的podmap中移除该pod
kuberuntime.kubeGenericRuntimeManager.removeContainerLog #删除容器日志
cri.ContainerManager.RemoveContainer #调用容器运行时删除容器
kuberuntime.containerGC.evictSandboxes #移除没有容器的沙箱
kubelet.podWorkers.ShouldPodContentBeRemoved
kuberuntime.containerGC.removeOldestNSandboxes
kuberuntime.containerGC.removeSandbox #移除n个不活跃的沙箱
cri.PodManager.StopPodSandbox #先停止沙箱
cri.PodManager.RemovePodSandbox #再删除沙箱
kuberuntime.containerGC.evictPodLogsDirectories #移除沙箱日志目录
images.realImageGCManager.GarbageCollect #镜像回收线程
rlimit.SetNumFiles #设置允许打开的最大文件数
app.startKubelet #运行kubelet
go kubelet.Kubelet.Run
http.FileServer #启动日志服务,开启一个http日志服务,以便可以通过http查看日志
kubelet.Kubelet.SyncManager.Run #cloudResourceSyncManager.Run,就是来同步云厂商资源状态的(这里仅仅是同步云厂商节点地址)
kubelet.Kubelet.SyncManager.syncNodeAddresses
kubelet.Kubelet.initializeModules
kubelet.Kubelet.setupDataDirs #设置rootdir/podsdir/plugindir/podsresourcedir,其中默认的root路径为/var/lib/kubelet
image.realImageGCManager.Start #启动image gc ,两个操作:1:定时更新image时间戳;2:定时更新image缓存(因为image可能被其他人删了,所以需要定时同步)
go image.realImageGCManager.detectImages #死循环,定时更新时间戳并返回正在使用的image
go {
kuberuntime.kubeGenericRuntimeManager.ListImages #从runtimeContainer重新获取最新的image信息快照
image.imageCache.set #更新image缓存
}
certificate.manager.Start #启动证书管理器,就是轮换证书,当证书过期时,可以自动生成新的密钥,并从 Kubernetes API 申请新的证书。
oom.realWatcher.Start #启动oom监视器
go oomparser.OomParser.StreamOoms #启动一个线程去
kmsgparser.parser.Parse #从/dev/kmsg获取日志并写到一个chan中
oomparser.checkIfStartOfOomMessages #检查一行日志是不是包含"invoked oom-killer:",如果是的,那么就认为是触发了oom,然后封装成一个对象发往指定chan
event.recorderImpl.Eventf #发送oom 事件到指定chan
stats.resourceAnalyzer.Start #启动文件系统资源分析器
stats.fsResourceAnalyzer.Start
stats.fsResourceAnalyzer.updateCachedPodVolumeStats #统计pod volume的信息
stats.volumeStatCalculator.calcAndStoreStats #计算volume的最新信息
volumeManager.volumeManager.Run #启动volumn管理器
go volume.VolumePluginMgr.Run #监听apiserver csi资源,当处理一个pod的时候会检查volume字段指定的csi类型apiserver是否支持
desiredStateOfWorldPopulator.Run #desiredStateWorld(dsw)存放pod的卷的期望状态,actualStateWorld(asw)表示pod的卷的实际状态,
#是否同步就是检测dsw中的状态是否等于asw的状态
#volumeManager会不断从podManager中获取pod信息然后从中提取volume的期望状态并更新到dsw中
#在syncLoop中podworker只是不断检测pod的卷状态是否同步,即podWorkder不处理卷的增删,卷由volumeManager负责管理和操作
desiredStateOfWorldPopulator.findAndAddNewPods #遍历podManager,更新获取所有非terminated状态的pod的volume信息到dsw
desiredStateOfWorldPopulator.findAndRemoveDeletedPods #同上,从dws中删除不存在的pod的volume信息
reconciler.reconciler.Run #同步卷使得pod的dsw=asw,比如一个卷没有挂载,那么就重新挂载;如果一个卷大小有调整,那么就调整卷大小(这一块不大清楚)
go reconciler.reconciler.reconciliationLoopFunc
reconciler.reconciler.reconcile #这里完成卷同步操作,这里是直接读取asw
reconciler.reconciler.unmountVolumes #从pod上unmount卷
reconciler.reconciler.mountAttachVolumes #mount卷到pod上
reconciler.reconciler.unmountDetachDevices #对应的设备unmount或者detach
reconciler.reconciler.processReconstructedVolumes #处理重建的卷
reconciler.reconciler.sync #通过扫描所有pod更新asw到最新状态即reconcile操作中只是读取asw,这里更新asw
go kubelet.Kubelet.syncNodeStatus #同步node状态到master上
kubelet.Kubelet.updateNodeStatus
kubelet.Kubelet.tryUpdateNodeStatus #通过clientgo更新apiserver上node的状态
kubelet.Kubelet.defaultNodeStatusFuncs #根据实际情况设置节点状态
volumeManager) MarkVolumesAsReportedInUse
nodeutil.PatchNodeStatus #更新master节点上的节点状态
go leases.Controller.Run #定时更新node对应的lease信息以表明node还是正常的
go kubelet.Kubelet.updateRuntimeUp #一个死循环,每隔5s检查一次containerRuntime的状态,如果有错则设置runtimeErrors字段
kubeRuntime.kubeGenericRuntimeManager.Status #检查容器运行时状态
kubelet.Kubelet.initializeRuntimeDependentModules #当containerRuntime启动以后,初始化相关模块,这个初始化操作只会进行一次
cadvisor.cadvisorClient.Start #启动cadvisor,就是监视容器
cm.containerManagerImpl.Start #启动containerMangaer,这个主要是资源分配,即cpu/memory/磁盘/cgroup的设置
cm.buildContainerMapFromRuntime #构建map[containerId]struct{sandBoxId,podId}
cpumanager.manager.Start #cpumangaer就是根据pod的resource字段来分配多少个cpu给这个pod
state.NewCheckpointState #从文件读取cpu的分配状态即checkpoint,默认文件为:/var/lib/kubelet/cpu_manager_state
cpumanager.Policy.Start #这是一个接口函数,policy有none和static,node表示默认策略,start什么也不做,而static的start则会校验读取的checkpoint的cpu分配状态是否有效
cpumanager.Policy.GetAllocatableCPUs #返回可用的cpuset,none策略则是默认返回所有cpu,static策略则是返回部分cpu集合(因为要除去保留的)
go cpumanager.manager.reconcileState #检查容器的状态,并根据状态来分配cpu确保实际cpu分配和预期相同
state.Reader.GetCPUSetOrDefault #获取容器默认的cpu集合
if !cpuset.CpuSet.Equals #如果默认的和预期的不相同就更新
cpumanager.manager.updateContainerCPUSet #更新容器对应的cpuset
cpumanager.runtimerServer.UpdateContainerResources #调用runtimeService来更新container的配置文件即通过修改配置文件即可修改container的cpu配置
state.Reader.SetCPUSet #更新状态
memorymanager.manager.Start #和cpumanager差不多的操作,只不过对应的文件为/var/lib/kubelet/memory_manager_state以及没有reconcile操作
state.NewCheckpointState
memorymanager.Policy.Start
memorymanager.manager.GetAllocatableMemory
cadvisor.cadvisorClient.RootFsInfo #获取根文件系统
cadvisor.EphemeralStorageCapacityFromFsInfo #获取根文件系统对应的磁盘存储容量
cm.containerManagerImpl.validateNodeAllocatable #校验配置文件和node实际可分配的资源数是否有冲突(因为node可能保留了许多资源导致实际的不够)
cm.containerManagerImpl.setupNode #主要是设置节点对应的cgroup(可以通过参数--cgroup-root配置)以及oom_score(分数越低,容器越容易oom)
devicemanager.ManagerImpl.Start #开一个server监听/var/lib/kubelet/device-plugins/kubelet.sock unix套接字
#device-plugins是k8s提供的资源设备插件框架,在这个目录下注册了某个资源设备插件,那么就可以在pod的resouce字段里设置该资源
eviction.managerImpl.Start #启动evictionManager
go eviction.managerImpl.synchronize #就是一个死循环,1:定时更新某些指标到chan;2:如果超过了阈值,达到了驱逐条件,就开启驱逐,阈值是通过signal传过来的即事件触发
eviction.thresholdsMet #确定哪些指标达到了阈值,硬阈值(达到阈值即触发驱逐)
eviction.thresholdsMetGracePeriod #确定哪些指标达到了软阈值(即达到阈值且持续了一段时间才触发驱逐)
eviction.managerImpl.localStorageEviction #先尝试驱逐因本地容量超过阈值导致的驱逐
eviction.managerImpl.emptyDirLimitEviction #驱逐emptydir超阈值的pod
eviction.managerImpl.evictPod #驱逐一个pod
kubelet.killPodNow #封装一个killpod操作,然后调用podworker去执行对应的操作
kubelet.PodWorker.UpdatePod #内部会异步调用runtimeservice去异步驱逐
eviction.managerImpl.podEphemeralStorageLimitEviction #驱逐超过临时存储容量限制的pod
eviction.managerImpl.evictPod
eviction.managerImpl.containerEphemeralStorageLimitEviction #驱逐pod内有某些容器超过临时存储容量限制的pod
eviction.managerImpl.evictPod
eviction.managerImpl.reclaimNodeLevelResources #尝试回收节点级别的资源
rank #evictionapi.Signalxxx系列函数,用来给pod排序
eviction.managerImpl.evictPod #按前面排好的顺序驱逐pod,如果是关键pod就跳过,直到成功驱逐一个pod即这个地方每次只驱逐一个pod
eviction.waitForPodsCleanup #等待本次驱逐的pod完成最后的清理工作即检测pod节点级资源是否已经回收了下一次
pluginManager.pluginManager.Run #启动pluginManger管理插件的增删改,就是开一个watcher监视文件目录的改动,当目录内容变化的时候及时register和unregister插件
pluginwatcher.Watcher.Start #启动一个fswatcher,监视目录的改动,目录:/var/lib/kubelet/plugin_registry
reconciler.reconciler.Run #同步状态,就是register和unregister插件,默认有csiplugin和deviceplugin,而cpu/memory则是由cpumanager/memorymanager去管理
logs.containerLogManager.Run #启动日志管理器
nodeshutdown.managerImpl.Start #启动节点关闭管理器
kubelet.Kubelet.initNetworkUtil #初始化iptables
status.manager.Start #启动statusManager,就是一个死循环,然后死循环里一个select,不断从指定chan接收podstatus,然后不断更新apiserver上的pod信息
status.manager.syncPod #更新单个pod信息
status.manager.needsUpdate #判断收到的podstatus是不是最新的,是否需要更新
kubeClient.CoreV1().Pods().Get #获取apiserver上pod的信息
status.manager.mergePodStatus #合并收到的podstatus和查到的podstatus
statusutil.PatchPodStatus #更新apiserver上的podstatus
status.manager.canBeDeleted #看pod能否删除
kubeClient.CoreV1().Pods().Delete #删除pod,不过会设置一个graceperiod,并不是立即删除
status.manager.deletePodStatus #从本地缓存podstatus
status.mangaer.syncBatch #更新一批pod的信息
runtimeClass.Manager.Start #启动runtimeClass,实际就是启动informer监听apiserver runtimeclass的变化
pleg.GenericPLEG.Start #启动pleg
go pleg.GenericPLEG.relist #从apiserver获取podlist,从containerRuntime获取podlist,比对,然后发送事件,默认两次relist操作之前间隔1s
pleg.GenericPLEG.getRelistTime #获取上一次relist开始的时间
kuberuntime.kubeGenericRuntimeManager.GetPods #调用runtimeservice获取所有pod信息
pleg.GenericPLEG.updateRelistTime #reslist设置为本次更新开始的时间
pleg.podRecords.setCurrent #更新pleg缓存的pod的信息
pleg.getContainersFromPods #获取所有container
pleg.computeEvents #根据container的状态生成事件对象,pleg状态有created/running/exited/unknow/non existed(如果获取不到pod内container的信息,那么状态就是nonexisted)
pleg.updateEvents #把event事件对象追加到一个临时的map里
pleg.GenericPLEG.updateCache #更新缓存,pleg的cache对象是外部kubelet对象的podcache的一个引用,所以这里实际就是更新kubelet的缓存,本次更新会保存更新失败的pod的信息
kuberuntime.kubeGenericRuntimeManager.GetPodStatus #通过runtimeserver实时获取pod最新状态,这里不是使用前面已经获取的pod信息
container.cache.Set #更新kubelet pod信息缓存
pleg.podRecords.update #podRecord是pleg自身的缓存,不是外部传进来的
pleg.podRecords.updateInternal #一个podRecored包含两个对象{oldPodInfo,currentPodInfo},update操作就是oldPodInfo=currentPodInfo,currentPodInfo=nil
eventChannel <- events #发送事件到syncloop,在syncloop调用的syncloopIteration函数中会有一个select,pleg的eventChannel是该select监听的事件源之一
pleg.GenericPLEG.updateCache #更新上一次更新过程中更新失败的pod信息,即再次尝试通过runtimeservice获取pod信息,再次失败的则会继续留到下一次relist操作再次进新尝试
container.cache.UpdateTime #当执行完本次所有更新操作之后,记录本次cache更新完成的时间
kubelet.Kubelet.syncLoop #一个死循环,死循环内一个select,这个select有多个数据源,每次迭代就是监听是否有事件到来,如果有则运行,否则阻塞
kubelet.runtimeState.runtimeErrors #一方面是前面有一个updateRuntimeUp会定时检查是否有runtimeError,一方面是会调用pleg.healthy,健康检查函数有且只有一个plegcheck
#如果报错,则睡眠一段随机时间然后再尝试
pleg.GenericPLEG.Watch #获取pleg的chan
atomic.Value.Store #记录本次同步操作开始的时间,后面还会记录一个检查完成的时间,这个时间在/healthz服务中会用到
kubelet.Kubelet.syncLoopIteration #就是一个大的select,监听多个chan,然后哪个chan有数据就读取哪个chan并进行对应处理,
#configChan: 来自于file/http/apiserver的事件
#syncTicker: 定时器,默认每1s触发一次同步操作(如果指定时间内其他数据源没有事件到来就会触发此事件)
#housekeepingTicker: 定时器,默认每2s触发一次清理工作
#pleg: pleg发来的事件(即relist操作中发送的事件)
#readinessManager.Updates: 就绪探针触发的事件
#startupManager.Updates: 启动探针触发的事件
#livenessManager.Updates: 存活探针触发的事件
case <-configChan: #来自file/http/apiserver的事件,case下还有一个case来分别处理Update/Remove/Reconcile/Delete等事件,这里仅以add为例,略去了case
#remove是立即删除,delete不是即有一个graceperiod
kubelet.Kubelet.HandlePodAddition #处理来pod添加事件,不同事件对应的函数名为HandlePodXXXX
sort.Sort #每个add事件可能包含多个新增的pod,所以先按时间顺序排个序
pod.PodManager.Add #把pod对象添加到podManager中
if types.IsMirrorPod #检查pod的annotation中是否有kubernetes.io/config.mirror这个字段,如果有,就说明是mirrorpod,反之是普通pod
kubelet.Kubelet.handleMirrorPod #mirror pod和普通pod的处理不同,apiserver上只有mirrorpod,没有staticpod,所以为了方便管理,
#kubelet会在apiserver上创建一个和staticpod一一对应的mirror pod,我们通过kubectl操作mirror pod就是操作static pod
#只不过mirror pod的处理不同,mirrorpod的add/delete/remove/update事件都会当做一个update事件来处理
#所以我们是无法通过apiserver来删除静态pod的,因为删除操作会被当做update操作,顶多会被转换成重启操作
#如果一个pod的annotation字段含有 kubernetes.io/config.mirror字段,那么该pod就是一个mirror pod
else
kubelet.podWorkers.IsPodTerminationRequested #检查pod是否被kubelet的其他部分请求终止(即可能存在其他进程同时在申请终止该pod)
kubelet.Kubelet.filterOutInactivePods #如果否,则返回目前所有处于actived状态的pod
kubelet.Kubelet.canAdmitPod #调用前面添加的准入插件来判断是否接受该pod,如果否就拒绝该pod
pod.basicManager.GetMirrorPodByPod #获取pod对应的mirrorpod?mirrorpod不太懂
kubelet.Kubelet.dispatchWork ##把事件对象包装以后丢给podWork异步处理,dispatchWork就是把接收到的参数封装成UpdatePodOptions,调用 UpdatePod 方法.
kubelet.podWorkers.UpdatePod #update函数主要是进行检测和设置选项,实际操作由syncPod函数执行
go kubelet.podWorkers.managePodLoop #update事件 一共三种状态:sync/terminating/terminated,三种状态对应三个不同的函数
case: TerminatedPodWork
syncTerminatedPodFn
kubelet.Kubectl.generateAPIPodStatus #生成pod的状态
status.Manager.SetPodStatus #更新apiserver上的podstatus
volumemanager.volumeManager.WaitForUnmount #等待volume unmount完成(unmount操作由volumeManager进行,这里只是检测)
status.Manager.TerminatePod #主要把pod的.status.containerStatuses 和.status.initContainerStatuses中container的state置为Terminated
status.Manager.updateStatusInternal #更新状态到apiserver
podStatusChannel<-xx #发送pod状态到一个chan,statusManager在监听这个chan,并把信息更新到apiserver中
case: TerminatingPodWork
kubelet.Kubelet.syncTerminatingPod #处理正在终止状态的事件
defaulte:
kubelet.Kubelet.syncPod #负责创建pod,代码很长,跳过
case <-plegChan:
kubelet.Kubelet.HandlePodSyncs
pod.basicManager.GetMirrorPodByPod
kubelet.Kubelet.dispatchWork #把事件对象包装以后丢给podWork异步处理
case <-syncChan: #当一个pod在deadline之后仍然是active状态,那么就需要重新同步这个pod的信息
kubectl.kubectl.getPodsToSync #获取需要进行同步的pod列表
kubelet.Kubelet.dispatchWork #把事件对象包装以后丢给podWork异步处理,事件对象有一个type字段,然后podworker就根据事件类型来调用对应的处理函数
case <-resultes.Updates: #存活探针触发的事件
kubelet.handleProbeSync #直接丢给podWorker
kubelet.Kubelet.HandlePodSyncs
kubelet.Kubelet.dispatchWork #把事件对象包装以后丢给podWork异步处理
case <-resultes.Updates: #就绪探针触发的事件,同上
case <-resultes.Updates: #启动探针触发的事件,同上
atomic.Value.Store #记录本次同步操作结束的时间,这个时间在/healthz服务中会用到
go kubelet.Kubelet.ListenAndServe #开启kubelet对外服务
server.ListenAndServeKubeletServer
server.NewServer #创建kubectlServer对象并进行配置和设置默认值
server.Server.InstallAuthFilter #验证相关
server.Server.InstallDefaultHandlers #设置url和对应的处理方法
http.ListenAndServe #运行healthz服务,路径为healthz
daemon.SdNotify #如果使用的是systemd,那么通知systemd
<-done #一直阻塞在这里,直到程序结束