Permalink
Browse files

Initial basic zookeeper backend for registrator

  • Loading branch information...
jmeichle committed Mar 28, 2015
1 parent ed771ac commit ed13635c5a374ad4a2e9e790c2b8e8d236cd5384
Showing with 136 additions and 0 deletions.
  1. +1 −0 CHANGELOG.md
  2. +19 −0 docs/user/backends.md
  3. +1 −0 modules.go
  4. +115 −0 zookeeper/zookeeper.go
View
@@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file.
- Panic from invalid skydns2 URI.
### Added
- Basic zookeeper adapter
- Optional periodic resyncing of services from containers
- More error logging for registries
- Support for services on containers with `--net=host`
View
@@ -104,3 +104,22 @@ SkyDNS requires the service ID to be a valid DNS hostname, so this backend requi
override service ID to a valid DNS name. Example:
$ docker run -d --name redis-1 -e SERVICE_ID=redis-1 -p 6379:6379 redis
## Zookeeper Store
The Zookeeper backend lets you publish ephemeral znodes into zookeeper. This mode is enabled by specifying a zookeeper path. The zookeeper backend supports publishing a json znode body complete with defined service attributes/tags as well as the service name and container id. Example URIs:
$ registrator zookeeper://zookeeper.host/basepath
$ registrator zookeeper://192.168.1.100:9999/basepath
Within the base path specified in the zookeeper URI, registrator will create the following path tree containing a JSON entry for the service:
<service-name>/<service-port> = <JSON>
The JSON will contain all infromation about the published container service. As an example, the following container start:
docker run -i -p 80 -e 'SERVICE_80_NAME=www' -t ubuntu:14.04 /bin/bash
Will result in the zookeeper path and JSON znode body:
/basepath/www/80 = {"Name":"www","IP":"192.168.1.123","PublicPort":49153,"PrivatePort":80,"ContainerID":"9124853ff0d1","Tags":[],"Attrs":{}}
View
@@ -5,4 +5,5 @@ import (
_ "github.com/gliderlabs/registrator/consulkv"
_ "github.com/gliderlabs/registrator/etcd"
_ "github.com/gliderlabs/registrator/skydns2"
_ "github.com/gliderlabs/registrator/zookeeper"
)
View
@@ -0,0 +1,115 @@
package zookeeper
import (
"encoding/json"
"log"
"net/url"
"strconv"
"time"
"github.com/gliderlabs/registrator/bridge"
"github.com/samuel/go-zookeeper/zk"
)
func init() {
bridge.Register(new(Factory), "zookeeper")
}
type Factory struct{}
func (f *Factory) New(uri *url.URL) bridge.RegistryAdapter {
c, _, err := zk.Connect([]string{uri.Host}, (time.Second * 10))
if err != nil {
panic(err)
}
exists, _, err := c.Exists(uri.Path)
if err != nil {
log.Println("zookeeper: error checking if base path exists:", err)
}
if !exists {
c.Create(uri.Path, []byte{}, 0, zk.WorldACL(zk.PermAll))
}
return &ZkAdapter{client: c, path: uri.Path}
}
type ZkAdapter struct {
client *zk.Conn
path string
}
type ZnodeBody struct {
Name string
IP string
PublicPort int
PrivatePort int
ContainerID string
Tags []string
Attrs map[string]string
}
func (r *ZkAdapter) Register(service *bridge.Service) error {
privatePort, _ := strconv.Atoi(service.Origin.ExposedPort)
acl := zk.WorldACL(zk.PermAll)
exists, _, err := r.client.Exists(r.path + "/" + service.Name)
if err != nil {
log.Println("zookeeper: error checking if exists: ", err)
} else {
if !exists {
_, err := r.client.Create(r.path+"/"+service.Name, []byte{}, 0, acl)
if err != nil {
log.Println("zookeeper: failed to create base service node: ", err)
} else {
zbody := &ZnodeBody{Name: service.Name, IP: service.IP, PublicPort: service.Port, PrivatePort: privatePort, Tags: service.Tags, Attrs: service.Attrs, ContainerID: service.Origin.ContainerHostname}
body, err := json.Marshal(zbody)
if err != nil {
log.Println("zookeeper: failed to json encode service body: ", err)
} else {
path := r.path + "/" + service.Name + "/" + service.Origin.ExposedPort
_, err = r.client.Create(path, body, 1, acl)
if err != nil {
log.Println("zookeeper: failed to register service: ", err)
}
} // json encode error check
} // create service path error check
} // service path exists
} // service path exists error check
return err
}
func (r *ZkAdapter) Ping() error {
_, _, err := r.client.Exists("/")
if err != nil {
log.Println("zookeeper: error on ping check for Exists(/): ", err)
return err
}
return nil
}
func (r *ZkAdapter) Deregister(service *bridge.Service) error {
basePath := r.path + "/" + service.Name
// Delete the service-port znode
servicePortPath := basePath + "/" + service.Origin.ExposedPort
err := r.client.Delete(servicePortPath, -1) // -1 means latest version number
if err != nil {
log.Println("zookeeper: failed to deregister service port entry: ", err)
}
// Check if all service-port znodes are removed.
children, _, err := r.client.Children(basePath)
if len(children) == 0 {
// Delete the service name znode
err := r.client.Delete(basePath, -1)
if err != nil {
log.Println("zookeeper: failed to delete service path: ", err)
}
}
return err
}
func (r *ZkAdapter) Refresh(service *bridge.Service) error {
return r.Register(service)
}
func (r *ZkAdapter) Services() ([]*bridge.Service, error) {
return []*bridge.Service{}, nil
}

0 comments on commit ed13635

Please sign in to comment.