Kubelet从人门到放弃:拓扑管理(下)

系列将对Kubelet组件由基础知识到源码进行深入梳理。上一篇zouyee带各位看了CPU 管理的相关内容,其中提及拓扑管理,本文将对此进行详细剖析,拓扑管理在Kubernetes 1.18时提升为Beta。 TopologyManager功能可实现CPU、内存和外围设备(例如SR-IOV VF和GPU)的NUMA对齐,从而使集群满足低延迟需求。

三、源码分析

对于拓扑管理器代码分析,我们从两个方面进行:

1)Kubelet初始化时,涉及拓扑管理的相关操作

2)Kubelet运行时,涉及拓扑管理的相关操作,深入分析拓扑管理结构逻辑

3.1 Kubelet初始化

关于Kubelet初始化,我们在以CPU manager结合拓扑管理器的启动图(当前为CPU manager、memory manager、device manager构成资源分配管理器,其属于Container Manager模块的子系统)进行说明。

对于上图的内容,zouyee总结流程如下:

1、在命令行启动部分,Kubelet中调用NewContainerManager构建ContainerManager

2、NewContainerManager函数调用topologymanager.NewManager构建拓扑管理器,否则未启用拓扑管理器,则构建fake

3、NewContainerManager函数分别调用cpu、memory及device提供的NewManager构建相关管理器

4、若拓扑管理特性开启,则拓扑管理器使用AddHintPriovider方法将CPU、memory及device管理器加入管理,上述三种资源分配器,需要实现HintPriovider接口。

5、回到命令行启动部分,调用NewMainKubelet(),构建Kubelet结构体

6、构建Kubelet结构体时,将CPU、memory管理器(没有device)跟拓扑管理器封装为InternalContainerLifecycle接口,其实现Pod相关的生命周期资源管理操作,涉及资源分配回收相关的是PreStartContainer、PostStopContainer方法,可参看具体实现。

7、构建Kubelet结构体时,调用AddPodmitHandler将GetAllocateResourcesPodAdmitHandler方法加入到Pod准入插件中,在Pod创建时,资源预分配检查,其中GetAllocateResourcesPodAdmitHandler根据是否开启拓扑管理,决定是返回拓扑管理Admit接口,还是使用cpu、memory及device构成资源分配器,实现Admit接口。

8、构建Kubelet结构体后,调用ContainerManager的Start方法,ContainerManager在Start方法中调用CPU、memeory及device管理器的Start方法,其做一些处理工作并孵化一个goroutine,执行reconcileState()

注:关于上述启动流程的代码解释,可以返回识透CPU一文。


3.2 Kubelet运行时

Kubelet运行时,涉及到拓扑管理、资源分配的就是对于Pod处理流程,zouyee总结如下:

1、PodConfig从apiserver、file及http三处接受Pod,调用Updates()返回channel,内容为Pod列表及类型。

2、Kubelet调用Run方法,处理PodConfig的Updates()返回的channel

3、在Run方法内部,Kubelet调用syncLoop,而在syncLoop内部,调用syncLoopIteration

4、在syncLoopIteration中,当configCh(即PodConfig调用的Updates())返回的pod类型为ADD时,执行handler.HandlePodAdditions,在HandlePodAdditions中,处理流程如下:当pod状态为非Termination时,Kubelet遍历admitHandlers,调用Admit方法。

注:syncLoopIteration中除了configCh,还有其他channel(plegCh、syncCh、housekeepingCh及livenessManager)其中plegCh、syncCh及livenessManager三类channel中调用的HandlePodAddtion、HandlePodReconcile、HandlePodSyncs及HandlePodUpdates都涉及dispatch方法调用,还记得Kubelet流程中,将CPU管理器、内存管理器跟拓扑管理器封装为InternalContainerLifecycle接口,其实现Pod相关的生命周期资源管理操作,涉及CPU、内存相关的是PreStartContainer方法,其调用AddContainer方法,后续统一介绍。

5、在介绍Kubelet启动时,调用AddPodmitHandler将GetAllocateResourcesPodAdmitHandler方法加入到admitHandlers中,因此在调用Admit方法的操作,涉及到拓扑管理的也就是GetAllocateResourcesPodAdmitHandler,那么接下来就接受一下该方法。

6、在Kublet的GetAllocateResourcesPodAdmitHandler方法的处理逻辑为:当启用拓扑特性时,资源分配由拓扑管理器统一接管,如果未启用,则为cpu管理器、内存管理器及设备管理器分别管理,本文只介绍启用拓扑管理器的情况。

7、启用拓扑管理器后,Kublet的GetAllocateResourcesPodAdmitHandler返回的Admit接口类型,由拓扑管理器实现,后续统一介绍。

上述流程即为Pod大致的处理流程,下面介绍拓扑结构初始化、AddContainer及Admit方法。

1)拓扑结构初始化

拓扑结构初始化函数为pkg/kubelet/cm/topologymanager/topology_manager.go:119

// NewManager creates a new TopologyManager based on provided policy and scope
func NewManager(topology []cadvisorapi.Node, topologyPolicyName string, topologyScopeName string) (Manager, error) {
   // a. 根据cadvisor数据初始化numa信息
   var numaNodes []int
   for _, node := range topology {
      numaNodes = append(numaNodes, node.Id)
   }
     // b. 判断策略为非none时,numa节点数量是否超过8,若超过,则返回错误
   if topologyPolicyName != PolicyNone && len(numaNodes) > maxAllowableNUMANodes {
      return nil, fmt.Errorf("unsupported on machines with more than %v NUMA Nodes", maxAllowableNUMANodes)
   }
     // c. 根据传入policy名称,进行初始化policy
   var policy Policy
   switch topologyPolicyName {

   case PolicyNone:
      policy = NewNonePolicy()

   case PolicyBestEffort:
      policy = NewBestEffortPolicy(numaNodes)

   case PolicyRestricted:
      policy = NewRestrictedPolicy(numaNodes)

   case PolicySingleNumaNode:
      policy = NewSingleNumaNodePolicy(numaNodes)

   default:
      return nil, fmt.Errorf("unknown policy: \"%s\"", topologyPolicyName)
   }
     // d. 根据传入scope名称,以初始化policy结构体初始化scope
   var scope Scope
   switch topologyScopeName {

   case containerTopologyScope:
      scope = NewContainerScope(policy)

   case podTopologyScope:
      scope = NewPodScope(policy)

   default:
      return nil, fmt.Errorf("unknown scope: \"%s\"", topologyScopeName)
   }
     // e. 封装scope,返回manager结构体
   manager := &manager{
      scope: scope,
   }

   

    a. 根据cadvisor数据初始化numa信息

    b. 判断策略为非none时,numa节点数量是否超过8,若超过,则返回错误

    c. 根据传入policy名称,进行初始化policy

    d. 根据传入scope名称,以初始化policy结构体初始化scope

    e. 封装scope,返回manager结构体

2) AddContainer

    AddContainer实际调用scope的方法:pkg/kubelet/cm/topologymanager/scope.go:97

func (s *scope) AddContainer(pod *v1.Pod, containerID string) error {
   s.mutex.Lock()
   defer s.mutex.Unlock()

   s.podMap[containerID] = string(pod.UID)
   return nil
}

    该处只做简单字典加入操作。

3)Admit

    Admit函数调用:pkg/kubelet/cm/topologymanager/topology_manager.go:186,根据scope类型分别调用不同的实现:

    a、container

pkg/kubelet/cm/topologymanager/scope_container.go:45

func (s *containerScope) Admit(pod *v1.Pod) lifecycle.PodAdmitResult {
   // Exception - Policy : none
   // 1. 策略为none,则跳过
   if s.policy.Name() == PolicyNone {
      return s.admitPolicyNone(pod)
   }
     // 2. 遍历init及常规容器
   for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) {
           // 2.1 计算亲和性,判断是否准入
      bestHint, admit := s.calculateAffinity(pod, &container)
      

      if !admit {
         return topologyAffinityError()
      }
      // 2.2 记录分配结果
      s.setTopologyHints(string(pod.UID), container.Name, bestHint)
            // 2.3 调用hint provider分配资源
      err := s.allocateAlignedResources(pod, &container)
      if err != nil {
         return unexpectedAdmissionError(err)
      }
   }
   return admitPod()
}

    b、pod

pkg/kubelet/cm/topologymanager/scope_pod.go:45

func (s *podScope) Admit(pod *v1.Pod) lifecycle.PodAdmitResult {
   // Exception - Policy : none
   // 1. 策略为none,则跳过
   if s.policy.Name() == PolicyNone {
      return s.admitPolicyNone(pod)
   }
    // 2 计算亲和性,判断是否准入
   bestHint, admit := s.calculateAffinity(pod)
   
   if !admit {
      return topologyAffinityError()
   }
        // 3. 遍历init及常规容器
   for _, container := range append(pod.Spec.InitContainers, pod.Spec.Containers...) {
      // 3.1 记录分配结果
      s.setTopologyHints(string(pod.UID), container.Name, bestHint)
            // 3.2 调用hint provider分配资源
      err := s.allocateAlignedResources(pod, &container)
      if err != nil {
         return unexpectedAdmissionError(err)
      }
   }
   return admitPod()
}

    具体说明见代码注释,需要说明的是scope为container与pod的区别主要在计算亲和性,判断是否准入的阶段,同样也反应了scope与container的粒度,后续重点介绍calculateAffinity方法。

    下面zouyee带各位总结一下拓扑管理器的Admit逻辑。

    拓扑管理器为组件定义Hint Providers的接口,以发送和接收拓扑信息,CPU、memory及device都实现该接口,拓扑管理器调用AddHintPriovider加入到管理器,其中拓扑信息表示可用的 NUMA 节点和首选分配指示的位掩码。 拓扑管理器策略对所提供的hint执行一组操作,并根据策略获取最优解;如果存储了与预期不符的hint,则该建议的优选字段设置为 false。所选建议可用来决定节点接受或拒绝 Pod 。 之后,hint结果存储在拓扑管理器中,供Hint Providers进行资源分配决策时使用。

对于上述两种作用域(container及pod)的calculateAffinity通用流程,汇总如下(忽略计算亲和性的差异):


对于上图的内容,zouyee总结流程如下:

  1. 遍历容器中的所有容器(scope为pod跟container的差别,上面已经说明)
  2. 对于每个容器,针对容器请求的每种拓扑感知资源类型(例如gpu-vendor.com/gpu、nic-vendor.com/nic、cpu等),从一组HintProviders中获取TopologyHints。
  3. 使用选定的策略,合并收集到的TopologyHints以找到最佳hint,该hint可以在所有资源类型之间对齐资源分配。
  4. 循环返回hintHintProviders集合,指示他们使用合并的hint来分配他们管理的资源。
  5. 如果上述步骤中的任一个失败或根据所选策略无法满足对齐要求,Kubelet将不会准入该pod。

下面zouyee根据下图依次介绍拓扑管理器涉及的结构体。

a. TopologyHints

拓扑hint对一组约束进行编码,记录可以满足给定的资源请求。 目前,我们唯一考虑的约束是NUMA对齐。 定义如下:

type TopologyHint struct {
    NUMANodeAffinity bitmask.BitMask
    Preferred bool
}

NUMANodeAffinity字段表示可以满足资源请求的NUMA节点个数的位掩码,是bitmask类型。 例如,在2个NUMA节点的系统上,可能的掩码包括:

{00}, {01}, {10}, {11}

Preferred是用来管理NUMANodeAffinity是否生效的布尔类型,如果Preferred为true那么当前的亲和度有效,如果为false那么当前的亲和度无效。 使用best-effort策略时,在生成最佳hint时,优先hint将优先于非优先hint。 使用restricted和single-numa-node策略时,将拒绝非优先hint。

HintProvider为每个可以满足该资源请求的NUMA节点的掩码生成一个TopologyHint。 如果掩码不能满足要求,则将其省略。 例如,当被要求分配2个资源时,HintProvider可能在具有2个NUMA节点的系统上提供以下hint。 这些hint编码代表的两种资源可以都来自单个NUMA节点(0或1),也可以各自来自不同的NUMA节点。

{01: True}, {10: True}, {11: False}

当且仅当NUMANodeAffinity代表的信息可以满足资源请求的最小NUMA节点集时,所有HintProvider才会将Preferred字段设置为True。

{0011: True}, {0111: False}, {1011: False}, {1111: False}

如果在其他容器释放资源之前无法满足实际的首选分配,则HintProvider返回所有Preferred字段设置为False的hint列表。考虑以下场景:

  1. 当前,除2个CPU外的所有CPU均已分配给容器
  2. 剩余的2个CPU在不同的NUMA节点上
  3. 一个新的容器请求2个CPU

在上述情况下,生成的唯一hint是{11:False}而不是{11:True}。因为可以从该系统上的同一NUMA节点分配2个CPU(虽然当前的分配状态,还不能立即分配),在可以满足最小对齐方式时,使pod进入失败并重试部署总比选择以次优对齐方式调度pod更好。

b. HintProviders

目前,Kubernetes中仅有的HintProviders是CPUManager、MemoryManager及DeviceManager。 拓扑管理器既从HintProviders收集TopologyHint,又使用合并的最佳hint调用资源分配。 HintProviders实现以下接口:

type HintProvider interface {
    GetTopologyHints(*v1.Pod, *v1.Container) map[string][]TopologyHint
    Allocate(*v1.Pod, *v1.Container) error
}

注意:GetTopologyHints返回一个map [string] [] TopologyHint。 这使单个HintProvider可以提供多种资源类型的hint。 例如,DeviceManager可以返回插件注册的多种资源类型。

当HintProvider生成hint时,仅考虑如何满足系统上当前可用资源的对齐方式。 不考虑已经分配给其他容器的任何资源。

例如,考虑图1中的系统,以下两个容器请求资源:

# Container0
spec:
    containers:
    - name: numa-aligned-container0
      image: alpine
      resources:
          limits:
              cpu: 2
              memory: 200Mi
              gpu-vendor.com/gpu: 1
              nic-vendor.com/nic: 1

# Container1
spec:
    containers:
    - name: numa-aligned-container1
      image: alpine
      resources:
          limits:
              cpu: 2
              memory: 200Mi
              gpu-vendor.com/gpu: 1
              nic-vendor.com/nic: 1

如果Container0是要在系统上分配的第一个容器,则当前三种拓扑感知资源类型生成以下hint集:

 cpu: {{01: True}, {10: True}, {11: False}}
gpu-vendor.com/gpu: {{01: True}, {10: True}}
nic-vendor.com/nic: {{01: True}, {10: True}}

已经对齐的资源分配:

{cpu: {0, 1}, gpu: 0, nic: 0}


在考虑Container1时,上述资源假定为不可用,因此将生成以下hint集:

cpu: {{01: True}, {10: True}, {11: False}}
gpu-vendor.com/gpu: {{10: True}}
nic-vendor.com/nic: {{10: True}}

分配的对齐资源:

{cpu: {4, 5}, gpu: 1, nic: 1}


注意:HintProviders调用Allocate的时,并未采用合并的最佳hint, 而是通过TopologyManager实现的Store接口,HintProviders通过该接口,获取生成的hint:

type Store interface {
    GetAffinity(podUID string, containerName string) TopologyHint
}

c. Policy.Merge

每个策略都实现了合并方法,各自实现如何将所有HintProviders生成的TopologyHint集合合并到单个TopologyHint中,该TopologyHint用于提供已对齐的资源分配信息。

// 1. bestEffort
func (p *bestEffortPolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, bool) {
    filteredProvidersHints := filterProvidersHints(providersHints)
    bestHint := mergeFilteredHints(p.numaNodes, filteredProvidersHints)
    admit := p.canAdmitPodResult(&bestHint)
    return bestHint, admit
}
// 2. restrict
func (p *restrictedPolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, bool) {
    filteredHints := filterProvidersHints(providersHints)
    hint := mergeFilteredHints(p.numaNodes, filteredHints)
    admit := p.canAdmitPodResult(&hint)
    return hint, admit
}
// 3. sigle-numa-node
func (p *singleNumaNodePolicy) Merge(providersHints []map[string][]TopologyHint) (TopologyHint, bool) {
   filteredHints := filterProvidersHints(providersHints)
   // Filter to only include don't cares and hints with a single NUMA node.
   singleNumaHints := filterSingleNumaHints(filteredHints)
   bestHint := mergeFilteredHints(p.numaNodes, singleNumaHints)

   defaultAffinity, _ := bitmask.NewBitMask(p.numaNodes...)
   if bestHint.NUMANodeAffinity.IsEqual(defaultAffinity) {
      bestHint = TopologyHint{nil, bestHint.Preferred}
   }

   admit := p.canAdmitPodResult(&bestHint)
   return bestHint, admit
}

从上述三种分配策略,可以发现Merge方法的一些类似流程:

1. filterProvidersHints
2. mergeFilteredHints
3. canAdmitPodResult

其中filterProvidersHints位于pkg/kubelet/cm/topologymanager/policy.go:62

func filterProvidersHints(providersHints []map[string][]TopologyHint) [][]TopologyHint {
   // Loop through all hint providers and save an accumulated list of the
   // hints returned by each hint provider. If no hints are provided, assume
   // that provider has no preference for topology-aware allocation.
   var allProviderHints [][]TopologyHint
   for _, hints := range providersHints {
      // If hints is nil, insert a single, preferred any-numa hint into allProviderHints.
      if len(hints) == 0 {
         klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with any resource")
         allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
         continue
      }

      // Otherwise, accumulate the hints for each resource type into allProviderHints.
      for resource := range hints {
         if hints[resource] == nil {
            klog.Infof("[topologymanager] Hint Provider has no preference for NUMA affinity with resource '%s'", resource)
            allProviderHints = append(allProviderHints, []TopologyHint{{nil, true}})
            continue
         }

         if len(hints[resource]) == 0 {
            klog.Infof("[topologymanager] Hint Provider has no possible NUMA affinities for resource '%s'", resource)
            allProviderHints = append(allProviderHints, []TopologyHint{{nil, false}})
            continue
         }

         allProviderHints = append(allProviderHints, hints[resource])
      }
   }
   return allProviderHints
}

遍历所有的HintProviders,收集并存储hint。如果HintProviders没有提供任何hint,那么就默认为该provider没有任何资源分配。最终返回allProviderHints.

其中mergeFilteredHints位于pkg/kubelet/cm/topologymanager/policy.go:95

// Merge a TopologyHints permutation to a single hint by performing a bitwise-AND
// of their affinity masks. The hint shall be preferred if all hits in the permutation
// are preferred.
func mergePermutation(numaNodes []int, permutation []TopologyHint) TopologyHint {
    // Get the NUMANodeAffinity from each hint in the permutation and see if any
    // of them encode unpreferred allocations.
    preferred := true
    defaultAffinity, _ := bitmask.NewBitMask(numaNodes...)
    var numaAffinities []bitmask.BitMask
    for _, hint := range permutation {
        // Only consider hints that have an actual NUMANodeAffinity set.
        if hint.NUMANodeAffinity == nil {
            numaAffinities = append(numaAffinities, defaultAffinity)
        } else {
            numaAffinities = append(numaAffinities, hint.NUMANodeAffinity)
        }

        if !hint.Preferred {
            preferred = false
        }
    }

    // Merge the affinities using a bitwise-and operation.
    mergedAffinity := bitmask.And(defaultAffinity, numaAffinities...)
    // Build a mergedHint from the merged affinity mask, indicating if an
    // preferred allocation was used to generate the affinity mask or not.
    return TopologyHint{mergedAffinity, preferred}
}


func mergeFilteredHints(numaNodes []int, filteredHints [][]TopologyHint) TopologyHint {
   // Set the default affinity as an any-numa affinity containing the list
   // of NUMA Nodes available on this machine.
   defaultAffinity, _ := bitmask.NewBitMask(numaNodes...)

   // Set the bestHint to return from this function as {nil false}.
   // This will only be returned if no better hint can be found when
   // merging hints from each hint provider.
   bestHint := TopologyHint{defaultAffinity, false}
   iterateAllProviderTopologyHints(filteredHints, func(permutation []TopologyHint) {
      // Get the NUMANodeAffinity from each hint in the permutation and see if any
      // of them encode unpreferred allocations.
      mergedHint := mergePermutation(numaNodes, permutation)
      // Only consider mergedHints that result in a NUMANodeAffinity > 0 to
      // replace the current bestHint.
      if mergedHint.NUMANodeAffinity.Count() == 0 {
         return
      }

      // If the current bestHint is non-preferred and the new mergedHint is
      // preferred, always choose the preferred hint over the non-preferred one.
      if mergedHint.Preferred && !bestHint.Preferred {
         bestHint = mergedHint
         return
      }

      // If the current bestHint is preferred and the new mergedHint is
      // non-preferred, never update bestHint, regardless of mergedHint's
      // narowness.
      if !mergedHint.Preferred && bestHint.Preferred {
         return
      }

      // If mergedHint and bestHint has the same preference, only consider
      // mergedHints that have a narrower NUMANodeAffinity than the
      // NUMANodeAffinity in the current bestHint.
      if !mergedHint.NUMANodeAffinity.IsNarrowerThan(bestHint.NUMANodeAffinity) {
         return
      }

      // In all other cases, update bestHint to the current mergedHint
      bestHint = mergedHint
   })

   return bestHint
}

mergeFilteredHints函数处理流程如下所示:

  1. 通过cadvisor传递的NUMA节点数生成bitmask
  2. 设置 bestHint := TopologyHint{defaultAffinity, false}如果没有符合条件的hint,返回该hint
  3. 取每种资源类型生成的TopologyHints的交叉积
  4. 对于交叉中的每个条目,每个TopologyHint的NUMA亲和力执行位计算。 在合并hint中将此设置为NUMA亲和性。
  5. 如果条目中的所有hint都将Preferred设置为True,则在合并hint中的Preferred设置为True。
  6. 如果条目中存在Preferred设置为False的hint,则在合并hint中的Preferred设置为False。 如果其NUMA亲和性节点数量全为0,则在合并hint中的Preferred设置为False。

接上文的分配说明,Container0的hint为:

cpu: {{01: True}, {10: True}, {11: False}}
gpu-vendor.com/gpu: {{01: True}, {10: True}}
nic-vendor.com/nic: {{01: True}, {10: True}}

上面的算法将产生的交叉积及合并后的hint:

cross-product entry{cpu, gpu-vendor.com/gpu, nic-vendor.com/nic} "merged" hint
{{01: True}, {01: True}, {01: True}} {01: True}
{{01: True}, {01: True}, {10: True}} {00: False}
{{01: True}, {10: True}, {01: True}} {00: False}
{{01: True}, {10: True}, {10: True}} {00: False}

{{10: True}, {01: True}, {01: True}} {00: False}
{{10: True}, {01: True}, {10: True}} {00: False}
{{10: True}, {10: True}, {01: True}} {00: False}
{{10: True}, {10: True}, {10: True}} {01: True}

{{11: False}, {01: True}, {01: True}} {01: False}
{{11: False}, {01: True}, {10: True}} {00: False}
{{11: False}, {10: True}, {01: True}} {00: False}
{{11: False}, {10: True}, {10: True}} {10: False}

生成合并的hint列表之后,将根据Kubelet配置的拓扑管理器分配策略来确定哪个为最佳hint。

一般流程如下所示:

  1. 根据合并hint的“狭窄度”进行排序。狭窄度定义为hint的NUMA相似性掩码中设置的位数。设置的位数越少,hint越窄。对于在NUMA关联掩码中设置了相同位数的hint,设置为最低位的hint被认为是较窄的。
  2. 根据合并hint的Preferred字段排序。Preferred为true的hint优于Preferred为true的hint。
  3. 为Preferred选择具有最佳设置的最窄hint。

在上面的示例中,当前支持的所有策略都将使用hint{01:True}以准入该Pod。


四、后续发展

4.1 已知问题

  1. 拓扑管理器所能处理的最大 NUMA 节点个数是 8。若 NUMA 节点数超过 8, 枚举可能的 NUMA 亲和性而生成hint时会导致数据爆炸式增长。
  2. 调度器不支持资源拓扑功能,当调度至该节点,但因为拓扑管理器的原因导致在该节点上调度失败。

4.2 功能特性

a. hugepage的numa应用

如前所述,当前仅可用于TopologyManager的三个HintProvider是CPUManager、MemoryManager及DeviceManager。 但是,目前也正在努力增加对hugepage的支持,TopologyManager最终将能够在同一NUMA节点上分配内存,大页,CPU和PCI设备。

b. 调度

当前,TopologyManager不参与Pod调度决策,仅充当Pod Admission控制器,当调度器将Pod调度到某节点后,TopologyManager才判定应该接受还是拒绝该pod。但是可能会因为节点可用的NUMA对齐资源而拒绝pod,这跟调度系统的决定相悖。

那么我们如何解决这个问题呢?当前Kubernetes调度框架提供实现framework架构,调度算法插件化,可以实现诸如NUMA对齐之类的调度插件。

d. Pod对齐策略

如前所述,单个策略通过Kubelet命令行应用于节点上的所有Pod,而不是根据Pod进行自定义配置。

当前实现该特性最大的问题是,此功能需要更改API才能在Pod结构或其关联的RuntimeClass中表达所需的对齐策略。

后续相关内容,请查看公众号:DCOS

Kubelet从人门到放弃:拓扑管理(下)_第1张图片

https://mp.weixin.qq.com/s/mA...


五、参考资料

1、kubernetes-1-18-feature-topoloy-manager-beta

2、topology manager

3、cpu manager policy

4、设计文档

你可能感兴趣的:(Kubelet从人门到放弃:拓扑管理(下))