Do network attach on docker event rather than intercepting start and restart commands.

This means it also works when the docker daemon restarts a container.
This commit is contained in:
Bryan Boreham committed 2015-09-01 17:48:12 +01:00
1 parent 5c3efbdca0
commit 81e8ba223f
6 files changed
+76 -55

No files matched your search

+20 -2
View File
@@ -7,6 +7,7 @@ import (
// An observer for container events
type ContainerObserver interface {
ContainerStarted(ident string)
ContainerDied(ident string)
}
@@ -22,12 +23,26 @@ func NewClient(apiPath string) (*Client, error) {
}
client := &Client{dc}
env, err := client.Version()
return client, client.checkWorking(apiPath)
}
func NewVersionedClient(apiPath string, apiVersionString string) (*Client, error) {
dc, err := docker.NewVersionedClient(apiPath, apiVersionString)
if err != nil {
return nil, err
}
client := &Client{dc}
return client, client.checkWorking(apiPath)
}
func (c *Client) checkWorking(apiPath string) error {
env, err := c.Version()
if err != nil {
return err
}
Log.Infof("[docker] Using Docker API on %s: %v", apiPath, env)
return client, nil
return nil
}
// AddObserver adds an observer for docker events
@@ -41,6 +56,9 @@ func (c *Client) AddObserver(ob ContainerObserver) error {
go func() {
for event := range events {
switch event.Status {
case "start":
id := event.ID
ob.ContainerStarted(id)
case "die":
id := event.ID
ob.ContainerDied(id)
+2
View File
@@ -226,6 +226,8 @@ func (alloc *Allocator) ContainerDied(ident string) {
}
}
func (alloc *Allocator) ContainerStarted(ident string) {}
// Delete (Sync) - release all IP addresses for container with given name
func (alloc *Allocator) Delete(ident string) error {
errChan := make(chan error)
+2
View File
@@ -130,6 +130,8 @@ func (n *Nameserver) ReverseLookup(ip address.Address) (string, error) {
return match.Hostname, nil
}
func (n *Nameserver) ContainerStarted(ident string) {}
func (n *Nameserver) ContainerDied(ident string) {
n.Lock()
entries := n.entries.tombstone(n.ourName, func(e *Entry) bool {
+45 -6
View File
@@ -11,8 +11,9 @@ import (
"strings"
"syscall"
"github.com/fsouza/go-dockerclient"
docker "github.com/fsouza/go-dockerclient"
. "github.com/weaveworks/weave/common"
weavedocker "github.com/weaveworks/weave/common/docker"
)
const (
@@ -25,7 +26,6 @@ const (
var (
containerCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/create$")
containerStartRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/(re)?start$")
execCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/exec$")
ErrWeaveCIDRNone = errors.New("the container was created with the '-e WEAVE_CIDR=none' option")
@@ -64,11 +64,11 @@ func NewProxy(c Config) (*Proxy, error) {
// to insulate ourselves from breaking changes to the API, as
// happened in 1.20 (Docker 1.8.0) when the presentation of
// volumes changed in `inspect`.
client, err := docker.NewVersionedClient(dockerSockUnix, "1.15")
client, err := weavedocker.NewVersionedClient(dockerSockUnix, "1.15")
if err != nil {
return nil, err
}
p.client = client
p.client = client.Client
if !p.WithoutDNS {
dockerBridgeIP, stderr, err := callWeave("docker-bridge-ip")
@@ -88,6 +88,8 @@ func NewProxy(c Config) (*Proxy, error) {
return nil, err
}
client.AddObserver(p)
return p, nil
}
@@ -121,8 +123,6 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch {
case containerCreateRegexp.MatchString(path):
i = &createContainerInterceptor{proxy}
case containerStartRegexp.MatchString(path):
i = &startContainerInterceptor{proxy}
case execCreateRegexp.MatchString(path):
i = &createExecInterceptor{proxy}
default:
@@ -224,6 +224,45 @@ func (proxy *Proxy) listen(protoAndAddr string) (net.Listener, string, error) {
return listener, fmt.Sprintf("%s://%s", proto, addr), nil
}
// weavedocker.ContainerObserver interface
func (proxy *Proxy) ContainerStarted(ident string) {
container, err := proxy.client.InspectContainer(ident)
if err != nil {
Log.Warningf("Error inspecting container %s: %v", ident, err)
return
}
// If this was a container we modified the entrypoint for, attach it to the network
if len(container.Config.Entrypoint) > 0 && container.Config.Entrypoint[0] == weaveWaitEntrypoint[0] {
proxy.attach(container)
}
}
func (proxy *Proxy) ContainerDied(ident string) {
}
func (proxy *Proxy) attach(container *docker.Container) error {
cidrs, err := proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig)
if err != nil {
Log.Infof("Leaving container %s alone because %s", container.ID, err)
return nil
}
Log.Infof("Attaching container %s with WEAVE_CIDR \"%s\" to weave network", container.ID, strings.Join(cidrs, " "))
args := []string{"attach"}
args = append(args, cidrs...)
if !proxy.NoRewriteHosts {
args = append(args, "--rewrite-hosts")
}
args = append(args, "--or-die", container.ID)
if _, stderr, err := callWeave(args...); err != nil {
Log.Warningf("Attaching container %s to weave network failed: %s", container.ID, string(stderr))
return errors.New(string(stderr))
} else if len(stderr) > 0 {
Log.Warningf("Attaching container %s to weave network: %s", container.ID, string(stderr))
}
return nil
}
func (proxy *Proxy) weaveCIDRsFromConfig(config *docker.Config, hostConfig *docker.HostConfig) ([]string, error) {
netMode := ""
if hostConfig != nil {
-47
View File
@@ -1,47 +0,0 @@
package proxy
import (
"errors"
"net/http"
"strings"
. "github.com/weaveworks/weave/common"
)
type startContainerInterceptor struct{ proxy *Proxy }
func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
return nil
}
func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error {
if r.StatusCode < 200 || r.StatusCode >= 300 { // Docker didn't do the start
return nil
}
container, err := inspectContainerInPath(i.proxy.client, r.Request.URL.Path)
if err != nil {
return err
}
cidrs, err := i.proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig)
if err != nil {
Log.Infof("Leaving container %s alone because %s", container.ID, err)
return nil
}
Log.Infof("Attaching container %s with WEAVE_CIDR \"%s\" to weave network", container.ID, strings.Join(cidrs, " "))
args := []string{"attach"}
args = append(args, cidrs...)
if !i.proxy.NoRewriteHosts {
args = append(args, "--rewrite-hosts")
}
args = append(args, "--or-die", container.ID)
if _, stderr, err := callWeave(args...); err != nil {
Log.Warningf("Attaching container %s to weave network failed: %s", container.ID, string(stderr))
return errors.New(string(stderr))
} else if len(stderr) > 0 {
Log.Warningf("Attaching container %s to weave network: %s", container.ID, string(stderr))
}
return nil
}
+7
View File
@@ -64,6 +64,10 @@ or
[remote API](https://docs.docker.com/reference/api/docker_remote_api/)
are attached to the weave network before they begin execution.
Containers started in this way that subsequently restart, either by an
explicit `docker restart` command or by Docker restart policy, are
re-attached to the weave network by the weave Docker API proxy.
### <a name="addressing"></a>Address allocation
Containers are automatically allocated an IP address that is unique
@@ -248,6 +252,9 @@ invocation:
host1$ weave detach net:default net:10.2.2.0/24 net:10.2.3.0/24 $C
10.2.1.3 10.2.2.3 10.2.3.1
Note that addresses added by dynamic attachment are not re-attached
if the container restarts.
### <a name="security"></a>Security
In order to connect containers across untrusted networks, weave peers