美文网首页kubernets相关分析
k8s Affinity 亲和性专题源码分析 (三)

k8s Affinity 亲和性专题源码分析 (三)

作者: Xiao_Yang | 来源:发表于2019-04-22 09:16 被阅读0次

    本文是续前面亲和性专题的最后一篇《服务亲和性》的算法分析篇,在default调度器代码内并未注册此预选策略,仅有代码实现。连google/baidu上都无法查询到相关使用案例,配置用法不予分析,仅看下面源码详细分析。

    四 Service亲和性

    代码场景应用注释译文:
    一个服务的第一个Pod被调度到带有Label “region=foo”的Nodes(资源集群)上, 那么其服务后面的其它Pod都将调度至Label “region=foo”的Nodes。

    4.1 Serice亲和性预选策略checkServiceAffinity

    通过NewServiceAffinityPredicate()创建一个ServiceAffinity类对象,并返回两个预选策略所必须的处理Func:

    • affinity.checkServiceAffinity 基于预选元数据Meta,对被调度的pod检测Node是否满足服务亲和性.

    • affinity.serverAffinityMetadataProducer 基于预选Meta的pod信息,获取服务信息和在相同NameSpace下的的Pod列表,供亲和检测时使用。

    后面将详述处理func

    !FILENAME pkg/scheduler/algorithm/predicates/predicates.go:955

    func NewServiceAffinityPredicate(podLister algorithm.PodLister, serviceLister algorithm.ServiceLister, nodeInfo NodeInfo, labels []string) (algorithm.FitPredicate, PredicateMetadataProducer) {
        affinity := &ServiceAffinity{
            podLister:     podLister,
            serviceLister: serviceLister,
            nodeInfo:      nodeInfo,
            labels:        labels,
        }
        return affinity.checkServiceAffinity, affinity.serviceAffinityMetadataProducer
    }
    

    affinity.serverAffinityMetadataProducer()
    输入:predicateMateData
    返回:services 和 pods

    1. 基于预选MetaData的pod信息查询出services
    2. 基于预选MetaData的pod Lables获取所有匹配的pods,且过滤掉仅剩在同一个Namespace的pods。

    !FILENAME pkg/scheduler/algorithm/predicates/predicates.go:934

    func (s *ServiceAffinity) serviceAffinityMetadataProducer(pm *predicateMetadata) {
        if pm.pod == nil {
            klog.Errorf("Cannot precompute service affinity, a pod is required to calculate service affinity.")
            return
        }
        pm.serviceAffinityInUse = true
        var errSvc, errList error
        // 1.基于预选MetaData的pod信息查询services
        pm.serviceAffinityMatchingPodServices, errSvc = s.serviceLister.GetPodServices(pm.pod)
        // 2.基于预选MetaData的pod Lables获取所有匹配的pods
        selector := CreateSelectorFromLabels(pm.pod.Labels)
        allMatches, errList := s.podLister.List(selector)
    
        // In the future maybe we will return them as part of the function.
        if errSvc != nil || errList != nil {
            klog.Errorf("Some Error were found while precomputing svc affinity: \nservices:%v , \npods:%v", errSvc, errList)
        }
        // 3.过滤掉仅剩在同一个Namespace的pods
        pm.serviceAffinityMatchingPodList = FilterPodsByNamespace(allMatches, pm.pod.Namespace)
    }
    
    
    

    affinity.checkServiceAffinity()
    基于预处理的MetaData,对被调度的pod检测Node是否满足服务亲和性。

    最终的亲和检测Labels:

    ​ Final affinityLabels =(A ∩ B)+ (B ∩ C) 与 node.Labels 进行Match计算 //∩交集符号

    A: 需被调度podNodeSelector配置
    B: 需被调度pod定义的服务亲和affinityLabels配置
    C: 被选定的亲和目标NodeLables

    !FILENAME pkg/scheduler/algorithm/predicates/predicates.go:992

    func (s *ServiceAffinity) checkServiceAffinity(pod *v1.Pod, meta algorithm.PredicateMetadata, nodeInfo *schedulercache.NodeInfo) (bool, []algorithm.PredicateFailureReason, error) {
        var services []*v1.Service
        var pods []*v1.Pod
        if pm, ok := meta.(*predicateMetadata); ok && (pm.serviceAffinityMatchingPodList != nil || pm.serviceAffinityMatchingPodServices != nil) {
            services = pm.serviceAffinityMatchingPodServices
            pods = pm.serviceAffinityMatchingPodList
        } else {
            // Make the predicate resilient in case metadata is missing.
            pm = &predicateMetadata{pod: pod}
            s.serviceAffinityMetadataProducer(pm)
            pods, services = pm.serviceAffinityMatchingPodList, pm.serviceAffinityMatchingPodServices
        }
        // 筛选掉存在于Node(nodeinfo)上pods,且与之进行podKey比对不相等的pods。          ①
        filteredPods := nodeInfo.FilterOutPods(pods)
        node := nodeInfo.Node()
        if node == nil {
            return false, nil, fmt.Errorf("node not found")
        }
        // affinityLabes交集 ==(A ∩ B) 
      // A:被调度pod的NodeSelector定义  B:定义的亲和性Labels                           ②
        affinityLabels := FindLabelsInSet(s.labels, labels.Set(pod.Spec.NodeSelector))
        // Step 1: If we don't have all constraints, introspect nodes to find the missing constraints.
        if len(s.labels) > len(affinityLabels) {
            if len(services) > 0 {
                if len(filteredPods) > 0 {
                    //"被选定的亲和Node"
            //基于第一个filteredPods获取Node信息
                    nodeWithAffinityLabels, err := s.nodeInfo.GetNodeInfo(filteredPods[0].Spec.NodeName)
                    if err != nil {
                        return false, nil, err
                    }
                    // 输入:交集Labels、服务亲和Labels、被选出的亲和Node Lables
                    // affinityLabels = affinityLabels + 交集(B ∩ C)
                    // B: 服务亲和Labels  C:被选出的亲和Node的Lables                           ③
                    AddUnsetLabelsToMap(affinityLabels, s.labels, labels.Set(nodeWithAffinityLabels.Labels))
                }
            }
        }
    
        // 进行一次最终的匹配(affinityLabels 与 被检测亲和的node.Labels )               ④
        if CreateSelectorFromLabels(affinityLabels).Matches(labels.Set(node.Labels)) {
            return true, nil, nil
        }
        return false, []algorithm.PredicateFailureReason{ErrServiceAffinityViolated}, nil
    }
    

    FilterOutPods()
    筛选掉存在于Node(nodeinfo)上pods,且与之进行podKey比对不相等的pods
    filteredPods = 未在Node上的pods + 在node上但podKey相同的pods

    !FILENAME pkg/scheduler/cache/node_info.go:656

    func (n *NodeInfo) FilterOutPods(pods []*v1.Pod) []*v1.Pod {
        //获取Node的详细信息
        node := n.Node()
        if node == nil {
            return pods
        }
        filtered := make([]*v1.Pod, 0, len(pods))
        for _, p := range pods {
            //如果pod(亲和matched)的NodeName 不等于Spec配置的nodeNmae (即pod不在此Node上),将pod放入filtered.
            if p.Spec.NodeName != node.Name {
                filtered = append(filtered, p)
                continue
            }
            //如果在此Node上,则获取podKey(pod.UID)
            //遍历此Node上所有的目标Pods,获取每个podKey进行与匹配pod的podkey是否相同,
        //相同则将pod放入filtered并返回
            podKey, _ := GetPodKey(p)
            for _, np := range n.Pods() {
                npodkey, _ := GetPodKey(np)
                if npodkey == podKey {
                    filtered = append(filtered, p)
                    break
                }
            }
        }
        return filtered
    }
    

    ② *FindLabelsInSet() *
    参数一: (B)定义的亲和性Labels配置
    参数二: (A)被调度pod的定义NodeSelector配置Selector
    检测存在的于NodeSelector的亲和性Labels配置,则取两者的交集部分. (A ∩ B)

    !FILENAME pkg/scheduler/algorithm/predicates/utils.go:26

    func FindLabelsInSet(labelsToKeep []string, selector labels.Set) map[string]string {
        aL := make(map[string]string)
        for _, l := range labelsToKeep {
            if selector.Has(l) {
                aL[l] = selector.Get(l)
            }
        }
        return aL
    }
    

    AddUnsetLabelsToMap()
    参数一: (N)在FindLabelsInSet()计算出来的交集Labels
    参数二: (B)定义的亲和性Labels配置
    参数三: (C)"被选出的亲和Node"上的Lables
    检测存在的于"被选出的亲和Node"上的亲和性配置Labels,则取两者的交集部分存放至N. (B ∩ C)=>N

    !FILENAME pkg/scheduler/algorithm/predicates/utils.go:37

    // 输入:交集Labels、服务亲和Labels、被选出的亲和Node Lables
    // 填充:Labels交集 ==(B ∩ C) B: 服务亲和Labels  C:被选出的亲和Node Lables
    func AddUnsetLabelsToMap(aL map[string]string, labelsToAdd []string, labelSet labels.Set) {
        for _, l := range labelsToAdd {
            // 如果存在则不作任何操作
            if _, exists := aL[l]; exists {
                continue
            }
            // 反之,计算包含的交集部分 C ∩ B
            if labelSet.Has(l) {
                aL[l] = labelSet.Get(l)
            }
        }
    }
    

    CreateSelectorFromLabels().Match() 返回labels.Selector对象

    !FILENAME pkg/scheduler/algorithm/predicates/utils.go:62

    func CreateSelectorFromLabels(aL map[string]string) labels.Selector {
        if aL == nil || len(aL) == 0 {
            return labels.Everything()
        }
        return labels.Set(aL).AsSelector()
    }
    

    END

    文章及内容转发请署名XiaoYang

    相关文章

      网友评论

        本文标题:k8s Affinity 亲和性专题源码分析 (三)

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