mirror of https://github.com/docker/docs.git
Merge branch 'JeffChien-discovery'
This commit is contained in:
commit
d27e8a35a1
|
@ -24,6 +24,6 @@ Docker Swarm Roadmap
|
|||
* [ ] Discovery backends
|
||||
* [x] etcd
|
||||
* [ ] zookeeper
|
||||
* [ ] consul
|
||||
* [x] consul
|
||||
* [x] hub
|
||||
* [x] file
|
||||
|
|
|
@ -78,6 +78,29 @@ $ swarm list --discovery etcd://<etcd_ip>/<path>
|
|||
http://<node_ip:2375>
|
||||
```
|
||||
|
||||
###### Using consul
|
||||
|
||||
```bash
|
||||
# on each of your nodes, start the swarm agent
|
||||
# <node_ip> doesn't have to be public (eg. 192.168.0.X),
|
||||
# as long as the other nodes can reach it, it is fine.
|
||||
$ swarm join --discovery consul://<consul_addr>/<path> --addr=<node_ip:2375>
|
||||
|
||||
# start the manager on any machine or your laptop
|
||||
$ swarm manage --discovery consul://<consul_addr>/<path> -H=<swarm_ip:swarm_port>
|
||||
|
||||
# use the regular docker cli
|
||||
$ docker -H <swarm_ip:swarm_port> info
|
||||
$ docker -H <swarm_ip:swarm_port> run ...
|
||||
$ docker -H <swarm_ip:swarm_port> ps
|
||||
$ docker -H <swarm_ip:swarm_port> logs ...
|
||||
...
|
||||
|
||||
# list nodes in your cluster
|
||||
$ swarm list --discovery consul://<consul_addr>/<path>
|
||||
http://<node_ip:2375>
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributing a new discovery backend is easy,
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
package consul
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
consul "github.com/armon/consul-api"
|
||||
"github.com/docker/swarm/discovery"
|
||||
)
|
||||
|
||||
type ConsulDiscoveryService struct {
|
||||
heartbeat time.Duration
|
||||
client *consul.Client
|
||||
prefix string
|
||||
lastIndex uint64
|
||||
}
|
||||
|
||||
func init() {
|
||||
discovery.Register("consul", &ConsulDiscoveryService{})
|
||||
}
|
||||
|
||||
func (s *ConsulDiscoveryService) Initialize(uris string, heartbeat int) error {
|
||||
parts := strings.SplitN(uris, "/", 2)
|
||||
if len(parts) < 2 {
|
||||
return errors.New("missing consul prefix")
|
||||
}
|
||||
addr := parts[0]
|
||||
path := parts[1]
|
||||
|
||||
config := consul.DefaultConfig()
|
||||
config.Address = addr
|
||||
|
||||
client, err := consul.NewClient(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.client = client
|
||||
s.heartbeat = time.Duration(heartbeat) * time.Second
|
||||
s.prefix = path + "/"
|
||||
kv := s.client.KV()
|
||||
p := &consul.KVPair{Key: s.prefix, Value: nil}
|
||||
if _, err = kv.Put(p, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
_, meta, err := kv.Get(s.prefix, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.lastIndex = meta.LastIndex
|
||||
return nil
|
||||
}
|
||||
func (s *ConsulDiscoveryService) Fetch() ([]*discovery.Node, error) {
|
||||
kv := s.client.KV()
|
||||
pairs, _, err := kv.List(s.prefix, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nodes []*discovery.Node
|
||||
|
||||
for _, pair := range pairs {
|
||||
if pair.Key == s.prefix {
|
||||
continue
|
||||
}
|
||||
nodes = append(nodes, discovery.NewNode(string(pair.Value)))
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
func (s *ConsulDiscoveryService) Watch(callback discovery.WatchCallback) {
|
||||
for _ = range s.waitForChange() {
|
||||
nodes, err := s.Fetch()
|
||||
if err == nil {
|
||||
callback(nodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConsulDiscoveryService) Register(addr string) error {
|
||||
kv := s.client.KV()
|
||||
p := &consul.KVPair{Key: path.Join(s.prefix, addr), Value: []byte(addr)}
|
||||
_, err := kv.Put(p, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *ConsulDiscoveryService) waitForChange() <-chan uint64 {
|
||||
c := make(chan uint64)
|
||||
go func() {
|
||||
for {
|
||||
kv := s.client.KV()
|
||||
option := &consul.QueryOptions{
|
||||
WaitIndex: s.lastIndex,
|
||||
WaitTime: s.heartbeat}
|
||||
_, meta, err := kv.List(s.prefix, option)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
break
|
||||
}
|
||||
s.lastIndex = meta.LastIndex
|
||||
c <- s.lastIndex
|
||||
}
|
||||
close(c)
|
||||
}()
|
||||
return c
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package consul
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestInitialize(t *testing.T) {
|
||||
discovery := &ConsulDiscoveryService{}
|
||||
discovery.Initialize("127.0.0.1:8500/path", 0)
|
||||
assert.Equal(t, discovery.prefix, "path/")
|
||||
}
|
2
flags.go
2
flags.go
|
@ -6,7 +6,7 @@ var (
|
|||
flDiscovery = cli.StringFlag{
|
||||
Name: "discovery",
|
||||
Value: "",
|
||||
Usage: "DiscoveryService to use [token://<token>, etcd://<ip1>,<ip2>/<path>, file://path/to/file]",
|
||||
Usage: "DiscoveryService to use [token://<token>, etcd://<ip1>,<ip2>/<path>, file://path/to/file, consul://<addr>/<path>]",
|
||||
EnvVar: "SWARM_DISCOVERY",
|
||||
}
|
||||
flAddr = cli.StringFlag{
|
||||
|
|
Loading…
Reference in New Issue