美文网首页kubelet 理解
evictionManager 的运行

evictionManager 的运行

作者: shinwing | 来源:发表于2018-05-15 16:04 被阅读0次

    和oom的对比

    首先对比一下 evictionManager 和 oom

    * System OOM events本来就是对资源敏感的,它会stall这个Node直到完成了OOM Killing Process。

    * 当OOM Killer干掉某些containers之后,kubernetes Scheduler可能很快又会调度一个新的Pod到该Node上或者container 直接在node上restart,马上又会触发该Node上的OOM Killer启动OOM Killing Process,事情可能会没完没了的进行。

    接下来看看 evictionManager

    * Kubelet通过pro-actively监控并阻止Node上资源的耗尽,一旦触发Eviction Signals,就会直接Fail一个或者多个Pod以回收资源,而不是通过Linux OOM Killer这样本身耗资源的组件进行回收。

    * 这样的Eviction Signals的可配置的,可以做到Pro-actively。

    * 另外,被Evicted Pods会在其他Node上重新调度,而不会再次触发本Node上的再次Eviction。

    工作机制

    * kubelet预先监控本节点的资源使用,并且阻止资源被耗尽,这样保证node的稳定性。

    kubelet会通过监控Eviction Signal的值,当达到配置的阈值时,就会触发Evict Pods。 kubelet对应的监控周期,就通过cAdvisor的 evictionMonitoringPeriod  配置的,默认10s。

    如果一个Node上监控到的Soft Eviction Signals的值,一直在eviction-soft水平线上下波动,那么为了避免 Node Condition 在true和false频繁切换,配置了  EvictionPressureTransitionPeriod 的值。一旦  MemoryPressure Or DiskPressure为True的前提下, 发生了Soft Evction Singal低于Soft Eviction Thresholds的情况,则需要等待配置时间(默认5m)才会切回 false。

    * kubelet会预先Fail N(>= 1)个Pod以回收出现紧缺的资源。

    如果 eviction pods 回收了一小部分资源就满足了要求,可能随着资源使用的波动或者新的调度Pod使得在该Node上很快又会触发evict pods的动作,这个是非常不划算的。所以在回收资源的时候,不仅要保证比  Eviction Thresholds 低,还要比它低  EvictionMinimumReclaim 所配置的数量。

    * kubelet会Fail一个Pod时,会将Pod内所有Containners都kill掉,并把PodPhase设为Failed。

    在每一个监控周期内,如果Eviction Thresholds被触及,则:

    获取候选Pod

    Fail the Pod

    等待该Pod被Terminated 如果该Pod由于种种原因没有被成功Terminated,Kubelet将会再选一个Pod进行Fail Operation。其中,Fail Pod的时候,Kubelet是通过调用容器运行时的KillPod接口,如果接口返回True,则认为Fail Pod成功,否则视为失败。

    * kubelet通过事先人为设定Eviction Thresholds来触发Eviction动作以回收资源。

    Eviction Thresholds 支持绝对值和相对百分比两种形式

    *  memory.available<10%

    *  memory.available<1Gi

    Soft Eviction Thresholds 指的是,当Eviction Signal中值达到配置的值时,并不会马上触发Kubelet去Evict Pods,而是会等待一个用户配置的grace period之后,再触发。

    Hard Eviction Thresholds  就是, 当Eviction Signal中值达到Hard Eviction Thresholds配置的值时,会立刻触发Kubelet去Evict Pods 。 这个值,要设置的比eviction-soft更低才有意义。

    代码学习

    1. evictionManager  的创建

    首先,Kubelet 在初始化的时候,初始化一个 evictionManager 对象;

    然后,在初始化 runtime 的时候启动这个 evictionManager;

    接下来,看一下 manager 的定义;

    managerImpl struct {

        clock clock.Clock

        config Config    // 配置,包括

                PressureTransitionPeriod( –eviction-pressure-transition-period)

                MaxPodGracePeriodSeconds(–eviction-max-pod-grace-period)

                Thresholds(–eviction-hard, –eviction-soft)

                KernelMemcgNotification(–experimental-kernel-memcg-notification)

        killPodFunc KillPodFunc    // evict pod时kill pod的接口,kubelet NewManager的时候,赋值为killPodNow方法

        imageGC ImageGC    // 当node出现diskPressure condition时,imageGC进行unused images删除操作以回收disk space

        containerGC ContainerGC    // 使用  containerGC  来对容器进行删除操作

        sync.RWMutex

        nodeConditions []v1.NodeConditionType

        nodeConditionsLastObservedAt nodeConditionsObservedAt

        nodeRef *v1.ObjectReference    // 记录有关节点的事件

        recorder record.EventRecorder    // used to measure usage stats on system

        summaryProvider stats.SummaryProvider    // 提供node和node上所有pods的最新status数据汇总,既NodeStats and []PodStats。

        thresholdsFirstObservedAt thresholdsObservedAt    // 记录threshold第一次观察到的时间

        thresholdsMet []evictionapi.Threshold    // 保存已经触发但还没解决的Thresholds,包括那些处于grace period等待阶段的Thresholds。

        resourceToRankFunc map[v1.ResourceName]rankFunc    // 定义各种Resource进行evict 挑选时的排名方法。

        resourceToNodeReclaimFuncs map[v1.ResourceName]nodeReclaimFuncs    // 定义各种Resource进行回收时调用的方法。

        lastObservations signalObservations    // 上一次获取的eviction signal的记录,确保每次更新thresholds时都是按照正确的时间序列进行。

        notifiersInitialized bool    // 表示threshold notifier是否已经初始化,以确定是否可以利用kernel memcg notification功能来提高evict的响应速度。目前创建manager时该值为false,是否要利用kernel memcg notification,完全取决于kubelet的--experimental-kernel-memcg-notification参数。

        dedicatedImageFs *bool

    }

    NewManager不但返回evictionManager对象,还返回了一个lifecycle.PodAdmitHandler实例evictionAdmitHandler,它其实和evictionManager的内容相同,但是不同的两个实例。evictionAdmitHandler用来kubelet创建Pod前进行准入检查,满足条件后才会继续创建Pod,通过 Admit 方法来检查

    这里EvictionManager就影响了 Pod调度的逻辑,在机器有压力的时候,禁止了新的pod产生。

    2. evictionManager  的运行

    start 方法,启动了一个goroutine,来调用 synchronize 方法,获取已经被驱逐的pods,并等待清理操作完成。

    在 synchronize  方法中

    注册Evict Pod时各种Resource的排名函数 (对于内存,硬盘的使用量进行排序)

    m.resourceToRankFunc = buildResourceToRankFunc(hasImageFs)

    注册回收Node Resource的Reclaim函数 (清理所有没有用到的容器和镜像)

    m.resourceToNodeReclaimFuncs = buildResourceToNodeReclaimFuncs(m.imageGC, m.containerGC, hasImageFs)

    通过makeSignalObservations从cAdvisor中获取Eviction Signal Observation和Pod的StatsFunc(后续对Pods进行Rank时需要用)

    observations, statsFunc, err := makeSignalObservations(m.summaryProvider, capacityProvider, activePods)

    如果kubelet配置了--experimental-kernel-memcg-notification且为true

    if m.config.KernelMemcgNotification && !m.notifiersInitialized {

         通过startMemoryThresholdNotifier启动soft & hard memory notification 当system usage第一时间达到soft & hard memory thresholds时,会立刻通知kubelet,并触发evictionManager.synchronize进行资源回收的流程。这样提高了eviction的实时性。(下面调用时候的最后一个参数即handler)

         err = startMemoryThresholdNotifier(m.config.Thresholds, observations, false, func(desc string) { m.synchronize(diskInfoProvider, podFunc, capacityProvider)})

        err = startMemoryThresholdNotifier(m.config.Thresholds, observations, true, func(desc string) { m.synchronize(diskInfoProvider, podFunc, capacityProvider)})

    }

    根据从cAdvisor数据计算得到的Observation(observasions)和配置的thresholds通过thresholdsMet计算得到此次Met的thresholds

    thresholds = thresholdsMet(thresholds, observations, false)

    再根据从cAdvisor数据计算得到的Observation(observasions)和thresholdsMet通过thresholdsMet计算得到已记录但还没解决的thresholds,然后与上一步中的thresholds进行合并。

    thresholdsNotYetResolved := thresholdsMet(m.thresholdsMet, observations, true)

    根据lastObservations中Signal的时间,对比observasions的中Signal中的时间,过滤thresholds。

    thresholds = mergeThresholds(thresholds, thresholdsNotYetResolved)

    更新thresholdsFirstObservedAt, nodeConditions

    nodeConditionsLastObservedAt := nodeConditionsLastObservedAt(nodeConditions, m.nodeConditionsLastObservedAt, now)

    nodeConditions = nodeConditionsObservedSince(nodeConditionsLastObservedAt, m.config.PressureTransitionPeriod, now)

    过滤出那些从observed time到now,已经历过grace period时间的thresholds。

    thresholds = thresholdsMetGracePeriod(thresholdsFirstObservedAt, now)

    更新evictionManager对象的内部数据: nodeConditions,thresholdsFirstObservedAt,nodeConditionsLastObservedAt,thresholds,observations。

    m.nodeConditions = nodeConditions

    m.thresholdsFirstObservedAt = thresholdsFirstObservedAt    

    m.nodeConditionsLastObservedAt = nodeConditionsLastObservedAt    

    m.thresholdsMet = thresholds

    m.lastObservations = observations

    根据thresholds得到starvedResources

    starvedResources := getStarvedResources(thresholds)

    进行排序,如果memory属于starvedResources,则memory排序第一

    sort.Sort(byEvictionPriority(starvedResources))

    取starvedResources排第一的Resource,调用reclaimNodeLevelResources对Node上这种Resource进行资源回收。如果回收完后,available满足thresholdValue+evictionMinimumReclaim,则流程结束,不再evict user-pods

    resourceToReclaim := starvedResources[0]

    m.reclaimNodeLevelResources(resourceToReclaim, observations)

    如果reclaimNodeLevelResources后,还不足以达到要求,则会继续evict user-pods,首先根据前面buildResourceToRankFunc注册的方法对所有active Pods进行排序

    rank, ok := m.resourceToRankFunc[resourceToReclaim]

    rank(activePods, statsFunc)

    按照前面的排序,顺序的调用killPodNow将选出的pod干掉。如果kill某个pod失败,则会跳过这个pod,再按顺序挑下一个pod进行kill。只要某个pod kill成功,就返回结束,也就是说这个流程中,最多只会kill最多一个Pod

    for i := range activePods {

         m.killPodFunc(pod, status, &gracePeriodOverride)

         return []*v1.Pod{pod}

    }

    其中,资源回收 reclaimNodeLevelResources 就是调用 GC 的方法进行资源的回收。

    killPodNow 则调用了 podWorkers.UpdatePod 方法进行pod的驱逐。

    一些总结

    Kubelet通过Eviction Signal来记录监控到的Node节点使用情况。

    Eviction Signal支持:memory.available, nodefs.available, nodefs.inodesFree, imagefs.available, imagefs.inodesFree。

    通过设置Hard Eviction Thresholds和Soft Eviction Thresholds相关参数来触发Kubelet进行Evict Pods的操作。

    Evict Pods的时候根据Pod QoS和资源使用情况挑选Pods进行Kill。

    Kubelet通过eviction-pressure-transition-period防止Node Condition来回切换引起scheduler做出错误的调度决定。

    Kubelet通过--eviction-minimum-reclaim来保证每次进行资源回收后,Node的最少可用资源,以避免频繁被触发Evict Pods操作。

    当Node Condition为MemoryPressure时,Scheduler不会调度新的QoS Class为BestEffort的Pods到该Node。

    当Node Condition为DiskPressure时,Scheduler不会调度任何新的Pods到该Node。

    相关文章

      网友评论

        本文标题:evictionManager 的运行

        本文链接:https://www.haomeiwen.com/subject/sfwedftx.html