Support for running Docker on multiple hosts, with autoscaling capabilities and pluggable scheduling algorithms.
For more details on the API, check the Docker remote API docs.
Go library for clustering support on Docker.
Home Page: http://godoc.org/github.com/tsuru/docker-cluster
License: BSD 3-Clause "New" or "Revised" License
Support for running Docker on multiple hosts, with autoscaling capabilities and pluggable scheduling algorithms.
For more details on the API, check the Docker remote API docs.
detected from an internal tsuru's CI:
==================
WARNING: DATA RACE
Read by goroutine 69:
github.com/tsuru/docker-cluster/cluster.(*roundRobin).Schedule()
/tmp/gopath/tsuru/src/github.com/tsuru/docker-cluster/cluster/scheduler.go:43 +0x21c
github.com/tsuru/docker-cluster/cluster.(*Cluster).CreateContainerSchedulerOpts()
/tmp/gopath/tsuru/src/github.com/tsuru/docker-cluster/cluster/container.go:35 +0x159
github.com/tsuru/tsuru/provision/docker.(*container).create()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/docker.go:212 +0xd2f
github.com/tsuru/tsuru/provision/docker.func·005()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions.go:90 +0x377
github.com/tsuru/tsuru/action.(*Pipeline).Execute()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/action/action.go:133 +0x745
github.com/tsuru/tsuru/provision/docker.start()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/docker.go:346 +0x4ec
github.com/tsuru/tsuru/provision/docker.func·027()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/provisioner.go:234 +0x152
Previous write by goroutine 124:
github.com/tsuru/docker-cluster/cluster.(*roundRobin).Schedule()
/tmp/gopath/tsuru/src/github.com/tsuru/docker-cluster/cluster/scheduler.go:44 +0x23c
github.com/tsuru/docker-cluster/cluster.(*Cluster).CreateContainerSchedulerOpts()
/tmp/gopath/tsuru/src/github.com/tsuru/docker-cluster/cluster/container.go:35 +0x159
github.com/tsuru/tsuru/provision/docker.(*container).create()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/docker.go:212 +0xd2f
github.com/tsuru/tsuru/provision/docker.func·005()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions.go:90 +0x377
github.com/tsuru/tsuru/action.(*Pipeline).Execute()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/action/action.go:133 +0x745
github.com/tsuru/tsuru/provision/docker.start()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/docker.go:346 +0x4ec
github.com/tsuru/tsuru/provision/docker.func·027()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/provisioner.go:234 +0x152
Goroutine 69 (running) created at:
github.com/tsuru/tsuru/provision/docker.addContainersWithHost()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/provisioner.go:240 +0x7b4
github.com/tsuru/tsuru/provision/docker.func·010()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions.go:150 +0x208
github.com/tsuru/tsuru/provision/docker.(*S).TestProvisionAddUnitsToHostForwardWithoutHost()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions_test.go:386 +0x751
runtime.call16()
/var/lib/jenkins/go/src/pkg/runtime/asm_amd64.s:360 +0x31
reflect.Value.Call()
/var/lib/jenkins/go/src/pkg/reflect/value.go:411 +0xed
launchpad.net/gocheck.func·006()
/tmp/gopath/tsuru/src/launchpad.net/gocheck/gocheck.go:733 +0x51b
launchpad.net/gocheck.func·004()
/tmp/gopath/tsuru/src/launchpad.net/gocheck/gocheck.go:628 +0xf4
Goroutine 124 (running) created at:
github.com/tsuru/tsuru/provision/docker.addContainersWithHost()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/provisioner.go:240 +0x7b4
github.com/tsuru/tsuru/provision/docker.func·010()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions.go:150 +0x208
github.com/tsuru/tsuru/provision/docker.(*S).TestProvisionAddUnitsToHostForwardWithoutHost()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions_test.go:386 +0x751
runtime.call16()
/var/lib/jenkins/go/src/pkg/runtime/asm_amd64.s:360 +0x31
reflect.Value.Call()
/var/lib/jenkins/go/src/pkg/reflect/value.go:411 +0xed
launchpad.net/gocheck.func·006()
/tmp/gopath/tsuru/src/launchpad.net/gocheck/gocheck.go:733 +0x51b
launchpad.net/gocheck.func·004()
/tmp/gopath/tsuru/src/launchpad.net/gocheck/gocheck.go:628 +0xf4
==================
==================
WARNING: DATA RACE
Read by goroutine 69:
github.com/tsuru/docker-cluster/cluster.(*roundRobin).Schedule()
/tmp/gopath/tsuru/src/github.com/tsuru/docker-cluster/cluster/scheduler.go:47 +0x270
github.com/tsuru/docker-cluster/cluster.(*Cluster).CreateContainerSchedulerOpts()
/tmp/gopath/tsuru/src/github.com/tsuru/docker-cluster/cluster/container.go:35 +0x159
github.com/tsuru/tsuru/provision/docker.(*container).create()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/docker.go:212 +0xd2f
github.com/tsuru/tsuru/provision/docker.func·005()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions.go:90 +0x377
github.com/tsuru/tsuru/action.(*Pipeline).Execute()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/action/action.go:133 +0x745
github.com/tsuru/tsuru/provision/docker.start()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/docker.go:346 +0x4ec
github.com/tsuru/tsuru/provision/docker.func·027()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/provisioner.go:234 +0x152
Previous write by goroutine 124:
github.com/tsuru/docker-cluster/cluster.(*roundRobin).Schedule()
/tmp/gopath/tsuru/src/github.com/tsuru/docker-cluster/cluster/scheduler.go:45 +0x258
github.com/tsuru/docker-cluster/cluster.(*Cluster).CreateContainerSchedulerOpts()
/tmp/gopath/tsuru/src/github.com/tsuru/docker-cluster/cluster/container.go:35 +0x159
github.com/tsuru/tsuru/provision/docker.(*container).create()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/docker.go:212 +0xd2f
github.com/tsuru/tsuru/provision/docker.func·005()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions.go:90 +0x377
github.com/tsuru/tsuru/action.(*Pipeline).Execute()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/action/action.go:133 +0x745
github.com/tsuru/tsuru/provision/docker.start()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/docker.go:346 +0x4ec
github.com/tsuru/tsuru/provision/docker.func·027()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/provisioner.go:234 +0x152
Goroutine 69 (running) created at:
github.com/tsuru/tsuru/provision/docker.addContainersWithHost()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/provisioner.go:240 +0x7b4
github.com/tsuru/tsuru/provision/docker.func·010()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions.go:150 +0x208
github.com/tsuru/tsuru/provision/docker.(*S).TestProvisionAddUnitsToHostForwardWithoutHost()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions_test.go:386 +0x751
runtime.call16()
/var/lib/jenkins/go/src/pkg/runtime/asm_amd64.s:360 +0x31
reflect.Value.Call()
/var/lib/jenkins/go/src/pkg/reflect/value.go:411 +0xed
launchpad.net/gocheck.func·006()
/tmp/gopath/tsuru/src/launchpad.net/gocheck/gocheck.go:733 +0x51b
launchpad.net/gocheck.func·004()
/tmp/gopath/tsuru/src/launchpad.net/gocheck/gocheck.go:628 +0xf4
Goroutine 124 (running) created at:
github.com/tsuru/tsuru/provision/docker.addContainersWithHost()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/provisioner.go:240 +0x7b4
github.com/tsuru/tsuru/provision/docker.func·010()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions.go:150 +0x208
github.com/tsuru/tsuru/provision/docker.(*S).TestProvisionAddUnitsToHostForwardWithoutHost()
/tmp/gopath/tsuru/src/github.com/tsuru/tsuru/provision/docker/actions_test.go:386 +0x751
runtime.call16()
/var/lib/jenkins/go/src/pkg/runtime/asm_amd64.s:360 +0x31
reflect.Value.Call()
/var/lib/jenkins/go/src/pkg/reflect/value.go:411 +0xed
launchpad.net/gocheck.func·006()
/tmp/gopath/tsuru/src/launchpad.net/gocheck/gocheck.go:733 +0x51b
launchpad.net/gocheck.func·004()
/tmp/gopath/tsuru/src/launchpad.net/gocheck/gocheck.go:628 +0xf4
==================
We can keep the panic, but use a custom error message,
When removing a node from the cluster it should remove it from the image host list
The shortened urls are like that:
http://docs.docker.io/en/latest/api/docker_remote_api/#list-containers
But the anchor stopped working, now the url must have the api version
e.g: http://docs.docker.io/en/latest/api/docker_remote_api_v1.4/#list-containers
Automatically handle errors on nodes. When an error happen it should try another node and move the node to some kind of quarantine zone.
The cluster should try to use nodes on quarantine for some time. After a number of errors a recovery process should be started, possibly spawning a new node and moving containers from one node to another.
The recovery process should be handled by the client implementing some kind of Recovery interface provided by the Cluster
I see that this project implements two libraries but no daemons or command line tools. Are there any examples of this in use?
Image commit should remove all hosts from storage image list
Related to tsuru/tsuru#848
docker-cluster should have a daemon, that implements the Docker API, so we will be able to use the docker client to manage Docker clusters, and even use a Docker cluster as a node in another cluster.
Returning a map breaks round robin. We need to return a slice.
Related to tsuru/tsuru#848
Scheduler will be an interface representing the scheduling strategy used by a cluster. It will be immutable in the cluster. The interface would look like this:
type Scheduler interface {
Schedule(config *docker.Config) (string, *docker.Container, error)
Register(nodes ...Node) error
}
Then the function New
would receive the scheduler instance, using a default implementation (round robin strategy).
Storage will be an interface that will store information about containers. This is how the interface may look like
type Storage interface {
Store(containerID, hostID string) error
Retrieve(containerID string) (hostID string, err error)
}
A naive implementation using maps would look like this (untested):
type MapStorage struct {
m map[string]string
mutex sync.Mutex
}
func (s *MapStorage) Store(containerID, hostID string) error {
s.mutex.Lock()
s.m[containerID] = hostID
s.mutex.Unlock()
return nil
}
func (s *MapStorage) Retrieve(containerID string) (string, error) {
s.mutex.Lock()
defer s.mutex.Unlock()
host, ok := s.m[containerID]
if !ok {
return "", errors.New("No such container")
}
return host, nil
}
This function gives the wrong impression that it retrieves the container, while it retrieves it's host.
currently, cluster try to remove an image in all nodes. it is very slow when we have many nodes.
Each node will have a quota of "available" containers. Whenever the cluster runs out of containers, it should fail to create new containers.
I think we could provide a package that export some fake types, as a fake scheduler and (possibly) fake storage.
Thoughts?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.