func (g *genericScheduler) Schedule(pod *api.Pod, minionLister algorithm.MinionLister) (string, error) { minions, err := minionLister.List() if err != nil { return "", err } if len(minions.Items) == 0 { return "", ErrNoNodesAvailable } filteredNodes, failedPredicateMap, err := findNodesThatFit(pod, g.pods, g.predicates, minions) if err != nil { return "", err } priorityList, err := PrioritizeNodes(pod, g.pods, g.prioritizers, algorithm.FakeMinionLister(filteredNodes)) if err != nil { return "", err } if len(priorityList) == 0 { return "", &FitError{ Pod: pod, FailedPredicates: failedPredicateMap, } } return g.selectHost(priorityList) }
// CalculateNodeLabelPriority checks whether a particular label exists on a minion or not, regardless of its value. // If presence is true, prioritizes minions that have the specified label, regardless of value. // If presence is false, prioritizes minions that do not have the specified label. func (n *NodeLabelPrioritizer) CalculateNodeLabelPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) { var score int minions, err := minionLister.List() if err != nil { return nil, err } labeledMinions := map[string]bool{} for _, minion := range minions.Items { exists := labels.Set(minion.Labels).Has(n.label) labeledMinions[minion.Name] = (exists && n.presence) || (!exists && !n.presence) } result := []algorithm.HostPriority{} //score int - scale of 0-10 // 0 being the lowest priority and 10 being the highest for minionName, success := range labeledMinions { if success { score = 10 } else { score = 0 } result = append(result, algorithm.HostPriority{Host: minionName, Score: score}) } return result, nil }
// CalculateSpreadPriority spreads pods by minimizing the number of pods belonging to the same service // on the same machine. func (s *ServiceSpread) CalculateSpreadPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (api.HostPriorityList, error) { var maxCount int var nsServicePods []*api.Pod services, err := s.serviceLister.GetPodServices(pod) if err == nil { // just use the first service and get the other pods within the service // TODO: a separate predicate can be created that tries to handle all services for the pod selector := labels.SelectorFromSet(services[0].Spec.Selector) pods, err := podLister.List(selector) if err != nil { return nil, err } // consider only the pods that belong to the same namespace for _, nsPod := range pods { if nsPod.Namespace == pod.Namespace { nsServicePods = append(nsServicePods, nsPod) } } } minions, err := minionLister.List() if err != nil { return nil, err } counts := map[string]int{} if len(nsServicePods) > 0 { for _, pod := range nsServicePods { counts[pod.Spec.NodeName]++ // Compute the maximum number of pods hosted on any minion if counts[pod.Spec.NodeName] > maxCount { maxCount = counts[pod.Spec.NodeName] } } } result := []api.HostPriority{} //score int - scale of 0-10 // 0 being the lowest priority and 10 being the highest for _, minion := range minions.Items { // initializing to the default/max minion score of 10 fScore := float32(10) if maxCount > 0 { fScore = 10 * (float32(maxCount-counts[minion.Name]) / float32(maxCount)) } result = append(result, api.HostPriority{Host: minion.Name, Score: int(fScore)}) glog.V(10).Infof( "%v -> %v: ServiceSpreadPriority, Score: (%d)", pod.Name, minion.Name, int(fScore), ) } return result, nil }
// BalancedResourceAllocation favors nodes with balanced resource usage rate. // BalancedResourceAllocation should **NOT** be used alone, and **MUST** be used together with LeastRequestedPriority. // It calculates the difference between the cpu and memory fracion of capacity, and prioritizes the host based on how // close the two metrics are to each other. // Detail: score = 10 - abs(cpuFraction-memoryFraction)*10. The algorithm is partly inspired by: // "Wei Huang et al. An Energy Efficient Virtual Machine Placement Algorithm with Balanced Resource Utilization" func BalancedResourceAllocation(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) { nodes, err := minionLister.List() if err != nil { return algorithm.HostPriorityList{}, err } podsToMachines, err := predicates.MapPodsToMachines(podLister) list := algorithm.HostPriorityList{} for _, node := range nodes.Items { list = append(list, calculateBalancedResourceAllocation(pod, node, podsToMachines[node.Name])) } return list, nil }
// LeastRequestedPriority is a priority function that favors nodes with fewer requested resources. // It calculates the percentage of memory and CPU requested by pods scheduled on the node, and prioritizes // based on the minimum of the average of the fraction of requested to capacity. // Details: cpu((capacity - sum(requested)) * 10 / capacity) + memory((capacity - sum(requested)) * 10 / capacity) / 2 func LeastRequestedPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (api.HostPriorityList, error) { nodes, err := minionLister.List() if err != nil { return api.HostPriorityList{}, err } podsToMachines, err := predicates.MapPodsToMachines(podLister) list := api.HostPriorityList{} for _, node := range nodes.Items { list = append(list, calculateResourceOccupancy(pod, node, podsToMachines[node.Name])) } return list, nil }
// Prioritizes the minions by running the individual priority functions sequentially. // Each priority function is expected to set a score of 0-10 // 0 is the lowest priority score (least preferred minion) and 10 is the highest // Each priority function can also have its own weight // The minion scores returned by the priority function are multiplied by the weights to get weighted scores // All scores are finally combined (added) to get the total weighted scores of all minions func PrioritizeNodes(pod *api.Pod, podLister algorithm.PodLister, priorityConfigs []algorithm.PriorityConfig, minionLister algorithm.MinionLister, cloud cloudprovider.Interface) (api.HostPriorityList, error) { result := api.HostPriorityList{} // If no priority configs are provided, then the EqualPriority function is applied // This is required to generate the priority list in the required format if len(priorityConfigs) == 0 { return EqualPriority(pod, podLister, minionLister) } combinedScores := map[string]int{} for _, priorityConfig := range priorityConfigs { weight := priorityConfig.Weight // skip the priority function if the weight is specified as 0 if weight == 0 { continue } priorityFunc := priorityConfig.Function prioritizedList, err := priorityFunc(pod, podLister, minionLister) if err != nil { return api.HostPriorityList{}, err } for _, hostEntry := range prioritizedList { combinedScores[hostEntry.Host] += hostEntry.Score * weight } } if cloud != nil { ext, supported := cloud.SchedulerExtension() if supported { nodes, err := minionLister.List() if err != nil { return api.HostPriorityList{}, err } prioritizedList, err := ext.Prioritize(pod, &nodes) if err != nil { return api.HostPriorityList{}, err } for _, hostEntry := range *prioritizedList { combinedScores[hostEntry.Host] += hostEntry.Score } } } for host, score := range combinedScores { glog.V(10).Infof("Host %s Score %d", host, score) result = append(result, api.HostPriority{Host: host, Score: score}) } return result, nil }
// EqualPriority is a prioritizer function that gives an equal weight of one to all nodes func EqualPriority(_ *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) { nodes, err := minionLister.List() if err != nil { fmt.Errorf("failed to list nodes: %v", err) return []algorithm.HostPriority{}, err } result := []algorithm.HostPriority{} for _, minion := range nodes.Items { result = append(result, algorithm.HostPriority{ Host: minion.Name, Score: 1, }) } return result, nil }
func numericPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) { nodes, err := minionLister.List() result := []algorithm.HostPriority{} if err != nil { return nil, fmt.Errorf("failed to list nodes: %v", err) } for _, minion := range nodes.Items { score, err := strconv.Atoi(minion.Name) if err != nil { return nil, err } result = append(result, algorithm.HostPriority{ Host: minion.Name, Score: score, }) } return result, nil }
// CalculateSpreadPriority spreads pods by minimizing the number of pods belonging to the same service or replication controller. It counts number of pods that run under // Services or RCs as the pod being scheduled and tries to minimize the number of conflicts. I.e. pushes scheduler towards a Node where there's a smallest number of // pods which match the same selectors of Services and RCs as current pod. func (s *SelectorSpread) CalculateSpreadPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) { var maxCount int var nsPods []*api.Pod selectors := make([]labels.Selector, 0) services, err := s.serviceLister.GetPodServices(pod) if err == nil { for _, service := range services { selectors = append(selectors, labels.SelectorFromSet(service.Spec.Selector)) } } controllers, err := s.controllerLister.GetPodControllers(pod) if err == nil { for _, controller := range controllers { selectors = append(selectors, labels.SelectorFromSet(controller.Spec.Selector)) } } if len(selectors) > 0 { pods, err := podLister.List(labels.Everything()) if err != nil { return nil, err } // consider only the pods that belong to the same namespace for _, nsPod := range pods { if nsPod.Namespace == pod.Namespace { nsPods = append(nsPods, nsPod) } } } minions, err := minionLister.List() if err != nil { return nil, err } counts := map[string]int{} if len(nsPods) > 0 { for _, pod := range nsPods { matches := false for _, selector := range selectors { if selector.Matches(labels.Set(pod.ObjectMeta.Labels)) { matches = true break } } if matches { counts[pod.Spec.NodeName]++ // Compute the maximum number of pods hosted on any minion if counts[pod.Spec.NodeName] > maxCount { maxCount = counts[pod.Spec.NodeName] } } } } result := []algorithm.HostPriority{} //score int - scale of 0-10 // 0 being the lowest priority and 10 being the highest for _, minion := range minions.Items { // initializing to the default/max minion score of 10 fScore := float32(10) if maxCount > 0 { fScore = 10 * (float32(maxCount-counts[minion.Name]) / float32(maxCount)) } result = append(result, algorithm.HostPriority{Host: minion.Name, Score: int(fScore)}) glog.V(10).Infof( "%v -> %v: SelectorSpreadPriority, Score: (%d)", pod.Name, minion.Name, int(fScore), ) } return result, nil }
// CalculateAntiAffinityPriority spreads pods by minimizing the number of pods belonging to the same service // on machines with the same value for a particular label. // The label to be considered is provided to the struct (ServiceAntiAffinity). func (s *ServiceAntiAffinity) CalculateAntiAffinityPriority(pod *api.Pod, podLister algorithm.PodLister, minionLister algorithm.MinionLister) (algorithm.HostPriorityList, error) { var nsServicePods []*api.Pod services, err := s.serviceLister.GetPodServices(pod) if err == nil { // just use the first service and get the other pods within the service // TODO: a separate predicate can be created that tries to handle all services for the pod selector := labels.SelectorFromSet(services[0].Spec.Selector) pods, err := podLister.List(selector) if err != nil { return nil, err } // consider only the pods that belong to the same namespace for _, nsPod := range pods { if nsPod.Namespace == pod.Namespace { nsServicePods = append(nsServicePods, nsPod) } } } minions, err := minionLister.List() if err != nil { return nil, err } // separate out the minions that have the label from the ones that don't otherMinions := []string{} labeledMinions := map[string]string{} for _, minion := range minions.Items { if labels.Set(minion.Labels).Has(s.label) { label := labels.Set(minion.Labels).Get(s.label) labeledMinions[minion.Name] = label } else { otherMinions = append(otherMinions, minion.Name) } } podCounts := map[string]int{} for _, pod := range nsServicePods { label, exists := labeledMinions[pod.Spec.NodeName] if !exists { continue } podCounts[label]++ } numServicePods := len(nsServicePods) result := []algorithm.HostPriority{} //score int - scale of 0-10 // 0 being the lowest priority and 10 being the highest for minion := range labeledMinions { // initializing to the default/max minion score of 10 fScore := float32(10) if numServicePods > 0 { fScore = 10 * (float32(numServicePods-podCounts[labeledMinions[minion]]) / float32(numServicePods)) } result = append(result, algorithm.HostPriority{Host: minion, Score: int(fScore)}) } // add the open minions with a score of 0 for _, minion := range otherMinions { result = append(result, algorithm.HostPriority{Host: minion, Score: 0}) } return result, nil }