Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
external-lb
==========
Rancher service facilitating integration of rancher with external load balancers. This service updates external LB with services created in Rancher that ask to be load balanced using an external LB.
Rancher service facilitating integration of rancher with external load balancers. This service updates external LB with services created in Rancher that ask to be load balanced using an external LB.
Initial version comes with f5 BIG-IP support; but a pluggable provider model makes it easy to implement other providers later.

Design
==========
* The external-lb gets deployed as a Rancher service containerized app.
* The external-lb gets deployed as a Rancher service containerized app.

* It enables any other service to be registered to external LB if the service has exposed a public port and has the label 'io.rancher.service.external_lb_endpoint'

Expand All @@ -22,6 +22,8 @@ The following environment variables are used to configure global options.
|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------|
| POLL_INTERVAL | Value in milliseconds to check for rancher metadata updates | `1000` |
| FORCE_UPDATE_INTERVAL | Value in minutes to force a resource poll. Increasing this value may be required if you run into api limits enforced by your cloud providor | `1` |
| SERVICE_LABEL_ENDPOINT | Which label to search for elb names to update. Useful to customize if a single rancher env spans disparate cloud provider accounts, and multiple aws-elb services are required to access each one | `io.rancher.service.external_lb.endpoint` |
| RESTRICT_SERVICE_TO_SELF_STACK | Limit service registration to those running in the same stack as the external-lb service | 'false' |

Contact
========
Expand Down
53 changes: 39 additions & 14 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ import (
)

const (
DefaultPollInterval = "1000"
DefaultForceUpdateInterval = "1"
DefaultLBTargetRancherSuffix = "rancher.internal"
EnvVarPollInterval = "POLL_INTERVAL"
EnvVarForceUpdateInterval = "FORCE_UPDATE_INTERVAL"
EnvVarLBTargetRancherSuffix = "LB_TARGET_RANCHER_SUFFIX"
DefaultPollInterval = "1000"
DefaultForceUpdateInterval = "1"
DefaultLBTargetRancherSuffix = "rancher.internal"
EnvVarPollInterval = "POLL_INTERVAL"
EnvVarForceUpdateInterval = "FORCE_UPDATE_INTERVAL"
EnvVarLBTargetRancherSuffix = "LB_TARGET_RANCHER_SUFFIX"
EnvVarServiceLabelEndpoint = "SERVICE_LABEL_ENDPOINT"
EnvVarRestrictServiceToSelfStack = "RESTRICT_SERVICE_TO_SELF_STACK"
)

var (
Expand All @@ -37,13 +39,15 @@ var (
m *metadata.MetadataClient
c *CattleClient

targetPoolSuffix string
metadataLBConfigsCached = make(map[string]model.LBConfig)

forceUpdateInterval float64
pollInterval float64
p string
i string
targetPoolSuffix string
serviceLabelEndpoint string
restrictServiceToSelfStack bool
metadataLBConfigsCached = make(map[string]model.LBConfig)
forceUpdateInterval float64
pollInterval float64
p string
i string
r string
)

func setEnv() {
Expand All @@ -54,6 +58,27 @@ func setEnv() {

var err error

// optionally restrict the service to those running in same stack as external-lb
r = os.Getenv(EnvVarRestrictServiceToSelfStack)
if len(r) == 0 {
logrus.Info(EnvVarRestrictServiceToSelfStack + " is not set")
restrictServiceToSelfStack = false
} else {
restrictServiceToSelfStack, err = strconv.ParseBool(r)
if err != nil {
logrus.Fatalf("Failed to initialize restrictServiceToSelfStack: %v", err)
}
logrus.Info(EnvVarRestrictServiceToSelfStack + " is set to: " + strconv.FormatBool(restrictServiceToSelfStack))
}

serviceLabelEndpoint = os.Getenv(EnvVarServiceLabelEndpoint)
if len(serviceLabelEndpoint) == 0 {
logrus.Info(EnvVarServiceLabelEndpoint + " is not set")
serviceLabelEndpoint = ""
} else {
logrus.Info(EnvVarServiceLabelEndpoint + " is set to: " + serviceLabelEndpoint)
}

// initialize polling and forceUpdate intervals
i = os.Getenv(EnvVarForceUpdateInterval)
if i == "" {
Expand Down Expand Up @@ -147,7 +172,7 @@ func main() {

if update || updateForced {
// get records from metadata
metadataLBConfigs, err := m.GetMetadataLBConfigs(targetPoolSuffix)
metadataLBConfigs, err := m.GetMetadataLBConfigs(targetPoolSuffix, serviceLabelEndpoint, restrictServiceToSelfStack)
if err != nil {
logrus.Errorf("Failed to get LB configs from metadata: %v", err)
continue
Expand Down
21 changes: 17 additions & 4 deletions metadata/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
)

const (
metadataURLTemplate = "http://%v/2015-12-19"
serviceLabelEndpoint = "io.rancher.service.external_lb.endpoint"
serviceLabelEndpointLegacy = "io.rancher.service.external_lb_endpoint"
metadataURLTemplate = "http://%v/2015-12-19"
serviceLabelEndpointLegacy = "io.rancher.service.external_lb_endpoint"
DefaultServiceLabelEndpoint = "io.rancher.service.external_lb.endpoint"

// DefaultMetadataAddress specifies the default value to use if nothing is specified
DefaultMetadataAddress = "169.254.169.250"
Expand Down Expand Up @@ -70,9 +70,13 @@ func (m *MetadataClient) GetVersion() (string, error) {
}

// GetMetadataLBConfigs ...
func (m *MetadataClient) GetMetadataLBConfigs(targetPoolSuffix string) (map[string]model.LBConfig, error) {
func (m *MetadataClient) GetMetadataLBConfigs(targetPoolSuffix string, serviceLabelEndpoint string, restrictServiceToSelfStack bool) (map[string]model.LBConfig, error) {
if serviceLabelEndpoint == "" {
serviceLabelEndpoint = DefaultServiceLabelEndpoint
}
lbConfigs := make(map[string]model.LBConfig)
services, err := m.MetadataClient.GetServices()
selfStack, err := m.MetadataClient.GetSelfStack()
if err != nil {
logrus.Infof("Error reading services: %v", err)
} else {
Expand All @@ -94,6 +98,15 @@ func (m *MetadataClient) GetMetadataLBConfigs(targetPoolSuffix string) (map[stri
continue
}

// Skip the service if it does not exist in the desired stack (optional)
logrus.Debugf("Service %s is running in stack %s", service.Name, service.StackName)
logrus.Debugf("external-lb is running in stack %s", selfStack.Name)
if restrictServiceToSelfStack && (service.StackName != selfStack.Name) {
logrus.Debugf("Skipping service %s as it is running in a different stack %s than external-lb: %s",
service.Name, service.StackName, selfStack.Name)
continue
}

// get the service port
if len(service.Ports) == 0 {
logrus.Warnf("Skipping LB configuration for service %s: "+
Expand Down
8 changes: 8 additions & 0 deletions providers/elbv1/aws_elbv1.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ func (p *AWSELBv1Provider) GetLBConfigs() ([]model.LBConfig, error) {
}

for _, lb := range allLb {

if _, ok := lbTags[*lb.LoadBalancerName]; !ok {
continue
}
Expand All @@ -128,6 +129,13 @@ func (p *AWSELBv1Provider) GetLBConfigs() ([]model.LBConfig, error) {

var targetPoolName, servicePort string
var ok bool

logrus.Debugf("Working on lb %s with VPCId: %s", *lb.LoadBalancerName, *lb.VPCId)
if *lb.VPCId != p.vpcID {
logrus.Debugf("Skipping LB whose vpc %s does not match our vpc %s", *lb.VPCId, p.vpcID)
continue
}

if targetPoolName, ok = tags[TagNameTargetPool]; !ok {
logrus.Debugf("Skipping LB without targetPool tag: %s", *lb.LoadBalancerName)
continue
Expand Down