From 25b4939ffa5b979ba7026102fdd80011753945d7 Mon Sep 17 00:00:00 2001 From: Brendan Burns Date: Tue, 23 Sep 2014 15:38:10 -0700 Subject: [PATCH] Initial cut of a spreading scheduler. --- pkg/scheduler/spreading_scheduler.go | 74 ++++++++++++++++++++++++++++ pkg/scheduler/types.go | 40 +++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 pkg/scheduler/spreading_scheduler.go create mode 100644 pkg/scheduler/types.go diff --git a/pkg/scheduler/spreading_scheduler.go b/pkg/scheduler/spreading_scheduler.go new file mode 100644 index 00000000000..e7f992b8f9a --- /dev/null +++ b/pkg/scheduler/spreading_scheduler.go @@ -0,0 +1,74 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scheduler + +import ( + "fmt" + "math/rand" + "sort" + "sync" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/api" + "github.com/GoogleCloudPlatform/kubernetes/pkg/labels" +) + +type SpreadingScheduler struct { + pods PodLister + random *rand.Rand + randomLock sync.Mutex +} + +// CalculateSpreadPriority spreads pods by minimizing the number of pods on the same machine with the same labels. +// Importantly, if there are services in the system that span multiple heterogenous sets of pods, this spreading priority +// may not provide optimal spreading for the members of that Service. +// TODO: consider if we want to include Service label sets in the scheduling priority. +func CalculateSpreadPriority(selector labels.Selector, podLister PodLister, minionLister MinionLister) (HostPriorityList, error) { + pods, err := podLister.ListPods(selector) + if err != nil { + return nil, err + } + minions, err := minionLister.List() + if err != nil { + return nil, err + } + + counts := map[string]int{} + for _, pod := range pods { + counts[pod.CurrentState.Host]++ + } + + result := []HostPriority{} + for _, minion := range minions { + result = append(result, HostPriority{host: minion, score: counts[minion]}) + } + return result, nil +} + +// Schedule schedules pods to maximize spreading of identical pods across multiple hosts. +// Does not currently take hostPort scheduling into account. +// TODO: combine priority based and fit based schedulers into a single scheduler. +func (s *SpreadingScheduler) Schedule(pod api.Pod, minionLister MinionLister) (string, error) { + priorities, err := CalculateSpreadPriority(labels.SelectorFromSet(pod.Labels), s.pods, minionLister) + if err != nil { + return "", err + } + sort.Sort(priorities) + if len(priorities) == 0 { + return "", fmt.Errorf("failed to find a fit: %v", pod) + } + return priorities[0].host, nil +} diff --git a/pkg/scheduler/types.go b/pkg/scheduler/types.go new file mode 100644 index 00000000000..90d7b642ec8 --- /dev/null +++ b/pkg/scheduler/types.go @@ -0,0 +1,40 @@ +/* +Copyright 2014 Google Inc. All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package scheduler + +// HostPriority represents the priority of scheduling to a particular host, lower priority is better. +type HostPriority struct { + host string + score int +} + +type HostPriorityList []HostPriority + +func (h HostPriorityList) Len() int { + return len(h) +} + +func (h HostPriorityList) Less(i, j int) bool { + if h[i].score == h[j].score { + return h[i].host < h[j].host + } + return h[i].score < h[j].score +} + +func (h HostPriorityList) Swap(i, j int) { + h[i], h[j] = h[j], h[i] +}