Service discovery

Add a minimal service discover support using service names or
service names qualified with network name. This is achieved
by populating the container's /etc/hosts file record with the
appropriate entries

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2015-06-18 23:40:17 -07:00
parent 362568467d
commit 271bcd7ba1
3 changed files with 100 additions and 0 deletions

View File

@ -284,6 +284,7 @@ func (c *controller) addNetwork(n *network) error {
} }
n.Lock() n.Lock()
n.svcRecords = svcMap{}
n.driver = dd.driver n.driver = dd.driver
d := n.driver d := n.driver
n.Unlock() n.Unlock()

View File

@ -571,9 +571,39 @@ func (ep *endpoint) deleteEndpoint() error {
} }
log.Warnf("driver error deleting endpoint %s : %v", name, err) log.Warnf("driver error deleting endpoint %s : %v", name, err)
} }
n.updateSvcRecord(ep, false)
return nil return nil
} }
func (ep *endpoint) addHostEntries(recs []etchosts.Record) {
ep.Lock()
container := ep.container
ep.Unlock()
if container == nil {
return
}
if err := etchosts.Add(container.config.hostsPath, recs); err != nil {
log.Warnf("Failed adding service host entries to the running container: %v", err)
}
}
func (ep *endpoint) deleteHostEntries(recs []etchosts.Record) {
ep.Lock()
container := ep.container
ep.Unlock()
if container == nil {
return
}
if err := etchosts.Delete(container.config.hostsPath, recs); err != nil {
log.Warnf("Failed deleting service host entries to the running container: %v", err)
}
}
func (ep *endpoint) buildHostsFiles() error { func (ep *endpoint) buildHostsFiles() error {
var extraContent []etchosts.Record var extraContent []etchosts.Record
@ -581,6 +611,7 @@ func (ep *endpoint) buildHostsFiles() error {
container := ep.container container := ep.container
joinInfo := ep.joinInfo joinInfo := ep.joinInfo
ifaces := ep.iFaces ifaces := ep.iFaces
n := ep.network
ep.Unlock() ep.Unlock()
if container == nil { if container == nil {
@ -613,6 +644,8 @@ func (ep *endpoint) buildHostsFiles() error {
etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP}) etchosts.Record{Hosts: extraHost.name, IP: extraHost.IP})
} }
extraContent = append(extraContent, n.getSvcRecords()...)
IP := "" IP := ""
if len(ifaces) != 0 && ifaces[0] != nil { if len(ifaces) != 0 && ifaces[0] != nil {
IP = ifaces[0].addr.IP.String() IP = ifaces[0].addr.IP.String()

View File

@ -2,6 +2,7 @@ package libnetwork
import ( import (
"encoding/json" "encoding/json"
"net"
"sync" "sync"
log "github.com/Sirupsen/logrus" log "github.com/Sirupsen/logrus"
@ -9,6 +10,7 @@ import (
"github.com/docker/libnetwork/config" "github.com/docker/libnetwork/config"
"github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/datastore"
"github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/etchosts"
"github.com/docker/libnetwork/netlabel" "github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/options" "github.com/docker/libnetwork/options"
"github.com/docker/libnetwork/types" "github.com/docker/libnetwork/types"
@ -51,6 +53,8 @@ type Network interface {
// When the function returns true, the walk will stop. // When the function returns true, the walk will stop.
type EndpointWalker func(ep Endpoint) bool type EndpointWalker func(ep Endpoint) bool
type svcMap map[string]net.IP
type network struct { type network struct {
ctrlr *controller ctrlr *controller
name string name string
@ -62,6 +66,7 @@ type network struct {
endpoints endpointTable endpoints endpointTable
generic options.Generic generic options.Generic
dbIndex uint64 dbIndex uint64
svcRecords svcMap
stopWatchCh chan struct{} stopWatchCh chan struct{}
sync.Mutex sync.Mutex
} }
@ -272,6 +277,8 @@ func (n *network) addEndpoint(ep *endpoint) error {
if err != nil { if err != nil {
return err return err
} }
n.updateSvcRecord(ep, true)
return nil return nil
} }
@ -384,3 +391,62 @@ func (n *network) isGlobalScoped() (bool, error) {
n.Unlock() n.Unlock()
return c.isDriverGlobalScoped(n.networkType) return c.isDriverGlobalScoped(n.networkType)
} }
func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) {
n.Lock()
var recs []etchosts.Record
for _, iface := range ep.InterfaceList() {
if isAdd {
n.svcRecords[ep.Name()] = iface.Address().IP
n.svcRecords[ep.Name()+"."+n.name] = iface.Address().IP
} else {
delete(n.svcRecords, ep.Name())
delete(n.svcRecords, ep.Name()+"."+n.name)
}
recs = append(recs, etchosts.Record{
Hosts: ep.Name(),
IP: iface.Address().IP.String(),
})
recs = append(recs, etchosts.Record{
Hosts: ep.Name() + "." + n.name,
IP: iface.Address().IP.String(),
})
}
n.Unlock()
var epList []*endpoint
n.WalkEndpoints(func(e Endpoint) bool {
cEp := e.(*endpoint)
cEp.Lock()
if cEp.container != nil {
epList = append(epList, cEp)
}
cEp.Unlock()
return false
})
for _, cEp := range epList {
if isAdd {
cEp.addHostEntries(recs)
} else {
cEp.deleteHostEntries(recs)
}
}
}
func (n *network) getSvcRecords() []etchosts.Record {
n.Lock()
defer n.Unlock()
var recs []etchosts.Record
for h, ip := range n.svcRecords {
recs = append(recs, etchosts.Record{
Hosts: h,
IP: ip.String(),
})
}
return recs
}