From 82407e505e5768bbd97e3474b51201d49648ed2a Mon Sep 17 00:00:00 2001 From: Everett Toews Date: Thu, 31 Mar 2016 20:03:32 -0500 Subject: [PATCH 1/2] Multi-interlock config --- .gitignore | 1 + config/config.go | 1 + docs/configuration.md | 1 + docs/interlock_data.md | 25 ++++++++++++++++++++++++ ext/ext.go | 1 + ext/lb/lb.go | 43 ++++++++++++++++++++++++++++++++---------- server/server.go | 9 ++++++++- 7 files changed, 70 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index ae67f0b0..90cf4148 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ +.config interlock/interlock *.swp diff --git a/config/config.go b/config/config.go index ebe627d8..39000f8d 100644 --- a/config/config.go +++ b/config/config.go @@ -11,6 +11,7 @@ type Rule struct { // the extension itself will use whichever options needed type ExtensionConfig struct { Name string // extension name + ServiceName string // service name ConfigPath string // config file path ConfigBasePath string `toml:"-"` // internal PidPath string // haproxy, nginx diff --git a/docs/configuration.md b/docs/configuration.md index c74dc5b5..7062e4ee 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -52,6 +52,7 @@ they are compatible: |Option|Type|Extensions Supported| |----|----|----| |Name | string | extension name | +|ServiceName | string | service name | |ConfigPath | string | config file path | |PidPath | string | haproxy, nginx | |BackendOverrideAddress | string | haproxy, nginx | diff --git a/docs/interlock_data.md b/docs/interlock_data.md index d0c810fe..3e602eda 100644 --- a/docs/interlock_data.md +++ b/docs/interlock_data.md @@ -9,6 +9,7 @@ compatibility. |Label|Extensions Supported| |----|----| |`interlock.ext.name` | internal | +|`interlock.ext.service.name` | internal | |`interlock.hostname` | haproxy, nginx| |`interlock.domain` | haproxy, nginx| |`interlock.ssl` | nginx| @@ -27,6 +28,30 @@ compatibility. |`interlock.balance_algorithm` | haproxy| |`interlock.backend_option` | haproxy| +# Service Name +To have Interlock work with multiple independent services, run the Interlock +container with the `interlock.ext.service.name` label. This will cause it to +only manage the load balancer and all application service containers with the +same label. For example: + +``` +docker run -d -p 8080:8080 \ + --name interlock_foo \ + --label interlock.ext.service.name=foo \ + ehazlett/interlock:1.2.0 \ + -D run -c /etc/interlock/config.toml + +docker run -d -p 80:80 \ + --name nginx_foo \ + --label interlock.ext.name=nginx \ + --label interlock.ext.service.name=foo \ + nginx + +docker run -d -P \ + --label interlock.ext.service.name=foo \ + ehazlett/docker-demo +``` + # Port If an upstream container uses multiple ports you can select the port for the proxy to use by specifying the following label: `interlock.port=8080`. diff --git a/ext/ext.go b/ext/ext.go index 11181528..70d3ba16 100644 --- a/ext/ext.go +++ b/ext/ext.go @@ -7,6 +7,7 @@ import ( const ( InterlockAppLabel = "interlock.app" // internal InterlockExtNameLabel = "interlock.ext.name" // common + InterlockExtServiceNameLabel = "interlock.ext.service.name" // common InterlockHostnameLabel = "interlock.hostname" // haproxy, nginx InterlockNetworkLabel = "interlock.network" // common InterlockDomainLabel = "interlock.domain" // haproxy, nginx diff --git a/ext/lb/lb.go b/ext/lb/lb.go index 08791816..a30945a9 100644 --- a/ext/lb/lb.go +++ b/ext/lb/lb.go @@ -182,7 +182,8 @@ func NewLoadBalancer(c *config.ExtensionConfig, client *dockerclient.DockerClien log().Debug("updating load balancers") - containers, err := client.ListContainers(true, false, "") + containers, err := extension.ListContainers() + if err != nil { errChan <- err continue @@ -202,7 +203,7 @@ func NewLoadBalancer(c *config.ExtensionConfig, client *dockerclient.DockerClien proxyNetworks := map[string]string{} - proxyContainers, err := extension.ProxyContainers(extension.backend.Name()) + proxyContainers, err := extension.ProxyContainers(extension.backend.Name(), containers) if err != nil { errChan <- err continue @@ -298,12 +299,27 @@ func (l *LoadBalancer) Name() string { return pluginName } -func (l *LoadBalancer) ProxyContainers(name string) ([]dockerclient.Container, error) { - containers, err := l.client.ListContainers(false, false, "") + +func (l *LoadBalancer) ListContainers() ([]dockerclient.Container, error) { + var containers []dockerclient.Container + var err error + + allContainers, err := l.client.ListContainers(false, false, "") + if err != nil { return nil, err } + for _, cnt := range allContainers { + if l.isServiceContainer(cnt.Labels) { + containers = append(containers, cnt) + } + } + + return containers, nil +} + +func (l *LoadBalancer) ProxyContainers(name string, containers []dockerclient.Container) ([]dockerclient.Container, error) { proxyContainers := []dockerclient.Container{} // find interlock proxy containers @@ -461,10 +477,8 @@ func (l *LoadBalancer) isExposedContainer(id string) bool { return false } - log().Debugf("checking container labels: id=%s", id) - // ignore proxy containers - if _, ok := c.Config.Labels[ext.InterlockExtNameLabel]; ok { - log().Debugf("ignoring proxy container: id=%s", id) + if !l.isServiceContainer(c.Config.Labels) { + log().Debugf("ignoring service container: id=%s labels=%s", id, c.Config.Labels) return false } @@ -473,8 +487,6 @@ func (l *LoadBalancer) isExposedContainer(id string) bool { return false } - log().Debugf("checking container ports: id=%s", id) - // ignore containers without exposed ports if len(c.Config.ExposedPorts) == 0 { log().Debugf("no ports exposed; ignoring: id=%s", id) return false @@ -483,3 +495,14 @@ func (l *LoadBalancer) isExposedContainer(id string) bool { log().Debugf("container is monitored; triggering reload: id=%s", id) return true } + +func (l *LoadBalancer) isServiceContainer(labels map[string]string) bool { + containerServiceName, labelled := labels[ext.InterlockExtServiceNameLabel] + + if (len(l.cfg.ServiceName) > 0 && containerServiceName == l.cfg.ServiceName) || + (len(l.cfg.ServiceName) == 0 && !labelled) { + return true + } else { + return false + } +} diff --git a/server/server.go b/server/server.go index e29474f9..941d509d 100644 --- a/server/server.go +++ b/server/server.go @@ -13,6 +13,7 @@ import ( "github.com/ehazlett/interlock/ext/lb" "github.com/prometheus/client_golang/prometheus" "github.com/samalba/dockerclient" + "fmt" ) type Server struct { @@ -165,7 +166,13 @@ func (s *Server) waitForSwarm() { func (s *Server) loadExtensions(client *dockerclient.DockerClient) { for _, x := range s.cfg.Extensions { - log.Debugf("loading extension: name=%s", x.Name) + loadingMsg := fmt.Sprintf("loading extension: name=%s", x.Name) + if len(x.ServiceName) > 0 { + loadingMsg = fmt.Sprintf("%s serviceName=%s", loadingMsg, x.ServiceName) + } + + log.Debugf(loadingMsg) + switch strings.ToLower(x.Name) { case "haproxy", "nginx": p, err := lb.NewLoadBalancer(x, client) From a8eb04a3eca58f773d6434dfc147e76f53bce0d9 Mon Sep 17 00:00:00 2001 From: Everett Toews Date: Thu, 28 Apr 2016 16:43:30 -0500 Subject: [PATCH 2/2] Addressed PR comments --- docs/interlock_data.md | 10 +++++----- ext/ext.go | 2 +- ext/lb/lb.go | 20 +++++++++++++++----- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/docs/interlock_data.md b/docs/interlock_data.md index 3e602eda..e5222107 100644 --- a/docs/interlock_data.md +++ b/docs/interlock_data.md @@ -9,7 +9,7 @@ compatibility. |Label|Extensions Supported| |----|----| |`interlock.ext.name` | internal | -|`interlock.ext.service.name` | internal | +|`interlock.ext.service_name` | internal | |`interlock.hostname` | haproxy, nginx| |`interlock.domain` | haproxy, nginx| |`interlock.ssl` | nginx| @@ -30,25 +30,25 @@ compatibility. # Service Name To have Interlock work with multiple independent services, run the Interlock -container with the `interlock.ext.service.name` label. This will cause it to +container with the `interlock.ext.service_name` label. This will cause it to only manage the load balancer and all application service containers with the same label. For example: ``` docker run -d -p 8080:8080 \ --name interlock_foo \ - --label interlock.ext.service.name=foo \ + --label interlock.ext.service_name=foo \ ehazlett/interlock:1.2.0 \ -D run -c /etc/interlock/config.toml docker run -d -p 80:80 \ --name nginx_foo \ --label interlock.ext.name=nginx \ - --label interlock.ext.service.name=foo \ + --label interlock.ext.service_name=foo \ nginx docker run -d -P \ - --label interlock.ext.service.name=foo \ + --label interlock.ext.service_name=foo \ ehazlett/docker-demo ``` diff --git a/ext/ext.go b/ext/ext.go index 70d3ba16..64570d6a 100644 --- a/ext/ext.go +++ b/ext/ext.go @@ -7,7 +7,7 @@ import ( const ( InterlockAppLabel = "interlock.app" // internal InterlockExtNameLabel = "interlock.ext.name" // common - InterlockExtServiceNameLabel = "interlock.ext.service.name" // common + InterlockExtServiceNameLabel = "interlock.ext.service_name" // common InterlockHostnameLabel = "interlock.hostname" // haproxy, nginx InterlockNetworkLabel = "interlock.network" // common InterlockDomainLabel = "interlock.domain" // haproxy, nginx diff --git a/ext/lb/lb.go b/ext/lb/lb.go index a30945a9..21b6f506 100644 --- a/ext/lb/lb.go +++ b/ext/lb/lb.go @@ -304,7 +304,7 @@ func (l *LoadBalancer) ListContainers() ([]dockerclient.Container, error) { var containers []dockerclient.Container var err error - allContainers, err := l.client.ListContainers(false, false, "") + allContainers, err := l.client.ListContainers(true, false, "") if err != nil { return nil, err @@ -497,12 +497,22 @@ func (l *LoadBalancer) isExposedContainer(id string) bool { } func (l *LoadBalancer) isServiceContainer(labels map[string]string) bool { - containerServiceName, labelled := labels[ext.InterlockExtServiceNameLabel] + serviceName, labelled := labels[ext.InterlockExtServiceNameLabel] - if (len(l.cfg.ServiceName) > 0 && containerServiceName == l.cfg.ServiceName) || - (len(l.cfg.ServiceName) == 0 && !labelled) { + switch { + case l.serviceNameMatch(serviceName): return true - } else { + case l.serviceNamelessMatch(serviceName, labelled): + return true + default: return false } } + +func (l *LoadBalancer) serviceNameMatch(serviceName string) bool { + return len(l.cfg.ServiceName) > 0 && serviceName == l.cfg.ServiceName +} + +func (l *LoadBalancer) serviceNamelessMatch(serviceName string, labelled bool) bool { + return len(l.cfg.ServiceName) == 0 && !labelled +}