diff --git a/docs/toml.md b/docs/toml.md index 0891809f7..fabbebc50 100644 --- a/docs/toml.md +++ b/docs/toml.md @@ -1453,3 +1453,72 @@ Træfɪk needs the following policy to read ECS information: ] } ``` + +# Rancher backend + +Træfɪk can be configured to use Rancher as a backend configuration: + + +```toml +################################################################ +# Rancher configuration backend +################################################################ + +# Enable Rancher configuration backend +# +# Optional +# +[rancher] + +# Default domain used. +# Can be overridden by setting the "traefik.domain" label on an service. +# +# Required +# +domain = "rancher.localhost" + +# Enable watch Rancher changes +# +# Optional +# Default: true +# +Watch = true + +# Expose Rancher services by default in traefik +# +# Optional +# Default: true +# +ExposedByDefault = false + +# Endpoint to use when connecting to Rancher +# +# Optional +# Endpoint = "http://rancherserver.example.com" + +# AccessKey to use when connecting to Rancher +# +# Optional +# AccessKey = "XXXXXXXXX" + +# SecretKey to use when connecting to Rancher +# +# Optional +# SecretKey = "XXXXXXXXXXX" + +``` + +If you're deploying traefik as a service within rancher, you can alternatively set these labels on the service to let it only fetch data of its current environment. The settings `endpoint`, `accesskey` and `secretkey` can be omitted then. + +- `io.rancher.container.create_agent=true` +- `io.rancher.container.agent.role=environment` + +Labels can be used on task containers to override default behaviour: + +- `traefik.protocol=https`: override the default `http` protocol +- `traefik.weight=10`: assign this weight to the container +- `traefik.enable=false`: disable this container in Træfɪk +- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`). +- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend. +- `traefik.frontend.priority=10`: override default frontend priority +- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`. diff --git a/examples/compose-rancher.yml b/examples/compose-rancher.yml new file mode 100644 index 000000000..cd4e0f677 --- /dev/null +++ b/examples/compose-rancher.yml @@ -0,0 +1,10 @@ +traefik: + image: traefik + command: --web --rancher --rancher.domain=rancher.localhost --logLevel=DEBUG + labels: + io.rancher.container.agent.role: environment + io.rancher.container.create_agent: 'true' + ports: + - "80:80" + - "443:443" + - "8080:8080" diff --git a/provider/rancher.go b/provider/rancher.go index 77072f0a9..72b2231d4 100644 --- a/provider/rancher.go +++ b/provider/rancher.go @@ -4,6 +4,13 @@ import ( "context" "errors" "fmt" + "math" + "os" + "strconv" + "strings" + "text/template" + "time" + "github.com/BurntSushi/ty/fun" "github.com/cenk/backoff" "github.com/containous/traefik/job" @@ -11,11 +18,6 @@ import ( "github.com/containous/traefik/safe" "github.com/containous/traefik/types" rancher "github.com/rancher/go-rancher/client" - "math" - "strconv" - "strings" - "text/template" - "time" ) const ( @@ -72,7 +74,7 @@ func (provider *Rancher) getFrontendRule(service rancherData) string { if label, err := getServiceLabel(service, "traefik.frontend.rule"); err == nil { return label } - return "Host:" + strings.ToLower(strings.Replace(service.Name, "/", "_", -1)) + "." + provider.Domain + return "Host:" + strings.ToLower(strings.Replace(service.Name, "/", ".", -1)) + "." + provider.Domain } func (provider *Rancher) getFrontendName(service rancherData) string { @@ -193,13 +195,26 @@ func getServiceLabel(service rancherData, label string) (string, error) { } func (provider *Rancher) createClient() (*rancher.RancherClient, error) { + + rancherURL := getenv("CATTLE_URL", provider.Endpoint) + accessKey := getenv("CATTLE_ACCESS_KEY", provider.AccessKey) + secretKey := getenv("CATTLE_SECRET_KEY", provider.SecretKey) + return rancher.NewRancherClient(&rancher.ClientOpts{ - Url: provider.Endpoint, - AccessKey: provider.AccessKey, - SecretKey: provider.SecretKey, + Url: rancherURL, + AccessKey: accessKey, + SecretKey: secretKey, }) } +func getenv(key, fallback string) string { + value := os.Getenv(key) + if len(value) == 0 { + return fallback + } + return value +} + // Provide allows the provider to provide configurations to traefik // using the given configuration channel. func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, constraints types.Constraints) error { @@ -207,6 +222,12 @@ func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, p safe.Go(func() { operation := func() error { rancherClient, err := provider.createClient() + + if err != nil { + log.Errorf("Failed to create a client for rancher, error: %s", err) + return err + } + ctx := context.Background() var environments = listRancherEnvironments(rancherClient) var services = listRancherServices(rancherClient) @@ -214,11 +235,6 @@ func (provider *Rancher) Provide(configurationChan chan<- types.ConfigMessage, p var rancherData = parseRancherData(environments, services, container) - if err != nil { - log.Errorf("Failed to create a client for rancher, error: %s", err) - return err - } - configuration := provider.loadRancherConfig(rancherData) configurationChan <- types.ConfigMessage{ ProviderName: "rancher", diff --git a/provider/rancher_test.go b/provider/rancher_test.go index d0b920f2d..9497a9139 100644 --- a/provider/rancher_test.go +++ b/provider/rancher_test.go @@ -87,6 +87,12 @@ func TestRancherGetFrontendRule(t *testing.T) { }, expected: "Host:foo.rancher.localhost", }, + { + service: rancherData{ + Name: "foo/bar", + }, + expected: "Host:foo.bar.rancher.localhost", + }, { service: rancherData{ Name: "test-service", @@ -388,7 +394,7 @@ func TestRancherLoadRancherConfig(t *testing.T) { { services: []rancherData{ { - Name: "test-service", + Name: "test/service", Labels: map[string]string{ "traefik.port": "80", }, @@ -405,7 +411,7 @@ func TestRancherLoadRancherConfig(t *testing.T) { Routes: map[string]types.Route{ "route-frontend-Host-test-service-rancher-localhost": { - Rule: "Host:test-service.rancher.localhost", + Rule: "Host:test.service.rancher.localhost", }, }, }, diff --git a/traefik.sample.toml b/traefik.sample.toml index e2c19f408..15d1d97d3 100644 --- a/traefik.sample.toml +++ b/traefik.sample.toml @@ -935,6 +935,52 @@ # # filename = "ecs.tmpl" +################################################################ +# Rancher configuration backend +################################################################ + +# Enable Rancher configuration backend +# +# Optional +# +[rancher] + +# Default domain used. +# Can be overridden by setting the "traefik.domain" label on an service. +# +# Required +# +domain = "rancher.localhost" + +# Enable watch Rancher changes +# +# Optional +# Default: true +# +Watch = true + +# Expose Rancher services by default in traefik +# +# Optional +# Default: true +# +ExposedByDefault = false + +# Endpoint to use when connecting to Rancher +# +# Optional +# Endpoint = "http://rancherserver.example.com" + +# AccessKey to use when connecting to Rancher +# +# Optional +# AccessKey = "XXXXXXXXX" + +# SecretKey to use when connecting to Rancher +# +# Optional +# SecretKey = "XXXXXXXXXXX" + ################################################################ # Sample rules