Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multi-port service routing for containers running on Marathon #1742

Merged
merged 13 commits into from
Aug 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions docs/toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,7 @@ Labels can be used on containers to override default behaviour:
- `traefik.docker.network`: Set the docker network to use for connections to this container. If a container is linked to several networks, be sure to set the proper network name (you can check with docker inspect <container_id>) otherwise it will randomly pick one (depending on how docker is returning them). For instance when deploying docker `stack` from compose files, the compose defined networks will be prefixed with the `stack` name.

If several ports need to be exposed from a container, the services labels can be used

- `traefik.<service-name>.port=443`: create a service binding with frontend/backend using this port. Overrides `traefik.port`.
- `traefik.<service-name>.protocol=https`: assign `https` protocol. Overrides `traefik.protocol`.
- `traefik.<service-name>.weight=10`: assign this service weight. Overrides `traefik.weight`.
Expand Down Expand Up @@ -1192,6 +1193,18 @@ Labels can be used on containers to override default behaviour:
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
- `traefik.frontend.auth.basic=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0`: Sets basic authentication for that frontend with the usernames and passwords test:test and test2:test2, respectively

If several ports need to be exposed from a container, the services labels can be used

- `traefik.<service-name>.port=443`: create a service binding with frontend/backend using this port. Overrides `traefik.port`.
- `traefik.<service-name>.portIndex=1`: create a service binding with frontend/backend using this port index. Overrides `traefik.portIndex`.
- `traefik.<service-name>.protocol=https`: assign `https` protocol. Overrides `traefik.protocol`.
- `traefik.<service-name>.weight=10`: assign this service weight. Overrides `traefik.weight`.
- `traefik.<service-name>.frontend.backend=fooBackend`: assign this service frontend to `foobackend`. Default is to assign to the service backend.
- `traefik.<service-name>.frontend.entryPoints=http`: assign this service entrypoints. Overrides `traefik.frontend.entrypoints`.
- `traefik.<service-name>.frontend.auth.basic=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0` Sets a Basic Auth for that frontend with the users test:test and test2:test2.
- `traefik.<service-name>.frontend.passHostHeader=true`: Forward client `Host` header to the backend. Overrides `traefik.frontend.passHostHeader`.
- `traefik.<service-name>.frontend.priority=10`: assign the service frontend priority. Overrides `traefik.frontend.priority`.
- `traefik.<service-name>.frontend.rule=Path:/foo`: assign the service frontend rule. Overrides `traefik.frontend.rule`.

## Mesos generic backend

Expand Down
30 changes: 26 additions & 4 deletions integration/marathon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ func (s *MarathonSuite) extendDockerHostsFile(host, ipAddr string) error {
return nil
}

func deployApplication(c *check.C, client marathon.Marathon, application *marathon.Application) {
deploy, err := client.UpdateApplication(application, false)
c.Assert(err, checker.IsNil)
// Wait for deployment to complete.
c.Assert(client.WaitOnDeployment(deploy.DeploymentID, 1*time.Minute), checker.IsNil)
}

func (s *MarathonSuite) TestConfigurationUpdate(c *check.C) {
// Start Traefik.
file := s.adaptFile(c, "fixtures/marathon/simple.toml", struct {
Expand Down Expand Up @@ -117,13 +124,28 @@ func (s *MarathonSuite) TestConfigurationUpdate(c *check.C) {
Container("emilevauge/whoami")

// Deploy the test application.
deploy, err := client.UpdateApplication(app, false)
c.Assert(err, checker.IsNil)
// Wait for deployment to complete.
c.Assert(client.WaitOnDeployment(deploy.DeploymentID, 1*time.Minute), checker.IsNil)
deployApplication(c, client, app)

// Query application via Traefik.
err = try.GetRequest("http://127.0.0.1:8000/service", 30*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)

// Create test application with services to be deployed.
app = marathon.NewDockerApplication().
Name("/whoami").
CPU(0.1).
Memory(32).
AddLabel(types.ServiceLabel(types.LabelFrontendRule, "app"), "PathPrefix:/app")
app.Container.Docker.Bridged().
Expose(80).
Container("emilevauge/whoami")

// Deploy the test application.
deployApplication(c, client, app)

// Query application via Traefik.
err = try.GetRequest("http://127.0.0.1:8000/app", 30*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)

showTraefikLog = false
}
2 changes: 1 addition & 1 deletion provider/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ func (p *Provider) hasCircuitBreakerLabel(container dockerData) bool {

// Regexp used to extract the name of the service and the name of the property for this service
// All properties are under the format traefik.<servicename>.frontent.*= except the port/weight/protocol directly after traefik.<servicename>.
var servicesPropertiesRegexp = regexp.MustCompile(`^traefik\.(?P<service_name>.*?)\.(?P<property_name>port|weight|protocol|frontend\.(.*))$`)
var servicesPropertiesRegexp = regexp.MustCompile(`^traefik\.(?P<service_name>.+?)\.(?P<property_name>port|weight|protocol|frontend\.(.*))$`)

// Map of services properties
// we can get it with label[serviceName][propertyName] and we got the propertyValue
Expand Down
13 changes: 13 additions & 0 deletions provider/marathon/builder_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package marathon

import (
"strings"
"time"

"github.com/containous/traefik/types"
"github.com/gambol99/go-marathon"
)

Expand Down Expand Up @@ -42,6 +44,17 @@ func label(key, value string) func(*marathon.Application) {
}
}

func labelWithService(key, value string, serviceName string) func(*marathon.Application) {
if len(serviceName) == 0 {
panic("serviceName can not be empty")
}

property := strings.TrimPrefix(key, types.LabelPrefix)
return func(app *marathon.Application) {
app.AddLabel(types.LabelPrefix+serviceName+"."+property, value)
}
}

func healthChecks(checks ...*marathon.HealthCheck) func(*marathon.Application) {
return func(app *marathon.Application) {
for _, check := range checks {
Expand Down