Initial scheduler implementation.

The scheduler is composed of filters (to apply constraints) and a
placement strategy (random, bin packing, ...).

Signed-off-by: Andrea Luzzardi <aluzzardi@gmail.com>
This commit is contained in:
Andrea Luzzardi 2014-11-14 15:49:45 -08:00
parent 23fa208ab9
commit 006f5e7118
4 changed files with 117 additions and 0 deletions

View File

@ -0,0 +1,24 @@
package filter
import (
"github.com/docker/libcluster"
"github.com/samalba/dockerclient"
)
type Filter interface {
// Return a subset of nodes that were accepted by the filtering policy.
Filter(*dockerclient.ContainerConfig, []*libcluster.Node) ([]*libcluster.Node, error)
}
// Apply a set of filters in batch.
func ApplyFilters(filters []Filter, config *dockerclient.ContainerConfig, nodes []*libcluster.Node) ([]*libcluster.Node, error) {
var err error
for _, filter := range filters {
nodes, err = filter.Filter(config, nodes)
if err != nil {
return nil, err
}
}
return nodes, nil
}

62
scheduler/scheduler.go Normal file
View File

@ -0,0 +1,62 @@
package scheduler
import (
"sync"
"github.com/docker/libcluster"
"github.com/docker/libcluster/scheduler/filter"
"github.com/docker/libcluster/scheduler/strategy"
"github.com/samalba/dockerclient"
)
type Scheduler struct {
sync.Mutex
cluster *libcluster.Cluster
strategy strategy.PlacementStrategy
filters []filter.Filter
}
func NewScheduler(cluster *libcluster.Cluster) *Scheduler {
return &Scheduler{
cluster: cluster,
strategy: &strategy.RandomPlacementStrategy{},
filters: []filter.Filter{},
}
}
// Find a nice home for our container.
func (s *Scheduler) selectNodeForContainer(config *dockerclient.ContainerConfig) (*libcluster.Node, error) {
candidates := []*libcluster.Node{}
for _, node := range s.cluster.Nodes() {
candidates = append(candidates, node)
}
accepted, err := filter.ApplyFilters(s.filters, config, candidates)
if err != nil {
return nil, err
}
return s.strategy.PlaceContainer(config, accepted)
}
// Schedule a brand new container into the cluster.
func (s *Scheduler) CreateContainer(config *dockerclient.ContainerConfig, name string) (*libcluster.Container, error) {
s.Lock()
defer s.Unlock()
node, err := s.selectNodeForContainer(config)
if err != nil {
return nil, err
}
return node.Create(config, name, true)
}
// Remove a container from the cluster. Containers should always be destroyed
// through the scheduler to guarantee atomicity.
func (s *Scheduler) RemoveContainer(container *libcluster.Container, force bool) error {
s.Lock()
defer s.Unlock()
return container.Node().Remove(container, force)
}

View File

@ -0,0 +1,19 @@
package strategy
import (
"errors"
"github.com/docker/libcluster"
"github.com/samalba/dockerclient"
)
// Randomly place the container into the cluster.
type RandomPlacementStrategy struct {
}
func (p *RandomPlacementStrategy) PlaceContainer(config *dockerclient.ContainerConfig, nodes []*libcluster.Node) (*libcluster.Node, error) {
for _, node := range nodes {
return node, nil
}
return nil, errors.New("No nodes running in the cluster")
}

View File

@ -0,0 +1,12 @@
package strategy
import (
"github.com/docker/libcluster"
"github.com/samalba/dockerclient"
)
type PlacementStrategy interface {
// Given a container configuration and a set of nodes, select the target
// node where the container should be scheduled.
PlaceContainer(config *dockerclient.ContainerConfig, nodes []*libcluster.Node) (*libcluster.Node, error)
}