Remove Marathon provider

This commit is contained in:
Romain 2022-12-19 11:52:05 +01:00 committed by GitHub
parent 2ad1fd725a
commit 2b67f1f66f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
80 changed files with 11 additions and 7802 deletions

View file

@ -11,7 +11,7 @@
[![Twitter](https://img.shields.io/twitter/follow/traefik.svg?style=social)](https://twitter.com/intent/follow?screen_name=traefik)
Traefik (pronounced _traffic_) is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy.
Traefik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Marathon](https://mesosphere.github.io/marathon/), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher v2](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
Traefik integrates with your existing infrastructure components ([Docker](https://www.docker.com/), [Swarm mode](https://docs.docker.com/engine/swarm/), [Kubernetes](https://kubernetes.io), [Consul](https://www.consul.io/), [Etcd](https://coreos.com/etcd/), [Rancher v2](https://rancher.com), [Amazon ECS](https://aws.amazon.com/ecs), ...) and configures itself automatically and dynamically.
Pointing Traefik at your orchestrator should be the _only_ configuration step you need.
---
@ -68,7 +68,6 @@ _(But if you'd rather configure some of your routes manually, Traefik supports t
- [Docker](https://doc.traefik.io/traefik/providers/docker/) / [Swarm mode](https://doc.traefik.io/traefik/providers/docker/)
- [Kubernetes](https://doc.traefik.io/traefik/providers/kubernetes-crd/)
- [Marathon](https://doc.traefik.io/traefik/providers/marathon/)
- [File](https://doc.traefik.io/traefik/providers/file/)
## Quickstart

View file

@ -43,17 +43,6 @@ spec:
- '*.example.org'
```
```json tab="Marathon"
labels: {
"traefik.http.routers.blog.rule": "Host(`example.com`) && Path(`/blog`)",
"traefik.http.routers.blog.tls": "true",
"traefik.http.routers.blog.tls.certresolver": "myresolver",
"traefik.http.routers.blog.tls.domains[0].main": "example.com",
"traefik.http.routers.blog.tls.domains[0].sans": "*.example.com",
"traefik.http.services.blog-svc.loadbalancer.server.port": "8080"
}
```
```yaml tab="File (YAML)"
## Dynamic configuration
http:

View file

@ -35,15 +35,6 @@ spec:
certResolver: myresolver
```
```json tab="Marathon"
labels: {
"traefik.http.routers.blog.rule": "(Host(`example.com`) && Path(`/blog`)) || Host(`blog.example.org`)",
"traefik.http.routers.blog.tls": "true",
"traefik.http.routers.blog.tls.certresolver": "myresolver",
"traefik.http.services.blog-svc.loadbalancer.server.port": "8080"
}
```
```yaml tab="File (YAML)"
## Dynamic configuration
http:

View file

@ -35,15 +35,6 @@ spec:
certResolver: myresolver
```
```json tab="Marathon"
labels: {
"traefik.http.routers.blog.rule": "Host(`example.com`) && Path(`/blog`)",
"traefik.http.routers.blog.tls": "true",
"traefik.http.routers.blog.tls.certresolver": "myresolver",
"traefik.http.services.blog-svc.loadbalancer.server.port": "8080"
}
```
```yaml tab="File (YAML)"
## Dynamic configuration
http:

View file

@ -120,13 +120,6 @@ A certificate resolver requests certificates for a set of domain names inferred
certResolver: myresolver
```
```json tab="Marathon"
labels: {
"traefik.http.routers.blog.rule": "Host(`monitoring.yak-bebop.ts.net`) && Path(`/metrics`)",
"traefik.http.routers.blog.tls.certresolver": "myresolver",
}
```
```yaml tab="File (YAML)"
## Dynamic configuration
http:
@ -185,14 +178,6 @@ A certificate resolver requests certificates for a set of domain names inferred
- main: monitoring.yak-bebop.ts.net
```
```json tab="Marathon"
labels: {
"traefik.http.routers.blog.rule": "Path(`/metrics`)",
"traefik.http.routers.blog.tls.certresolver": "myresolver",
"traefik.http.routers.blog.tls.domains[0].main": "monitoring.yak-bebop.ts.net",
}
```
```yaml tab="File (YAML)"
## Dynamic configuration
http:

View file

@ -219,14 +219,6 @@ labels:
- "traefik.tls.stores.default.defaultgeneratedcert.domain.sans=foo.example.org, bar.example.org"
```
```json tab="Marathon"
labels: {
"traefik.tls.stores.default.defaultgeneratedcert.resolver": "myresolver",
"traefik.tls.stores.default.defaultgeneratedcert.domain.main": "example.org",
"traefik.tls.stores.default.defaultgeneratedcert.domain.sans": "foo.example.org, bar.example.org",
}
```
## TLS Options
The TLS options allow one to configure some parameters of the TLS connection.

View file

@ -13,7 +13,7 @@ It receives requests on behalf of your system and finds out which components are
What sets Traefik apart, besides its many features, is that it automatically discovers the right configuration for your services.
The magic happens when Traefik inspects your infrastructure, where it finds relevant information and discovers which service serves which request.
Traefik is natively compliant with every major cluster technology, such as Kubernetes, Docker, Docker Swarm, AWS, Mesos, Marathon, and [the list goes on](providers/overview.md); and can handle many at the same time. (It even works for legacy software running on bare metal.)
Traefik is natively compliant with every major cluster technology, such as Kubernetes, Docker, Docker Swarm, AWS, and [the list goes on](providers/overview.md); and can handle many at the same time. (It even works for legacy software running on bare metal.)
With Traefik, there is no need to maintain and synchronize a separate configuration file: everything happens automatically, in real time (no restarts, no connection interruptions).
With Traefik, you spend time developing and deploying new features to your system, not on configuring and maintaining its working state.

View file

@ -36,12 +36,6 @@ spec:
- "traefik.http.middlewares.add-foo.addprefix.prefix=/foo"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.add-foo.addprefix.prefix": "/foo"
}
```
```yaml tab="File (YAML)"
# Prefixing with /foo
http:

View file

@ -41,12 +41,6 @@ spec:
- "traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.basicauth.users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="File (YAML)"
# Declaring the user list
http:
@ -151,12 +145,6 @@ data:
- "traefik.http.middlewares.test-auth.basicauth.users=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.basicauth.users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="File (YAML)"
# Declaring the user list
http:
@ -220,12 +208,6 @@ data:
- "traefik.http.middlewares.test-auth.basicauth.usersfile=/path/to/my/usersfile"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.basicauth.usersfile": "/path/to/my/usersfile"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -270,12 +252,6 @@ spec:
- "traefik.http.middlewares.test-auth.basicauth.realm=MyRealm"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.basicauth.realm": "MyRealm"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -314,12 +290,6 @@ spec:
- "traefik.http.middlewares.my-auth.basicauth.headerField=X-WebAuth-User"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.my-auth.basicauth.headerField": "X-WebAuth-User"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -358,12 +328,6 @@ spec:
- "traefik.http.middlewares.test-auth.basicauth.removeheader=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.basicauth.removeheader": "true"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -40,12 +40,6 @@ spec:
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.limit.buffering.maxRequestBodyBytes": "2000000"
}
```
```yaml tab="File (YAML)"
# Sets the maximum request body to 2MB
http:
@ -91,12 +85,6 @@ spec:
- "traefik.http.middlewares.limit.buffering.maxRequestBodyBytes=2000000"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.limit.buffering.maxRequestBodyBytes": "2000000"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -136,12 +124,6 @@ spec:
- "traefik.http.middlewares.limit.buffering.memRequestBodyBytes=2000000"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.limit.buffering.memRequestBodyBytes": "2000000"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -183,12 +165,6 @@ spec:
- "traefik.http.middlewares.limit.buffering.maxResponseBodyBytes=2000000"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.limit.buffering.maxResponseBodyBytes": "2000000"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -228,12 +204,6 @@ spec:
- "traefik.http.middlewares.limit.buffering.memResponseBodyBytes=2000000"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.limit.buffering.memResponseBodyBytes": "2000000"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -275,12 +245,6 @@ You can have the Buffering middleware replay the request using `retryExpression`
- "traefik.http.middlewares.limit.buffering.retryExpression=IsNetworkError() && Attempts() < 2"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.limit.buffering.retryExpression": "IsNetworkError() && Attempts() < 2"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -97,19 +97,6 @@ spec:
- "traefik.http.services.service1.loadbalancer.server.port=80"
```
```json tab="Marathon"
"labels": {
"traefik.http.routers.router1.service": "service1",
"traefik.http.routers.router1.middlewares": "secured",
"traefik.http.routers.router1.rule": "Host(`mydomain`)",
"traefik.http.middlewares.secured.chain.middlewares": "https-only,known-ips,auth-users",
"traefik.http.middlewares.auth-users.basicauth.users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"traefik.http.middlewares.https-only.redirectscheme.scheme": "https",
"traefik.http.middlewares.known-ips.ipallowlist.sourceRange": "192.168.1.7,127.0.0.1/32",
"traefik.http.services.service1.loadbalancer.server.port": "80"
}
```
```yaml tab="File (YAML)"
# ...
http:

View file

@ -52,12 +52,6 @@ spec:
- "traefik.http.middlewares.latency-check.circuitbreaker.expression=LatencyAtQuantileMS(50.0) > 100"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.latency-check.circuitbreaker.expression": "LatencyAtQuantileMS(50.0) > 100"
}
```
```yaml tab="File (YAML)"
# Latency Check
http:

View file

@ -36,12 +36,6 @@ spec:
- "traefik.http.middlewares.test-compress.compress=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-compress.compress": "true"
}
```
```yaml tab="File (YAML)"
# Enable compression
http:
@ -108,12 +102,6 @@ spec:
- "traefik.http.middlewares.test-compress.compress.excludedcontenttypes=text/event-stream"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-compress.compress.excludedcontenttypes": "text/event-stream"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -156,12 +144,6 @@ spec:
- "traefik.http.middlewares.test-compress.compress.minresponsebodybytes=1200"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-compress.compress.minresponsebodybytes": 1200
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -39,12 +39,6 @@ spec:
- "traefik.http.middlewares.autodetect.contenttype=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.autodetect.contenttype": "true"
}
```
```yaml tab="File (YAML)"
# Enable auto-detection
http:

View file

@ -36,12 +36,6 @@ spec:
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.digestauth.users": "test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
}
```
```yaml tab="File (YAML)"
# Declaring the user list
http:
@ -108,12 +102,6 @@ data:
- "traefik.http.middlewares.test-auth.digestauth.users=test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.digestauth.users": "test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -175,12 +163,6 @@ data:
- "traefik.http.middlewares.test-auth.digestauth.usersfile=/path/to/my/usersfile"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.digestauth.usersfile": "/path/to/my/usersfile"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -225,12 +207,6 @@ spec:
- "traefik.http.middlewares.test-auth.digestauth.realm=MyRealm"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.digestauth.realm": "MyRealm"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -269,12 +245,6 @@ spec:
- "traefik.http.middlewares.my-auth.digestauth.headerField=X-WebAuth-User"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.my-auth.digestauth.headerField": "X-WebAuth-User"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -313,12 +283,6 @@ spec:
- "traefik.http.middlewares.test-auth.digestauth.removeheader=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.digestauth.removeheader": "true"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -48,14 +48,6 @@ spec:
- "traefik.http.middlewares.test-errors.errors.query=/{status}.html"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-errors.errors.status": "500-599",
"traefik.http.middlewares.test-errors.errors.service": "serviceError",
"traefik.http.middlewares.test-errors.errors.query": "/{status}.html"
}
```
```yaml tab="File (YAML)"
# Custom Error Page for 5XX
http:

View file

@ -38,12 +38,6 @@ spec:
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.address": "https://example.com/auth"
}
```
```yaml tab="File (YAML)"
# Forward authentication to example.com
http:
@ -97,12 +91,6 @@ spec:
- "traefik.http.middlewares.test-auth.forwardauth.address=https://example.com/auth"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.address": "https://example.com/auth"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -141,12 +129,6 @@ spec:
- "traefik.http.middlewares.test-auth.forwardauth.trustForwardHeader=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.trustForwardHeader": "true"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -190,12 +172,6 @@ spec:
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeaders=X-Auth-User, X-Secret"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.authResponseHeaders": "X-Auth-User,X-Secret"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -241,12 +217,6 @@ spec:
- "traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex=^X-"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.authResponseHeadersRegex": "^X-"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -297,12 +267,6 @@ spec:
- "traefik.http.middlewares.test-auth.forwardauth.authRequestHeaders=Accept,X-CustomHeader"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.authRequestHeaders": "Accept,X-CustomHeader"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -366,12 +330,6 @@ data:
- "traefik.http.middlewares.test-auth.forwardauth.tls.ca=path/to/local.crt"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.tls.ca": "path/to/local.crt"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -431,13 +389,6 @@ data:
- "traefik.http.middlewares.test-auth.forwardauth.tls.key=path/to/foo.key"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.tls.cert": "path/to/foo.cert",
"traefik.http.middlewares.test-auth.forwardauth.tls.key": "path/to/foo.key"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -503,13 +454,6 @@ data:
- "traefik.http.middlewares.test-auth.forwardauth.tls.key=path/to/foo.key"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.tls.cert": "path/to/foo.cert",
"traefik.http.middlewares.test-auth.forwardauth.tls.key": "path/to/foo.key"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -561,12 +505,6 @@ spec:
- "traefik.http.middlewares.test-auth.forwardauth.tls.InsecureSkipVerify=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-auth.forwardauth.tls.insecureSkipVerify": "true"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -37,12 +37,6 @@ spec:
- "traefik.http.middlewares.test-grpcweb.grpcWeb.allowOrigins=*"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-grpcweb.grpcweb.alloworigins": "*"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -44,13 +44,6 @@ spec:
- "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header=value"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name": "test",
"traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header": "value"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -103,14 +96,6 @@ spec:
- "traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header="
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Script-Name": "test",
"traefik.http.middlewares.testheader.headers.customrequestheaders.X-Custom-Request-Header": "",
"traefik.http.middlewares.testheader.headers.customresponseheaders.X-Custom-Response-Header": "",
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -160,14 +145,6 @@ spec:
- "traefik.http.middlewares.testheader.headers.browserxssfilter=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.testheader.headers.framedeny": "true",
"traefik.http.middlewares.testheader.headers.browserxssfilter": "true"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -224,15 +201,6 @@ spec:
- "traefik.http.middlewares.testheader.headers.addvaryheader=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.testheader.headers.accesscontrolallowmethods": "GET,OPTIONS,PUT",
"traefik.http.middlewares.testheader.headers.accesscontrolalloworiginlist": "https://foo.bar.org,https://example.org",
"traefik.http.middlewares.testheader.headers.accesscontrolmaxage": "100",
"traefik.http.middlewares.testheader.headers.addvaryheader": "true"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -34,12 +34,6 @@ spec:
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-inflightreq.inflightreq.amount": "10"
}
```
```yaml tab="File (YAML)"
# Limiting to 10 simultaneous connections
http:
@ -83,12 +77,6 @@ spec:
- "traefik.http.middlewares.test-inflightreq.inflightreq.amount=10"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-inflightreq.inflightreq.amount": "10"
}
```
```yaml tab="File (YAML)"
# Limiting to 10 simultaneous connections
http:
@ -153,12 +141,6 @@ spec:
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.depth=2"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.depth": "2"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -215,12 +197,6 @@ spec:
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.ipstrategy.excludedips": "127.0.0.1/32, 192.168.1.7"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -264,12 +240,6 @@ spec:
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requestheadername=username"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requestheadername": "username"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -310,12 +280,6 @@ spec:
- "traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requesthost=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-inflightreq.inflightreq.sourcecriterion.requesthost": "true"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -35,12 +35,6 @@ spec:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange": "127.0.0.1/32,192.168.1.7"
}
```
```yaml tab="File (YAML)"
# Accepts request from defined IP
http:
@ -114,13 +108,6 @@ spec:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth=2"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange": "127.0.0.1/32, 192.168.1.7",
"traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth": "2"
}
```
```yaml tab="File (YAML)"
# Allowlisting Based on `X-Forwarded-For` with `depth=2`
http:
@ -184,12 +171,6 @@ spec:
- "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips": "127.0.0.1/32, 192.168.1.7"
}
```
```yaml tab="File (YAML)"
# Exclude from `X-Forwarded-For`
http:

View file

@ -69,13 +69,6 @@ spec:
- "traefik.http.routers.router1.middlewares=foo-add-prefix@consulcatalog"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.foo-add-prefix.addprefix.prefix": "/foo",
"traefik.http.routers.router1.middlewares": "foo-add-prefix@marathon"
}
```
```toml tab="File (TOML)"
# As TOML Configuration File
[http.routers]

View file

@ -39,12 +39,6 @@ spec:
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.pem": "true"
}
```
```yaml tab="File (YAML)"
# Pass the pem in the `X-Forwarded-Tls-Client-Cert` header.
http:
@ -140,29 +134,6 @@ http:
- "traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notafter": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.notbefore": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.sans": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.commonname": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.country": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.domaincomponent": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.locality": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organization": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.organizationalunit": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.province": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.subject.serialnumber": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.commonname": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.country": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.domaincomponent": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.locality": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.organization": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.province": "true",
"traefik.http.middlewares.test-passtlsclientcert.passtlsclientcert.info.issuer.serialnumber": "true"
}
```
```yaml tab="File (YAML)"
# Pass all the available info in the `X-Forwarded-Tls-Client-Cert-Info` header
http:

View file

@ -40,13 +40,6 @@ spec:
- "traefik.http.middlewares.test-ratelimit.ratelimit.burst=50"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ratelimit.ratelimit.average": "100",
"traefik.http.middlewares.test-ratelimit.ratelimit.burst": "50"
}
```
```yaml tab="File (YAML)"
# Here, an average of 100 requests per second is allowed.
# In addition, a burst of 50 requests is allowed.
@ -100,12 +93,6 @@ spec:
- "traefik.http.middlewares.test-ratelimit.ratelimit.average=100"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ratelimit.ratelimit.average": "100",
}
```
```yaml tab="File (YAML)"
# 100 reqs/s
http:
@ -157,13 +144,6 @@ spec:
- "traefik.http.middlewares.test-ratelimit.ratelimit.period=1m"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ratelimit.ratelimit.average": "6",
"traefik.http.middlewares.test-ratelimit.ratelimit.period": "1m",
}
```
```yaml tab="File (YAML)"
# 6 reqs/minute
http:
@ -207,12 +187,6 @@ spec:
- "traefik.http.middlewares.test-ratelimit.ratelimit.burst=100"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ratelimit.ratelimit.burst": "100",
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -275,12 +249,6 @@ spec:
- "traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.ipstrategy.depth=2"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.ipstrategy.depth": "2"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -364,12 +332,6 @@ spec:
- "traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.ipstrategy.excludedips": "127.0.0.1/32, 192.168.1.7"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -413,12 +375,6 @@ spec:
- "traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.requestheadername=username"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.requestheadername": "username"
}
```
```yaml tab="File (YAML)"
http:
middlewares:
@ -459,12 +415,6 @@ spec:
- "traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.requesthost=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-ratelimit.ratelimit.sourcecriterion.requesthost": "true"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -43,13 +43,6 @@ spec:
- "traefik.http.middlewares.test-redirectregex.redirectregex.replacement=http://mydomain/$${1}"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-redirectregex.redirectregex.regex": "^http://localhost/(.*)",
"traefik.http.middlewares.test-redirectregex.redirectregex.replacement": "http://mydomain/${1}"
}
```
```yaml tab="File (YAML)"
# Redirect with domain replacement
http:

View file

@ -51,13 +51,6 @@ labels:
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme": "https"
"traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent": "true"
}
```
```yaml tab="File (YAML)"
# Redirect to https
http:
@ -108,13 +101,6 @@ labels:
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent=true"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-redirectscheme.redirectscheme.permanent": "true"
}
```
```yaml tab="File (YAML)"
# Redirect to https
http:
@ -160,12 +146,6 @@ labels:
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme=https"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-redirectscheme.redirectscheme.scheme": "https"
}
```
```yaml tab="File (YAML)"
# Redirect to https
http:
@ -212,13 +192,6 @@ labels:
- "traefik.http.middlewares.test-redirectscheme.redirectscheme.port=443"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-redirectscheme.redirectscheme.port": "443"
}
```
```yaml tab="File (YAML)"
# Redirect to https
http:

View file

@ -38,12 +38,6 @@ spec:
- "traefik.http.middlewares.test-replacepath.replacepath.path=/foo"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-replacepath.replacepath.path": "/foo"
}
```
```yaml tab="File (YAML)"
# Replace the path with /foo
http:

View file

@ -41,13 +41,6 @@ spec:
- "traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement=/bar/$1"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-replacepathregex.replacepathregex.regex": "^/foo/(.*)",
"traefik.http.middlewares.test-replacepathregex.replacepathregex.replacement": "/bar/$1"
}
```
```yaml tab="File (YAML)"
# Replace path with regex
http:

View file

@ -43,13 +43,6 @@ spec:
- "traefik.http.middlewares.test-retry.retry.initialinterval=100ms"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-retry.retry.attempts": "4",
"traefik.http.middlewares.test-retry.retry.initialinterval": "100ms",
}
```
```yaml tab="File (YAML)"
# Retry 4 times with exponential backoff
http:

View file

@ -40,12 +40,6 @@ spec:
- "traefik.http.middlewares.test-stripprefix.stripprefix.prefixes=/foobar,/fiibar"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-stripprefix.stripprefix.prefixes": "/foobar,/fiibar"
}
```
```yaml tab="File (YAML)"
# Strip prefix /foobar and /fiibar
http:

View file

@ -32,12 +32,6 @@ spec:
- "traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex=/foo/[a-z0-9]+/[0-9]+/"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.test-stripprefixregex.stripprefixregex.regex": "/foo/[a-z0-9]+/[0-9]+/"
}
```
```yaml tab="File (YAML)"
http:
middlewares:

View file

@ -66,13 +66,6 @@ spec:
- "traefik.http.routers.router1.middlewares=foo-add-prefix@consulcatalog"
```
```json tab="Marathon"
"labels": {
"traefik.http.middlewares.foo-add-prefix.addprefix.prefix": "/foo",
"traefik.http.routers.router1.middlewares": "foo-add-prefix@marathon"
}
```
```yaml tab="File (YAML)"
# As YAML Configuration File
http:

View file

@ -27,12 +27,6 @@ spec:
- "traefik.tcp.middlewares.test-inflightconn.inflightconn.amount=10"
```
```json tab="Marathon"
"labels": {
"traefik.tcp.middlewares.test-inflightconn.inflightconn.amount": "10"
}
```
```yaml tab="File (YAML)"
# Limiting to 10 simultaneous connections.
tcp:

View file

@ -35,12 +35,6 @@ spec:
- "traefik.tcp.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7"
```
```json tab="Marathon"
"labels": {
"traefik.tcp.middlewares.test-ipallowlist.ipallowlist.sourcerange": "127.0.0.1/32,192.168.1.7"
}
```
```toml tab="File (TOML)"
# Accepts request from defined IP
[tcp.middlewares]

View file

@ -70,13 +70,6 @@ spec:
- "traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@consulcatalog"
```
```json tab="Marathon"
"labels": {
"traefik.tcp.middlewares.foo-ip-allowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7",
"traefik.tcp.routers.router1.middlewares=foo-ip-allowlist@marathon"
}
```
```toml tab="File (TOML)"
# As TOML Configuration File
[tcp.routers]

View file

@ -26,7 +26,7 @@ In v3, the reported status code for gRPC requests is now the value of the `Grpc-
- The `pilot` option has been removed from the static configuration.
- The `tracing.datadog.globaltag` option has been removed.
- The `namespace` option of Consul, Consul Catalog and Nomad providers has been removed.
- The `tls.caOptional` option has been removed from the ForwardAuth middleware, as well as from the HTTP, Consul, Etcd, Redis, ZooKeeper, Marathon, Consul Catalog, and Docker providers.
- The `tls.caOptional` option has been removed from the ForwardAuth middleware, as well as from the HTTP, Consul, Etcd, Redis, ZooKeeper, Consul Catalog, and Docker providers.
- `sslRedirect`, `sslTemporaryRedirect`, `sslHost`, `sslForceHost` and `featurePolicy` options of the Headers middleware have been removed.
- The `forceSlash` option of the StripPrefix middleware has been removed.
- the `preferServerCipherSuites` option has been removed.
@ -72,3 +72,7 @@ In v3, the rancher v1 provider has been removed because Rancher v1 is [no longer
Rancher 2.x requires Kubernetes and does not have a metadata endpoint of its own for Traefik to query.
As such, Rancher 2.x users should utilize the [Kubernetes CRD provider](../providers/kubernetes-crd.md) directly.
## Marathon provider
In v3, the Marathon provider has been removed.

View file

@ -51,15 +51,6 @@ spec:
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```json tab="Marathon"
"labels": {
"traefik.http.routers.api.rule": "Host(`traefik.example.com`)",
"traefik.http.routers.api.service": "api@internal",
"traefik.http.routers.api.middlewares": "auth",
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="File (YAML)"
# Dynamic Configuration
http:

View file

@ -51,15 +51,6 @@ spec:
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```json tab="Marathon"
"labels": {
"traefik.http.routers.dashboard.rule": "Host(`traefik.example.com`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))",
"traefik.http.routers.dashboard.service": "api@internal",
"traefik.http.routers.dashboard.middlewares": "auth",
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="File (YAML)"
# Dynamic Configuration
http:

View file

@ -1,583 +0,0 @@
---
title: "Traefik Configuration for Marathon"
description: "Traefik Proxy can be configured to use Marathon as a provider. Read the technical documentation to learn how."
---
# Traefik & Marathon
Traefik can be configured to use Marathon as a provider.
{: .subtitle }
For additional information, refer to [Marathon user guide](../user-guides/marathon.md).
## Configuration Examples
??? example "Configuring Marathon & Deploying / Exposing Applications"
Enabling the Marathon provider
```yaml tab="File (YAML)"
providers:
marathon: {}
```
```toml tab="File (TOML)"
[providers.marathon]
```
```bash tab="CLI"
--providers.marathon=true
```
Attaching labels to Marathon applications
```json
{
"id": "/whoami",
"container": {
"type": "DOCKER",
"docker": {
"image": "traefik/whoami",
"network": "BRIDGE",
"portMappings": [
{
"containerPort": 80,
"hostPort": 0,
"protocol": "tcp"
}
]
}
},
"labels": {
"traefik.http.Routers.app.Rule": "PathPrefix(`/app`)"
}
}
```
## Routing Configuration
See the dedicated section in [routing](../routing/providers/marathon.md).
## Provider Configuration
### `basic`
_Optional_
Enables Marathon basic authentication.
```yaml tab="File (YAML)"
providers:
marathon:
basic:
httpBasicAuthUser: foo
httpBasicPassword: bar
```
```toml tab="File (TOML)"
[providers.marathon.basic]
httpBasicAuthUser = "foo"
httpBasicPassword = "bar"
```
```bash tab="CLI"
--providers.marathon.basic.httpbasicauthuser=foo
--providers.marathon.basic.httpbasicpassword=bar
```
### `dcosToken`
_Optional_
Datacenter Operating System (DCOS) Token for DCOS environment.
If set, it overrides the Authorization header.
```toml tab="File (YAML)"
providers:
marathon:
dcosToken: "xxxxxx"
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
dcosToken = "xxxxxx"
# ...
```
```bash tab="CLI"
--providers.marathon.dcosToken=xxxxxx
```
### `defaultRule`
_Optional, Default=```Host(`{{ normalize .Name }}`)```_
The default host rule for all services.
For a given application, if no routing rule was defined by a label, it is defined by this `defaultRule` instead.
It must be a valid [Go template](https://pkg.go.dev/text/template/),
and can include [sprig template functions](https://masterminds.github.io/sprig/).
The app ID can be accessed with the `Name` identifier,
and the template has access to all the labels defined on this Marathon application.
```yaml tab="File (YAML)"
providers:
marathon:
defaultRule: "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)"
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
defaultRule = "Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)"
# ...
```
```bash tab="CLI"
--providers.marathon.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)
# ...
```
### `dialerTimeout`
_Optional, Default=5s_
Amount of time the Marathon provider should wait before timing out,
when trying to open a TCP connection to a Marathon master.
The value of `dialerTimeout` should be provided in seconds or as a valid duration format,
see [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration).
```yaml tab="File (YAML)"
providers:
marathon:
dialerTimeout: "10s"
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
dialerTimeout = "10s"
# ...
```
```bash tab="CLI"
--providers.marathon.dialerTimeout=10s
```
### `endpoint`
_Optional, Default=http://127.0.0.1:8080_
Marathon server endpoint.
You can optionally specify multiple endpoints.
```yaml tab="File (YAML)"
providers:
marathon:
endpoint: "http://10.241.1.71:8080,10.241.1.72:8080,10.241.1.73:8080"
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
endpoint = "http://10.241.1.71:8080,10.241.1.72:8080,10.241.1.73:8080"
# ...
```
```bash tab="CLI"
--providers.marathon.endpoint=http://10.241.1.71:8080,10.241.1.72:8080,10.241.1.73:8080
```
### `exposedByDefault`
_Optional, Default=true_
Exposes Marathon applications by default through Traefik.
If set to `false`, applications that do not have a `traefik.enable=true` label are ignored from the resulting routing configuration.
For additional information, refer to [Restrict the Scope of Service Discovery](./overview.md#restrict-the-scope-of-service-discovery).
```yaml tab="File (YAML)"
providers:
marathon:
exposedByDefault: false
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
exposedByDefault = false
# ...
```
```bash tab="CLI"
--providers.marathon.exposedByDefault=false
# ...
```
### `constraints`
_Optional, Default=""_
The `constraints` option can be set to an expression that Traefik matches against the application labels to determine whether
to create any route for that application. If none of the application labels match the expression, no route for that application is
created. In addition, the expression is also matched against the application constraints, such as described
in [Marathon constraints](https://mesosphere.github.io/marathon/docs/constraints.html).
If the expression is empty, all detected applications are included.
The expression syntax is based on the `Label("key", "value")`, and `LabelRegex("key", "value")` functions, as well as the usual boolean logic.
In addition, to match against Marathon constraints, the function `MarathonConstraint("field:operator:value")` can be used, where the field, operator, and value parts are concatenated in a single string using the `:` separator.
??? example "Constraints Expression Examples"
```toml
# Includes only applications having a label with key `a.label.name` and value `foo`
constraints = "Label(`a.label.name`, `foo`)"
```
```toml
# Excludes applications having any label with key `a.label.name` and value `foo`
constraints = "!Label(`a.label.name`, `value`)"
```
```toml
# With logical AND.
constraints = "Label(`a.label.name`, `valueA`) && Label(`another.label.name`, `valueB`)"
```
```toml
# With logical OR.
constraints = "Label(`a.label.name`, `valueA`) || Label(`another.label.name`, `valueB`)"
```
```toml
# With logical AND and OR, with precedence set by parentheses.
constraints = "Label(`a.label.name`, `valueA`) && (Label(`another.label.name`, `valueB`) || Label(`yet.another.label.name`, `valueC`))"
```
```toml
# Includes only applications having a label with key `a.label.name` and a value matching the `a.+` regular expression.
constraints = "LabelRegex(`a.label.name`, `a.+`)"
```
```toml
# Includes only applications having a Marathon constraint with field `A`, operator `B`, and value `C`.
constraints = "MarathonConstraint(`A:B:C`)"
```
```toml
# Uses both Marathon constraint and application label with logical operator.
constraints = "MarathonConstraint(`A:B:C`) && Label(`a.label.name`, `value`)"
```
For additional information, refer to [Restrict the Scope of Service Discovery](./overview.md#restrict-the-scope-of-service-discovery).
```yaml tab="File (YAML)"
providers:
marathon:
constraints: "Label(`a.label.name`,`foo`)"
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
constraints = "Label(`a.label.name`,`foo`)"
# ...
```
```bash tab="CLI"
--providers.marathon.constraints=Label(`a.label.name`,`foo`)
# ...
```
### `forceTaskHostname`
_Optional, Default=false_
By default, the task IP address (as returned by the Marathon API) is used as backend server if an IP-per-task configuration can be found;
otherwise, the name of the host running the task is used.
The latter behavior can be enforced by setting this option to `true`.
```yaml tab="File (YAML)"
providers:
marathon:
forceTaskHostname: true
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
forceTaskHostname = true
# ...
```
```bash tab="CLI"
--providers.marathon.forceTaskHostname=true
# ...
```
### `keepAlive`
_Optional, Default=10s_
Set the TCP Keep Alive duration for the Marathon HTTP Client.
The value of `keepAlive` should be provided in seconds or as a valid duration format,
see [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration).
```yaml tab="File (YAML)"
providers:
marathon:
keepAlive: "30s"
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
keepAlive = "30s"
# ...
```
```bash tab="CLI"
--providers.marathon.keepAlive=30s
# ...
```
### `respectReadinessChecks`
_Optional, Default=false_
Applications may define readiness checks which are probed by Marathon during deployments periodically, and these check results are exposed via the API.
Enabling `respectReadinessChecks` causes Traefik to filter out tasks whose readiness checks have not succeeded.
Note that the checks are only valid during deployments.
See the Marathon guide for details.
```yaml tab="File (YAML)"
providers:
marathon:
respectReadinessChecks: true
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
respectReadinessChecks = true
# ...
```
```bash tab="CLI"
--providers.marathon.respectReadinessChecks=true
# ...
```
### `responseHeaderTimeout`
_Optional, Default=60s_
Amount of time the Marathon provider should wait before timing out when waiting for the first response header
from a Marathon master.
The value of `responseHeaderTimeout` should be provided in seconds or as a valid duration format,
see [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration).
```yaml tab="File (YAML)"
providers:
marathon:
responseHeaderTimeout: "66s"
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
responseHeaderTimeout = "66s"
# ...
```
```bash tab="CLI"
--providers.marathon.responseHeaderTimeout=66s
# ...
```
### `tls`
_Optional_
Defines the TLS configuration used for the secure connection to Marathon.
#### `ca`
`ca` is the path to the certificate authority used for the secure connection to Marathon,
it defaults to the system bundle.
```yaml tab="File (YAML)"
providers:
marathon:
tls:
ca: path/to/ca.crt
```
```toml tab="File (TOML)"
[providers.marathon.tls]
ca = "path/to/ca.crt"
```
```bash tab="CLI"
--providers.marathon.tls.ca=path/to/ca.crt
```
#### `cert`
_Optional_
`cert` is the path to the public certificate used for the secure connection to Marathon.
When using this option, setting the `key` option is required.
```yaml tab="File (YAML)"
providers:
marathon:
tls:
cert: path/to/foo.cert
key: path/to/foo.key
```
```toml tab="File (TOML)"
[providers.marathon.tls]
cert = "path/to/foo.cert"
key = "path/to/foo.key"
```
```bash tab="CLI"
--providers.marathon.tls.cert=path/to/foo.cert
--providers.marathon.tls.key=path/to/foo.key
```
#### `key`
_Optional_
`key` is the path to the private key used for the secure connection to Marathon.
When using this option, setting the `cert` option is required.
```yaml tab="File (YAML)"
providers:
marathon:
tls:
cert: path/to/foo.cert
key: path/to/foo.key
```
```toml tab="File (TOML)"
[providers.marathon.tls]
cert = "path/to/foo.cert"
key = "path/to/foo.key"
```
```bash tab="CLI"
--providers.marathon.tls.cert=path/to/foo.cert
--providers.marathon.tls.key=path/to/foo.key
```
#### `insecureSkipVerify`
_Optional, Default=false_
If `insecureSkipVerify` is `true`, the TLS connection to Marathon accepts any certificate presented by the server regardless of the hostnames it covers.
```yaml tab="File (YAML)"
providers:
marathon:
tls:
insecureSkipVerify: true
```
```toml tab="File (TOML)"
[providers.marathon.tls]
insecureSkipVerify = true
```
```bash tab="CLI"
--providers.marathon.tls.insecureSkipVerify=true
```
### `tlsHandshakeTimeout`
_Optional, Default=5s_
Amount of time the Marathon provider should wait before timing out,
when waiting for the TLS handshake to complete.
The value of `tlsHandshakeTimeout` should be provided in seconds or as a valid duration format,
see [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration).
```yaml tab="File (YAML)"
providers:
marathon:
tlsHandshakeTimeout: "10s"
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
tlsHandshakeTimeout = "10s"
# ...
```
```bash tab="CLI"
--providers.marathon.tlsHandshakeTimeout=10s
# ...
```
### `trace`
_Optional, Default=false_
Displays additional provider logs when available.
```yaml tab="File (YAML)"
providers:
marathon:
trace: true
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
trace = true
# ...
```
```bash tab="CLI"
--providers.marathon.trace=true
# ...
```
### `watch`
_Optional, Default=true_
When set to `true`, watches for Marathon changes.
```yaml tab="File (YAML)"
providers:
marathon:
watch: false
# ...
```
```toml tab="File (TOML)"
[providers.marathon]
watch = false
# ...
```
```bash tab="CLI"
--providers.marathon.watch=false
# ...
```

View file

@ -141,7 +141,6 @@ Below is the list of the currently supported providers in Traefik.
| [Consul Catalog](./consul-catalog.md) | Orchestrator | Label | `consulcatalog` |
| [Nomad](./nomad.md) | Orchestrator | Label | `nomad` |
| [ECS](./ecs.md) | Orchestrator | Label | `ecs` |
| [Marathon](./marathon.md) | Orchestrator | Label | `marathon` |
| [File](./file.md) | Manual | YAML/TOML format | `file` |
| [Consul](./consul.md) | KV | KV | `consul` |
| [Etcd](./etcd.md) | KV | KV | `etcd` |
@ -215,7 +214,6 @@ List of providers that support these features:
- [ECS](./ecs.md#exposedbydefault)
- [Consul Catalog](./consul-catalog.md#exposedbydefault)
- [Nomad](./nomad.md#exposedbydefault)
- [Marathon](./marathon.md#exposedbydefault)
### Constraints
@ -225,7 +223,6 @@ List of providers that support constraints:
- [ECS](./ecs.md#constraints)
- [Consul Catalog](./consul-catalog.md#constraints)
- [Nomad](./nomad.md#constraints)
- [Marathon](./marathon.md#constraints)
- [Kubernetes CRD](./kubernetes-crd.md#labelselector)
- [Kubernetes Ingress](./kubernetes-ingress.md#labelselector)
- [Kubernetes Gateway](./kubernetes-gateway.md#labelselector)

View file

@ -1,210 +0,0 @@
"traefik.http.middlewares.middleware00.addprefix.prefix": "foobar",
"traefik.http.middlewares.middleware01.basicauth.headerfield": "foobar",
"traefik.http.middlewares.middleware01.basicauth.realm": "foobar",
"traefik.http.middlewares.middleware01.basicauth.removeheader": "true",
"traefik.http.middlewares.middleware01.basicauth.users": "foobar, foobar",
"traefik.http.middlewares.middleware01.basicauth.usersfile": "foobar",
"traefik.http.middlewares.middleware02.buffering.maxrequestbodybytes": "42",
"traefik.http.middlewares.middleware02.buffering.maxresponsebodybytes": "42",
"traefik.http.middlewares.middleware02.buffering.memrequestbodybytes": "42",
"traefik.http.middlewares.middleware02.buffering.memresponsebodybytes": "42",
"traefik.http.middlewares.middleware02.buffering.retryexpression": "foobar",
"traefik.http.middlewares.middleware03.chain.middlewares": "foobar, foobar",
"traefik.http.middlewares.middleware04.circuitbreaker.expression": "foobar",
"traefik.http.middlewares.middleware04.circuitbreaker.checkperiod": "42s",
"traefik.http.middlewares.middleware04.circuitbreaker.fallbackduration": "42s",
"traefik.http.middlewares.middleware04.circuitbreaker.recoveryduration": "42s",
"traefik.http.middlewares.middleware05.compress": "true",
"traefik.http.middlewares.middleware05.compress.excludedcontenttypes": "foobar, foobar",
"traefik.http.middlewares.middleware05.compress.minresponsebodybytes": "42",
"traefik.http.middlewares.middleware06.contenttype": "true",
"traefik.http.middlewares.middleware07.digestauth.headerfield": "foobar",
"traefik.http.middlewares.middleware07.digestauth.realm": "foobar",
"traefik.http.middlewares.middleware07.digestauth.removeheader": "true",
"traefik.http.middlewares.middleware07.digestauth.users": "foobar, foobar",
"traefik.http.middlewares.middleware07.digestauth.usersfile": "foobar",
"traefik.http.middlewares.middleware08.errors.query": "foobar",
"traefik.http.middlewares.middleware08.errors.service": "foobar",
"traefik.http.middlewares.middleware08.errors.status": "foobar, foobar",
"traefik.http.middlewares.middleware09.forwardauth.address": "foobar",
"traefik.http.middlewares.middleware09.forwardauth.authrequestheaders": "foobar, foobar",
"traefik.http.middlewares.middleware09.forwardauth.authresponseheaders": "foobar, foobar",
"traefik.http.middlewares.middleware09.forwardauth.authresponseheadersregex": "foobar",
"traefik.http.middlewares.middleware09.forwardauth.tls.ca": "foobar",
"traefik.http.middlewares.middleware09.forwardauth.tls.cert": "foobar",
"traefik.http.middlewares.middleware09.forwardauth.tls.insecureskipverify": "true",
"traefik.http.middlewares.middleware09.forwardauth.tls.key": "foobar",
"traefik.http.middlewares.middleware09.forwardauth.trustforwardheader": "true",
"traefik.http.middlewares.middleware10.headers.accesscontrolallowcredentials": "true",
"traefik.http.middlewares.middleware10.headers.accesscontrolallowheaders": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolallowmethods": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlist": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolalloworiginlistregex": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolexposeheaders": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.accesscontrolmaxage": "42",
"traefik.http.middlewares.middleware10.headers.addvaryheader": "true",
"traefik.http.middlewares.middleware10.headers.allowedhosts": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.browserxssfilter": "true",
"traefik.http.middlewares.middleware10.headers.contentsecuritypolicy": "foobar",
"traefik.http.middlewares.middleware10.headers.contenttypenosniff": "true",
"traefik.http.middlewares.middleware10.headers.custombrowserxssvalue": "foobar",
"traefik.http.middlewares.middleware10.headers.customframeoptionsvalue": "foobar",
"traefik.http.middlewares.middleware10.headers.customrequestheaders.name0": "foobar",
"traefik.http.middlewares.middleware10.headers.customrequestheaders.name1": "foobar",
"traefik.http.middlewares.middleware10.headers.customresponseheaders.name0": "foobar",
"traefik.http.middlewares.middleware10.headers.customresponseheaders.name1": "foobar",
"traefik.http.middlewares.middleware10.headers.forcestsheader": "true",
"traefik.http.middlewares.middleware10.headers.framedeny": "true",
"traefik.http.middlewares.middleware10.headers.hostsproxyheaders": "foobar, foobar",
"traefik.http.middlewares.middleware10.headers.isdevelopment": "true",
"traefik.http.middlewares.middleware10.headers.permissionspolicy": "foobar",
"traefik.http.middlewares.middleware10.headers.publickey": "foobar",
"traefik.http.middlewares.middleware10.headers.referrerpolicy": "foobar",
"traefik.http.middlewares.middleware10.headers.sslproxyheaders.name0": "foobar",
"traefik.http.middlewares.middleware10.headers.sslproxyheaders.name1": "foobar",
"traefik.http.middlewares.middleware10.headers.stsincludesubdomains": "true",
"traefik.http.middlewares.middleware10.headers.stspreload": "true",
"traefik.http.middlewares.middleware10.headers.stsseconds": "42",
"traefik.http.middlewares.middleware11.ipallowlist.ipstrategy.depth": "42",
"traefik.http.middlewares.middleware11.ipallowlist.ipstrategy.excludedips": "foobar, foobar",
"traefik.http.middlewares.middleware11.ipallowlist.sourcerange": "foobar, foobar",
"traefik.http.middlewares.middleware12.inflightreq.amount": "42",
"traefik.http.middlewares.middleware12.inflightreq.sourcecriterion.ipstrategy.depth": "42",
"traefik.http.middlewares.middleware12.inflightreq.sourcecriterion.ipstrategy.excludedips": "foobar, foobar",
"traefik.http.middlewares.middleware12.inflightreq.sourcecriterion.requestheadername": "foobar",
"traefik.http.middlewares.middleware12.inflightreq.sourcecriterion.requesthost": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.commonname": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.country": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.domaincomponent": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.locality": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.organization": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.province": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.issuer.serialnumber": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.notafter": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.notbefore": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.sans": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.serialnumber": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.commonname": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.country": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.domaincomponent": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.locality": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.organization": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.organizationalunit": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.province": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.info.subject.serialnumber": "true",
"traefik.http.middlewares.middleware13.passtlsclientcert.pem": "true",
"traefik.http.middlewares.middleware14.plugin.foobar.foo": "bar",
"traefik.http.middlewares.middleware15.ratelimit.average": "42",
"traefik.http.middlewares.middleware15.ratelimit.burst": "42",
"traefik.http.middlewares.middleware15.ratelimit.period": "42",
"traefik.http.middlewares.middleware15.ratelimit.sourcecriterion.ipstrategy.depth": "42",
"traefik.http.middlewares.middleware15.ratelimit.sourcecriterion.ipstrategy.excludedips": "foobar, foobar",
"traefik.http.middlewares.middleware15.ratelimit.sourcecriterion.requestheadername": "foobar",
"traefik.http.middlewares.middleware15.ratelimit.sourcecriterion.requesthost": "true",
"traefik.http.middlewares.middleware16.redirectregex.permanent": "true",
"traefik.http.middlewares.middleware16.redirectregex.regex": "foobar",
"traefik.http.middlewares.middleware16.redirectregex.replacement": "foobar",
"traefik.http.middlewares.middleware17.redirectscheme.permanent": "true",
"traefik.http.middlewares.middleware17.redirectscheme.port": "foobar",
"traefik.http.middlewares.middleware17.redirectscheme.scheme": "foobar",
"traefik.http.middlewares.middleware18.replacepath.path": "foobar",
"traefik.http.middlewares.middleware19.replacepathregex.regex": "foobar",
"traefik.http.middlewares.middleware19.replacepathregex.replacement": "foobar",
"traefik.http.middlewares.middleware20.retry.attempts": "42",
"traefik.http.middlewares.middleware20.retry.initialinterval": "42",
"traefik.http.middlewares.middleware21.stripprefix.prefixes": "foobar, foobar",
"traefik.http.middlewares.middleware22.stripprefixregex.regex": "foobar, foobar",
"traefik.http.middlewares.middleware23.grpcweb.alloworigins": "foobar, foobar",
"traefik.http.routers.router0.entrypoints": "foobar, foobar",
"traefik.http.routers.router0.middlewares": "foobar, foobar",
"traefik.http.routers.router0.priority": "42",
"traefik.http.routers.router0.rule": "foobar",
"traefik.http.routers.router0.service": "foobar",
"traefik.http.routers.router0.tls": "true",
"traefik.http.routers.router0.tls.certresolver": "foobar",
"traefik.http.routers.router0.tls.domains[0].main": "foobar",
"traefik.http.routers.router0.tls.domains[0].sans": "foobar, foobar",
"traefik.http.routers.router0.tls.domains[1].main": "foobar",
"traefik.http.routers.router0.tls.domains[1].sans": "foobar, foobar",
"traefik.http.routers.router0.tls.options": "foobar",
"traefik.http.routers.router1.entrypoints": "foobar, foobar",
"traefik.http.routers.router1.middlewares": "foobar, foobar",
"traefik.http.routers.router1.priority": "42",
"traefik.http.routers.router1.rule": "foobar",
"traefik.http.routers.router1.service": "foobar",
"traefik.http.routers.router1.tls": "true",
"traefik.http.routers.router1.tls.certresolver": "foobar",
"traefik.http.routers.router1.tls.domains[0].main": "foobar",
"traefik.http.routers.router1.tls.domains[0].sans": "foobar, foobar",
"traefik.http.routers.router1.tls.domains[1].main": "foobar",
"traefik.http.routers.router1.tls.domains[1].sans": "foobar, foobar",
"traefik.http.routers.router1.tls.options": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.followredirects": "true",
"traefik.http.services.service01.loadbalancer.healthcheck.headers.name0": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.headers.name1": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.hostname": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.interval": "42s",
"traefik.http.services.service01.loadbalancer.healthcheck.path": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.method": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.status": "42",
"traefik.http.services.service01.loadbalancer.healthcheck.port": "42",
"traefik.http.services.service01.loadbalancer.healthcheck.scheme": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.mode": "foobar",
"traefik.http.services.service01.loadbalancer.healthcheck.timeout": "42s",
"traefik.http.services.service01.loadbalancer.passhostheader": "true",
"traefik.http.services.service01.loadbalancer.responseforwarding.flushinterval": "42s",
"traefik.http.services.service01.loadbalancer.serverstransport": "foobar",
"traefik.http.services.service01.loadbalancer.sticky.cookie": "true",
"traefik.http.services.service01.loadbalancer.sticky.cookie.httponly": "true",
"traefik.http.services.service01.loadbalancer.sticky.cookie.name": "foobar",
"traefik.http.services.service01.loadbalancer.sticky.cookie.samesite": "foobar",
"traefik.http.services.service01.loadbalancer.sticky.cookie.secure": "true",
"traefik.http.services.service01.loadbalancer.server.port": "foobar",
"traefik.http.services.service01.loadbalancer.server.scheme": "foobar",
"traefik.tcp.middlewares.tcpmiddleware00.ipallowlist.sourcerange": "foobar, foobar",
"traefik.tcp.middlewares.tcpmiddleware01.inflightconn.amount": "42",
"traefik.tcp.routers.tcprouter0.entrypoints": "foobar, foobar",
"traefik.tcp.routers.tcprouter0.middlewares": "foobar, foobar",
"traefik.tcp.routers.tcprouter0.rule": "foobar",
"traefik.tcp.routers.tcprouter0.priority": "42",
"traefik.tcp.routers.tcprouter0.service": "foobar",
"traefik.tcp.routers.tcprouter0.tls": "true",
"traefik.tcp.routers.tcprouter0.tls.certresolver": "foobar",
"traefik.tcp.routers.tcprouter0.tls.domains[0].main": "foobar",
"traefik.tcp.routers.tcprouter0.tls.domains[0].sans": "foobar, foobar",
"traefik.tcp.routers.tcprouter0.tls.domains[1].main": "foobar",
"traefik.tcp.routers.tcprouter0.tls.domains[1].sans": "foobar, foobar",
"traefik.tcp.routers.tcprouter0.tls.options": "foobar",
"traefik.tcp.routers.tcprouter0.tls.passthrough": "true",
"traefik.tcp.routers.tcprouter1.entrypoints": "foobar, foobar",
"traefik.tcp.routers.tcprouter1.middlewares": "foobar, foobar",
"traefik.tcp.routers.tcprouter1.rule": "foobar",
"traefik.tcp.routers.tcprouter1.priority": "42",
"traefik.tcp.routers.tcprouter1.service": "foobar",
"traefik.tcp.routers.tcprouter1.tls": "true",
"traefik.tcp.routers.tcprouter1.tls.certresolver": "foobar",
"traefik.tcp.routers.tcprouter1.tls.domains[0].main": "foobar",
"traefik.tcp.routers.tcprouter1.tls.domains[0].sans": "foobar, foobar",
"traefik.tcp.routers.tcprouter1.tls.domains[1].main": "foobar",
"traefik.tcp.routers.tcprouter1.tls.domains[1].sans": "foobar, foobar",
"traefik.tcp.routers.tcprouter1.tls.options": "foobar",
"traefik.tcp.routers.tcprouter1.tls.passthrough": "true",
"traefik.tcp.services.tcpservice01.loadbalancer.proxyprotocol.version": "42",
"traefik.tcp.services.tcpservice01.loadbalancer.server.port": "foobar",
"traefik.tcp.services.tcpservice01.loadbalancer.server.tls": "true",
"traefik.tcp.services.tcpservice01.loadbalancer.serverstransport": "foobar",
"traefik.udp.routers.udprouter0.entrypoints": "foobar, foobar",
"traefik.udp.routers.udprouter0.service": "foobar",
"traefik.udp.routers.udprouter1.entrypoints": "foobar, foobar",
"traefik.udp.routers.udprouter1.service": "foobar",
"traefik.udp.services.udpservice01.loadbalancer.server.port": "foobar",
"traefik.tls.stores.Store0.defaultcertificate.certfile": "foobar",
"traefik.tls.stores.Store0.defaultcertificate.keyfile": "foobar",
"traefik.tls.stores.Store0.defaultgeneratedcert.domain.main": "foobar",
"traefik.tls.stores.Store0.defaultgeneratedcert.domain.sans": "foobar, foobar",
"traefik.tls.stores.Store0.defaultgeneratedcert.resolver": "foobar",
"traefik.tls.stores.Store1.defaultcertificate.certfile": "foobar",
"traefik.tls.stores.Store1.defaultcertificate.keyfile": "foobar",
"traefik.tls.stores.Store1.defaultgeneratedcert.domain.main": "foobar",
"traefik.tls.stores.Store1.defaultgeneratedcert.domain.sans": "foobar, foobar",
"traefik.tls.stores.Store1.defaultgeneratedcert.resolver": "foobar",

View file

@ -1,2 +0,0 @@
"traefik.enable": "true",
"traefik.marathon.ipaddressidx": "42",

View file

@ -1,16 +0,0 @@
---
title: "Dynamic Configuration with Marathon Labels"
description: "Traefik Proxy can be configured to use Marathon as a provider. Read the technical documentation on the Traefik dynamic configuration with Marathon Labels."
---
# Marathon Configuration Reference
Dynamic configuration with Marathon Labels
{: .subtitle }
```json
"labels": {
--8<-- "content/reference/dynamic-configuration/marathon.json"
--8<-- "content/reference/dynamic-configuration/marathon-labels.json"
}
```

View file

@ -798,66 +798,6 @@ Ingress refresh throttle duration (Default: ```0```)
`--providers.kubernetesingress.token`:
Kubernetes bearer token (not needed for in-cluster client).
`--providers.marathon`:
Enable Marathon backend with default settings. (Default: ```false```)
`--providers.marathon.basic.httpbasicauthuser`:
Basic authentication User.
`--providers.marathon.basic.httpbasicpassword`:
Basic authentication Password.
`--providers.marathon.constraints`:
Constraints is an expression that Traefik matches against the application's labels to determine whether to create any route for that application.
`--providers.marathon.dcostoken`:
DCOSToken for DCOS environment, This will override the Authorization header.
`--providers.marathon.defaultrule`:
Default rule. (Default: ```Host(`{{ normalize .Name }}`)```)
`--providers.marathon.dialertimeout`:
Set a dialer timeout for Marathon. (Default: ```5```)
`--providers.marathon.endpoint`:
Marathon server endpoint. You can also specify multiple endpoint for Marathon. (Default: ```http://127.0.0.1:8080```)
`--providers.marathon.exposedbydefault`:
Expose Marathon apps by default. (Default: ```true```)
`--providers.marathon.forcetaskhostname`:
Force to use the task's hostname. (Default: ```false```)
`--providers.marathon.keepalive`:
Set a TCP Keep Alive time. (Default: ```10```)
`--providers.marathon.respectreadinesschecks`:
Filter out tasks with non-successful readiness checks during deployments. (Default: ```false```)
`--providers.marathon.responseheadertimeout`:
Set a response header timeout for Marathon. (Default: ```60```)
`--providers.marathon.tls.ca`:
TLS CA
`--providers.marathon.tls.cert`:
TLS cert
`--providers.marathon.tls.insecureskipverify`:
TLS insecure skip verify (Default: ```false```)
`--providers.marathon.tls.key`:
TLS key
`--providers.marathon.tlshandshaketimeout`:
Set a TLS handshake timeout for Marathon. (Default: ```5```)
`--providers.marathon.trace`:
Display additional provider logs. (Default: ```false```)
`--providers.marathon.watch`:
Watch provider. (Default: ```true```)
`--providers.nomad`:
Enable Nomad backend with default settings. (Default: ```false```)

View file

@ -798,66 +798,6 @@ Ingress refresh throttle duration (Default: ```0```)
`TRAEFIK_PROVIDERS_KUBERNETESINGRESS_TOKEN`:
Kubernetes bearer token (not needed for in-cluster client).
`TRAEFIK_PROVIDERS_MARATHON`:
Enable Marathon backend with default settings. (Default: ```false```)
`TRAEFIK_PROVIDERS_MARATHON_BASIC_HTTPBASICAUTHUSER`:
Basic authentication User.
`TRAEFIK_PROVIDERS_MARATHON_BASIC_HTTPBASICPASSWORD`:
Basic authentication Password.
`TRAEFIK_PROVIDERS_MARATHON_CONSTRAINTS`:
Constraints is an expression that Traefik matches against the application's labels to determine whether to create any route for that application.
`TRAEFIK_PROVIDERS_MARATHON_DCOSTOKEN`:
DCOSToken for DCOS environment, This will override the Authorization header.
`TRAEFIK_PROVIDERS_MARATHON_DEFAULTRULE`:
Default rule. (Default: ```Host(`{{ normalize .Name }}`)```)
`TRAEFIK_PROVIDERS_MARATHON_DIALERTIMEOUT`:
Set a dialer timeout for Marathon. (Default: ```5```)
`TRAEFIK_PROVIDERS_MARATHON_ENDPOINT`:
Marathon server endpoint. You can also specify multiple endpoint for Marathon. (Default: ```http://127.0.0.1:8080```)
`TRAEFIK_PROVIDERS_MARATHON_EXPOSEDBYDEFAULT`:
Expose Marathon apps by default. (Default: ```true```)
`TRAEFIK_PROVIDERS_MARATHON_FORCETASKHOSTNAME`:
Force to use the task's hostname. (Default: ```false```)
`TRAEFIK_PROVIDERS_MARATHON_KEEPALIVE`:
Set a TCP Keep Alive time. (Default: ```10```)
`TRAEFIK_PROVIDERS_MARATHON_RESPECTREADINESSCHECKS`:
Filter out tasks with non-successful readiness checks during deployments. (Default: ```false```)
`TRAEFIK_PROVIDERS_MARATHON_RESPONSEHEADERTIMEOUT`:
Set a response header timeout for Marathon. (Default: ```60```)
`TRAEFIK_PROVIDERS_MARATHON_TLSHANDSHAKETIMEOUT`:
Set a TLS handshake timeout for Marathon. (Default: ```5```)
`TRAEFIK_PROVIDERS_MARATHON_TLS_CA`:
TLS CA
`TRAEFIK_PROVIDERS_MARATHON_TLS_CERT`:
TLS cert
`TRAEFIK_PROVIDERS_MARATHON_TLS_INSECURESKIPVERIFY`:
TLS insecure skip verify (Default: ```false```)
`TRAEFIK_PROVIDERS_MARATHON_TLS_KEY`:
TLS key
`TRAEFIK_PROVIDERS_MARATHON_TRACE`:
Display additional provider logs. (Default: ```false```)
`TRAEFIK_PROVIDERS_MARATHON_WATCH`:
Watch provider. (Default: ```true```)
`TRAEFIK_PROVIDERS_NOMAD`:
Enable Nomad backend with default settings. (Default: ```false```)

View file

@ -98,28 +98,6 @@
watch = true
filename = "foobar"
debugLogGeneratedTemplate = true
[providers.marathon]
constraints = "foobar"
trace = true
watch = true
endpoint = "foobar"
defaultRule = "foobar"
exposedByDefault = true
dcosToken = "foobar"
dialerTimeout = "42s"
responseHeaderTimeout = "42s"
tlsHandshakeTimeout = "42s"
keepAlive = "42s"
forceTaskHostname = true
respectReadinessChecks = true
[providers.marathon.tls]
ca = "foobar"
cert = "foobar"
key = "foobar"
insecureSkipVerify = true
[providers.marathon.basic]
httpBasicAuthUser = "foobar"
httpBasicPassword = "foobar"
[providers.kubernetesIngress]
endpoint = "foobar"
token = "foobar"

View file

@ -105,28 +105,6 @@ providers:
watch: true
filename: foobar
debugLogGeneratedTemplate: true
marathon:
constraints: foobar
trace: true
watch: true
endpoint: foobar
defaultRule: foobar
exposedByDefault: true
dcosToken: foobar
tls:
ca: foobar
cert: foobar
key: foobar
insecureSkipVerify: true
dialerTimeout: 42s
responseHeaderTimeout: 42s
tlsHandshakeTimeout: 42s
keepAlive: 42s
forceTaskHostname: true
basic:
httpBasicAuthUser: foobar
httpBasicPassword: foobar
respectReadinessChecks: true
kubernetesIngress:
endpoint: foobar
token: foobar

View file

@ -1,545 +0,0 @@
---
title: "Traefik Routing Configuration for Marathon"
description: "Traefik Proxy can be configured to use Marathon as a provider. Read the technical documentation to understand the Traefik routing configuration for Marathon."
---
# Traefik & Marathon
Traefik can be configured to use Marathon as a provider.
{: .subtitle }
See also [Marathon user guide](../../user-guides/marathon.md).
## Routing Configuration
!!! info "Labels"
- Labels are case insensitive.
- The complete list of labels can be found in [the reference page](../../reference/dynamic-configuration/marathon.md).
### General
Traefik creates, for each Marathon application, a corresponding [service](../services/index.md) and [router](../routers/index.md).
The Service automatically gets a server per instance of the application,
and the router automatically gets a rule defined by defaultRule (if no rule for it was defined in labels).
#### Service definition
--8<-- "content/routing/providers/service-by-label.md"
??? example "Automatic service assignment with labels"
Service myservice gets automatically assigned to router myproxy.
```json
labels: {
"traefik.http.routers.myproxy.rule": "Host(`example.net`)",
"traefik.http.services.myservice.loadbalancer.server.port": "80"
}
```
??? example "Automatic service creation and assignment with labels"
No service specified or defined, and yet one gets automatically created.
and assigned to router myproxy.
```json
labels: {
"traefik.http.routers.myproxy.rule": "Host(`example.net`)"
}
```
### Routers
To update the configuration of the Router automatically attached to the application,
add labels starting with `traefik.http.routers.{router-name-of-your-choice}.` and followed by the option you want to change.
For example, to change the routing rule, you could add the label ```"traefik.http.routers.routername.rule": "Host(`example.com`)"```.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
??? info "`traefik.http.routers.<router_name>.rule`"
See [rule](../routers/index.md#rule) for more information.
```json
"traefik.http.routers.myrouter.rule": "Host(`example.com`)"
```
??? info "`traefik.http.routers.<router_name>.entrypoints`"
See [entry points](../routers/index.md#entrypoints) for more information.
```json
"traefik.http.routers.myrouter.entrypoints": "ep1,ep2"
```
??? info "`traefik.http.routers.<router_name>.middlewares`"
See [middlewares](../routers/index.md#middlewares) and [middlewares overview](../../middlewares/overview.md) for more information.
```json
"traefik.http.routers.myrouter.middlewares": "auth,prefix,cb"
```
??? info "`traefik.http.routers.<router_name>.service`"
See [rule](../routers/index.md#service) for more information.
```json
"traefik.http.routers.myrouter.service": "myservice"
```
??? info "`traefik.http.routers.<router_name>.tls`"
See [tls](../routers/index.md#tls) for more information.
```json
"traefik.http.routers.myrouter.tls": "true"
```
??? info "`traefik.http.routers.<router_name>.tls.certresolver`"
See [certResolver](../routers/index.md#certresolver) for more information.
```json
"traefik.http.routers.myrouter.tls.certresolver": "myresolver"
```
??? info "`traefik.http.routers.<router_name>.tls.domains[n].main`"
See [domains](../routers/index.md#domains) for more information.
```json
"traefik.http.routers.myrouter.tls.domains[0].main": "example.org"
```
??? info "`traefik.http.routers.<router_name>.tls.domains[n].sans`"
See [domains](../routers/index.md#domains) for more information.
```json
"traefik.http.routers.myrouter.tls.domains[0].sans": "test.example.org,dev.example.org"
```
??? info "`traefik.http.routers.<router_name>.tls.options`"
See [options](../routers/index.md#options) for more information.
```json
"traefik.http.routers.myrouter.tls.options": "foobar"
```
??? info "`traefik.http.routers.<router_name>.priority`"
See [priority](../routers/index.md#priority) for more information.
```json
"traefik.http.routers.myrouter.priority": "42"
```
### Services
To update the configuration of the Service automatically attached to the container,
add labels starting with `traefik.http.services.{service-name-of-your-choice}.`, followed by the option you want to change.
For example, to change the passHostHeader behavior, you'd add the label `"traefik.http.services.servicename.loadbalancer.passhostheader": "false"`.
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
??? info "`traefik.http.services.<service_name>.loadbalancer.server.port`"
Registers a port.
Useful when the container exposes multiples ports.
```json
"traefik.http.services.myservice.loadbalancer.server.port": "8080"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.server.scheme`"
Overrides the default scheme.
```json
"traefik.http.services.myservice.loadbalancer.server.scheme": "http"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
See [serverstransport](../services/index.md#serverstransport) for more information.
```json
"traefik.http.services.<service_name>.loadbalancer.serverstransport": "foobar@file"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.passhostheader`"
See [pass Host header](../services/index.md#pass-host-header) for more information.
```json
"traefik.http.services.myservice.loadbalancer.passhostheader": "true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.headers.<header_name>`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.headers.X-Foo": "foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.hostname`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.hostname": "example.org"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.interval`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.interval": "10"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.path`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.path": "/foo"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.method`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.method": "foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.status`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.status": "42"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.port`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.port": "42"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.scheme`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.scheme": "http"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.timeout`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.timeout": "10"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.healthcheck.followredirects`"
See [health check](../services/index.md#health-check) for more information.
```json
"traefik.http.services.myservice.loadbalancer.healthcheck.followredirects": "true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```json
"traefik.http.services.myservice.loadbalancer.sticky.cookie": "true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.httponly`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```json
"traefik.http.services.myservice.loadbalancer.sticky.cookie.httponly": "true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.name`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```json
"traefik.http.services.myservice.loadbalancer.sticky.cookie.name": "foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```json
"traefik.http.services.myservice.loadbalancer.sticky.cookie.secure": "true"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.samesite`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```json
"traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite": "none"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
See [response forwarding](../services/index.md#response-forwarding) for more information.
```json
"traefik.http.services.myservice.loadbalancer.responseforwarding.flushinterval": "10"
```
### Middleware
You can declare pieces of middleware using labels starting with `traefik.http.middlewares.{middleware-name-of-your-choice}.`, followed by the middleware type/options.
For example, to declare a middleware [`redirectscheme`](../../middlewares/http/redirectscheme.md) named `my-redirect`, you'd write `"traefik.http.middlewares.my-redirect.redirectscheme.scheme": "https"`.
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).
!!! warning "The character `@` is not authorized in the middleware name."
??? example "Declaring and Referencing a Middleware"
```json
{
...
"labels": {
"traefik.http.middlewares.my-redirect.redirectscheme.scheme": "https",
"traefik.http.routers.my-container.middlewares": "my-redirect"
}
}
```
!!! warning "Conflicts in Declaration"
If you declare multiple middleware with the same name but with different parameters, the middleware fails to be declared.
### TCP
You can declare TCP Routers and/or Services using labels.
??? example "Declaring TCP Routers and Services"
```json
{
...
"labels": {
"traefik.tcp.routers.my-router.rule": "HostSNI(`example.com`)",
"traefik.tcp.routers.my-router.tls": "true",
"traefik.tcp.services.my-service.loadbalancer.server.port": "4123"
}
}
```
!!! warning "TCP and HTTP"
If you declare a TCP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no TCP Router/Service is defined).
You can declare both a TCP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually).
#### TCP Routers
??? info "`traefik.tcp.routers.<router_name>.entrypoints`"
See [entry points](../routers/index.md#entrypoints_1) for more information.
```json
"traefik.tcp.routers.mytcprouter.entrypoints": "ep1,ep2"
```
??? info "`traefik.tcp.routers.<router_name>.rule`"
See [rule](../routers/index.md#rule_1) for more information.
```json
"traefik.tcp.routers.mytcprouter.rule": "HostSNI(`example.com`)"
```
??? info "`traefik.tcp.routers.<router_name>.service`"
See [service](../routers/index.md#services) for more information.
```json
"traefik.tcp.routers.mytcprouter.service": "myservice"
```
??? info "`traefik.tcp.routers.<router_name>.tls`"
See [TLS](../routers/index.md#tls_1) for more information.
```json
"traefik.tcp.routers.mytcprouter.tls": "true
```
??? info "`traefik.tcp.routers.<router_name>.tls.certresolver`"
See [certResolver](../routers/index.md#certresolver_1) for more information.
```json
"traefik.tcp.routers.mytcprouter.tls.certresolver": "myresolver"
```
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].main`"
See [domains](../routers/index.md#domains_1) for more information.
```json
"traefik.tcp.routers.mytcprouter.tls.domains[0].main": "example.org"
```
??? info "`traefik.tcp.routers.<router_name>.tls.domains[n].sans`"
See [domains](../routers/index.md#domains_1) for more information.
```json
"traefik.tcp.routers.mytcprouter.tls.domains[0].sans": "test.example.org,dev.example.org"
```
??? info "`traefik.tcp.routers.<router_name>.tls.options`"
See [options](../routers/index.md#options_1) for more information.
```json
"traefik.tcp.routers.mytcprouter.tls.options": "mysoptions"
```
??? info "`traefik.tcp.routers.<router_name>.tls.passthrough`"
See [TLS](../routers/index.md#tls_1) for more information.
```json
"traefik.tcp.routers.mytcprouter.tls.passthrough": "true"
```
??? info "`traefik.tcp.routers.<router_name>.priority`"
See [priority](../routers/index.md#priority_1) for more information.
```json
"traefik.tcp.routers.myrouter.priority": "42"
```
#### TCP Services
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.port`"
Registers a port of the application.
```json
"traefik.tcp.services.mytcpservice.loadbalancer.server.port": "423"
```
??? info "`traefik.tcp.services.<service_name>.loadbalancer.server.tls`"
Determines whether to use TLS when dialing with the backend.
```json
"traefik.tcp.services.mytcpservice.loadbalancer.server.tls": "true"
```
??? info "`traefik.tcp.services.<service_name>.loadbalancer.proxyprotocol.version`"
See [PROXY protocol](../services/index.md#proxy-protocol) for more information.
```json
"traefik.tcp.services.mytcpservice.loadbalancer.proxyprotocol.version": "1"
```
??? info "`traefik.tcp.services.<service_name>.loadbalancer.serverstransport`"
Allows to reference a ServersTransport resource that is defined either with the File provider or the Kubernetes CRD one.
See [serverstransport](../services/index.md#serverstransport_2) for more information.
```json
"traefik.tcp.services.<service_name>.loadbalancer.serverstransport": "foobar@file"
```
### UDP
You can declare UDP Routers and/or Services using labels.
??? example "Declaring UDP Routers and Services"
```json
{
...
"labels": {
"traefik.udp.routers.my-router.entrypoints": "udp",
"traefik.udp.services.my-service.loadbalancer.server.port": "4123"
}
}
```
!!! warning "UDP and HTTP"
If you declare a UDP Router/Service, it will prevent Traefik from automatically creating an HTTP Router/Service (like it does by default if no UDP Router/Service is defined).
You can declare both a UDP Router/Service and an HTTP Router/Service for the same container (but you have to do so manually).
#### UDP Routers
??? info "`traefik.udp.routers.<router_name>.entrypoints`"
See [entry points](../routers/index.md#entrypoints_2) for more information.
```json
"traefik.udp.routers.myudprouter.entrypoints": "ep1,ep2"
```
??? info "`traefik.udp.routers.<router_name>.service`"
See [service](../routers/index.md#services_1) for more information.
```json
"traefik.udp.routers.myudprouter.service": "myservice"
```
#### UDP Services
??? info "`traefik.udp.services.<service_name>.loadbalancer.server.port`"
Registers a port of the application.
```json
"traefik.udp.services.myudpservice.loadbalancer.server.port": "423"
```
### Specific Provider Options
#### `traefik.enable`
```json
"traefik.enable": "true"
```
Setting this option controls whether Traefik exposes the application.
It overrides the value of `exposedByDefault`.
#### `traefik.marathon.ipadressidx`
```json
"traefik.marathon.ipadressidx": "1"
```
If a task has several IP addresses, this option specifies which one, in the list of available addresses, to select.

View file

@ -557,8 +557,7 @@ which is basically where the request will be passed along to.
In general, a service assigned to a router should have been defined,
but there are exceptions for label-based providers.
See the specific [docker](../providers/docker.md#service-definition),
or [marathon](../providers/marathon.md#service-definition) documentation.
See the specific [docker](../providers/docker.md#service-definition) documentation.
!!! warning "The character `@` is not authorized in the service name."

View file

@ -1,133 +0,0 @@
---
title: "Traefik Proxy and Marathon Integration Guide |Traefik Docs"
description: "This guide explains how to integrate Marathon and operate the cluster in a reliable way from the Traefik Proxy standpoint."
---
# Marathon
This guide explains how to integrate Marathon and operate the cluster in a reliable way from Traefik's standpoint.
## Host detection
Marathon offers multiple ways to run (Docker-containerized) applications, the most popular ones being
- BRIDGE-networked containers with dynamic high ports exposed
- HOST-networked containers with host machine ports
- containers with dedicated IP addresses ([IP-per-task](https://mesosphere.github.io/marathon/docs/ip-per-task.html)).
Traefik tries to detect the configured mode and route traffic to the right IP addresses. It is possible to force using task hosts with the `forceTaskHostname` option.
## Port detection
Traefik also attempts to determine the right port (which is a [non-trivial matter in Marathon](https://mesosphere.github.io/marathon/docs/ports.html)) from the following sources:
1. An arbitrary port specified through label `traefik.http.services.serviceName.loadbalancer.server.port=8080`
1. The task port.
1. The port from the application's `portDefinitions` field.
1. The port from the application's `ipAddressPerTask` field.
### Port label syntax
To select a port, you can either
- specify the port directly: `traefik.http.services.serviceName.loadbalancer.server.port=8080`
- specify a port index: `traefik.http.services.serviceName.loadbalancer.server.port=index:0`
- specify a port name: `traefik.http.services.serviceName.loadbalancer.server.port=name:http`
- otherwise the first one is selected.
## Achieving high availability
### Scenarios
There are three scenarios where the availability of a Marathon application could be impaired along with the risk of losing or failing requests:
- During the startup phase when Traefik already routes requests to the backend even though it has not completed its bootstrapping process yet.
- During the shutdown phase when Traefik still routes requests to the backend while the backend is already terminating.
- During a failure of the application when Traefik has not yet identified the backend as being erroneous.
The first two scenarios are common with every rolling upgrade of an application (i.e. a new version release or configuration update).
The following sub-sections describe how to resolve or mitigate each scenario.
#### Startup
It is possible to define [readiness checks](https://mesosphere.github.io/marathon/docs/readiness-checks.html) (available since Marathon version 1.1) per application and have Marathon take these into account during the startup phase.
The idea is that each application provides an HTTP endpoint that Marathon queries periodically during an ongoing deployment in order to mark the associated readiness check result as successful if and only if the endpoint returns a response within the configured HTTP code range.
As long as the check keeps failing, Marathon will not proceed with the deployment (within the configured upgrade strategy bounds).
Beginning with version 1.4, Traefik respects readiness check results if the Traefik option is set and checks are configured on the applications accordingly.
!!! note
Due to the way readiness check results are currently exposed by the Marathon API, ready tasks may be taken into rotation with a small delay.
It is on the order of one readiness check timeout interval (as configured on the application specification) and guarantees that non-ready tasks do not receive traffic prematurely.
If readiness checks are not possible, a current mitigation strategy is to enable [retries](../middlewares/http/retry.md) and make sure that a sufficient number of healthy application tasks exist so that one retry will likely hit one of those.
Apart from its probabilistic nature, the workaround comes at the price of increased latency.
#### Shutdown
It is possible to install a [termination handler](https://mesosphere.github.io/marathon/docs/health-checks.html) (available since Marathon version 1.3) with each application whose responsibility it is to delay the shutdown process long enough until the backend has been taken out of load-balancing rotation with reasonable confidence (i.e., Traefik has received an update from the Marathon event bus, recomputes the available Marathon backends, and applies the new configuration).
Specifically, each termination handler should install a signal handler listening for a SIGTERM signal and implement the following steps on signal reception:
1. Disable Keep-Alive HTTP connections.
1. Keep accepting HTTP requests for a certain period of time.
1. Stop accepting new connections.
1. Finish serving any in-flight requests.
1. Shut down.
Traefik already ignores Marathon tasks whose state does not match `TASK_RUNNING`; since terminating tasks transition into the `TASK_KILLING` and eventually `TASK_KILLED` state, there is nothing further that needs to be done on Traefik's end.
How long HTTP requests should continue to be accepted in step 2 depends on how long Traefik needs to receive and process the Marathon configuration update.
Under regular operational conditions, it should be on the order of seconds, with 10 seconds possibly being a good default value.
Again, configuring Traefik to do retries (as discussed in the previous section) can serve as a decent workaround strategy.
Paired with termination handlers, they would cover for those cases where either the termination sequence or Traefik cannot complete their part of the orchestration process in time.
#### Failure
A failing application always happens unexpectedly, and hence, it is very difficult or even impossible to rule out the adversal effects categorically.
Failure reasons vary broadly and could stretch from unacceptable slowness, a task crash, or a network split.
There are two mitigation efforts:
1. Configure [Marathon health checks](https://mesosphere.github.io/marathon/docs/health-checks.html) on each application.
2. Configure Traefik health checks (possibly via the `traefik.http.services.yourServiceName.loadbalancer.healthcheck.*` labels) and make sure they probe with proper frequency.
The Marathon health check makes sure that applications once deemed dysfunctional are being rescheduled to different slaves.
However, they might take a while to get triggered and the follow-up processes to complete.
For that reason, the Traefik health check provides an additional check that responds more rapidly and does not require a configuration reload to happen.
Additionally, it protects from cases that the Marathon health check may not be able to cover, such as a network split.
### (Non-)Alternatives
There are a few alternatives of varying quality that are frequently asked for.
The remaining section is going to explore them along with a benefit/cost trade-off.
#### Reusing Marathon health checks
It may seem obvious to reuse the Marathon health checks as a signal to Traefik whether an application should be taken into load-balancing rotation or not.
Apart from the increased latency a failing health check may have, a major problem with this is that Marathon does not persist the health check results.
Consequently, if a master re-election occurs in the Marathon clusters, all health check results will revert to the _unknown_ state, effectively causing all applications inside the cluster to become unavailable and leading to a complete cluster failure.
Re-elections do not only happen during regular maintenance work (often requiring rolling upgrades of the Marathon nodes) but also when the Marathon leader fails spontaneously.
As such, there is no way to handle this situation deterministically.
Finally, Marathon health checks are not mandatory (the default is to use the task state as reported by Mesos), so requiring them for Traefik would raise the entry barrier for Marathon users.
Traefik used to use the health check results as a strict requirement but moved away from it as [users reported the dramatic consequences](https://github.com/traefik/traefik/issues/653).
#### Draining
Another common approach is to let a proxy drain backends that are supposed to shut down.
That is, once a backend is supposed to shut down, Traefik would stop forwarding requests.
On the plus side, this would not require any modifications to the application in question.
However, implementing this fully within Traefik seems like a non-trivial undertaking.
Additionally, the approach is less flexible compared to a custom termination handler since only the latter allows for the implementation of custom termination sequences that go beyond simple request draining (e.g., persisting a snapshot state to disk prior to terminating).
The feature is currently not implemented; a request for draining in general is at [issue 41](https://github.com/traefik/traefik/issues/41).

View file

@ -81,7 +81,6 @@ nav:
- 'Consul Catalog': 'providers/consul-catalog.md'
- 'Nomad': 'providers/nomad.md'
- 'ECS': 'providers/ecs.md'
- 'Marathon': 'providers/marathon.md'
- 'File': 'providers/file.md'
- 'Consul': 'providers/consul.md'
- 'Etcd': 'providers/etcd.md'
@ -101,7 +100,6 @@ nav:
- 'Consul Catalog': 'routing/providers/consul-catalog.md'
- 'Nomad': 'routing/providers/nomad.md'
- 'ECS': 'routing/providers/ecs.md'
- 'Marathon': 'routing/providers/marathon.md'
- 'KV': 'routing/providers/kv.md'
- 'HTTPS & TLS':
- 'Overview': 'https/overview.md'
@ -170,7 +168,6 @@ nav:
- 'User Guides':
- 'Kubernetes and Let''s Encrypt': 'user-guides/crd-acme/index.md'
- 'gRPC Examples': 'user-guides/grpc.md'
- 'Marathon': 'user-guides/marathon.md'
- 'Docker':
- 'Basic Example': 'user-guides/docker-compose/basic-example/index.md'
- 'HTTPS with Let''s Encrypt':
@ -206,7 +203,6 @@ nav:
- 'Nomad': "reference/dynamic-configuration/nomad.md"
- 'ECS': 'reference/dynamic-configuration/ecs.md'
- 'KV': 'reference/dynamic-configuration/kv.md'
- 'Marathon': 'reference/dynamic-configuration/marathon.md'
- 'Deprecation Notices':
- 'Releases': 'deprecation/releases.md'
- 'Features': 'deprecation/features.md'

2
go.mod
View file

@ -19,7 +19,6 @@ require (
github.com/docker/docker v20.10.7+incompatible
github.com/docker/go-connections v0.4.0
github.com/fatih/structs v1.1.0
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2
github.com/go-acme/lego/v4 v4.9.1
github.com/go-check/check v0.0.0-00010101000000-000000000000
github.com/go-kit/kit v0.10.1-0.20200915143503-439c4d2ed3ea
@ -173,7 +172,6 @@ require (
github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/elastic/go-licenser v0.3.1 // indirect
github.com/elastic/go-sysinfo v1.1.1 // indirect

4
go.sum
View file

@ -589,8 +589,6 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNE
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e h1:rMOGp6HPeMHbdLrZkX2nD+94uqDunc27tXVuS+ey4mQ=
github.com/donovanhide/eventsource v0.0.0-20170630084216-b8f31a59085e/go.mod h1:56wL82FO0bfMU5RvfXoIwSOP2ggqqxT+tAfNEIyxuHw=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
@ -665,8 +663,6 @@ github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmV
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/fvbommel/sortorder v1.0.1 h1:dSnXLt4mJYH25uDDGa3biZNQsozaUWDSWeKJ0qqFfzE=
github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2 h1:df6OFl8WNXk82xxP3R9ZPZ5seOA8XZkwLdbEzZF1/xI=
github.com/gambol99/go-marathon v0.0.0-20180614232016-99a156b96fb2/go.mod h1:GLyXJD41gBO/NPKVPGQbhyyC06eugGy15QEZyUkE2/s=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/getkin/kin-openapi v0.87.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=

View file

@ -1,22 +0,0 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
noColor = true
[entryPoints]
[entryPoints.web]
address = ":8000"
[entryPoints.traefik]
address = ":9090"
[api]
insecure = true
[providers]
[providers.marathon]
endpoint = "{{.MarathonURL}}"
watch = true
exposedByDefault = true

View file

@ -91,8 +91,6 @@ func Test(t *testing.T) {
}
check.Suite(&KeepAliveSuite{})
check.Suite(&LogRotationSuite{})
check.Suite(&MarathonSuite{})
check.Suite(&MarathonSuite15{})
if !useVPN {
check.Suite(&ProxyProtocolSuite{})
}

View file

@ -1,94 +0,0 @@
package integration
import (
"net/http"
"os"
"time"
"github.com/gambol99/go-marathon"
"github.com/go-check/check"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
// Marathon test suites.
type MarathonSuite15 struct {
BaseSuite
marathonURL string
}
func (s *MarathonSuite15) SetUpSuite(c *check.C) {
s.createComposeProject(c, "marathon15")
s.composeUp(c)
s.marathonURL = "http://" + s.getComposeServiceIP(c, containerNameMarathon) + ":8080"
// Wait for Marathon readiness prior to creating the client so that we
// don't run into the "all cluster members down" state right from the
// start.
err := try.GetRequest(s.marathonURL+"/v2/leader", 1*time.Minute, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
}
func (s *MarathonSuite15) TestConfigurationUpdate(c *check.C) {
// Start Traefik.
file := s.adaptFile(c, "fixtures/marathon/simple.toml", struct {
MarathonURL string
}{s.marathonURL})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
// Wait for Traefik to turn ready.
err = try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
// Prepare Marathon client.
config := marathon.NewDefaultConfig()
config.URL = s.marathonURL
client, err := marathon.NewClient(config)
c.Assert(err, checker.IsNil)
// Create test application to be deployed.
app := marathon.NewDockerApplication().
Name("/whoami").
CPU(0.1).
Memory(32).
EmptyNetworks().
AddLabel("traefik.http.Routers.rt.Rule", "PathPrefix(`/service`)")
app.Container.
Expose(80).
Docker.
Container("traefik/whoami")
*app.Networks = append(*app.Networks, *marathon.NewBridgePodNetwork())
// Deploy the test application.
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).
EmptyNetworks().
AddLabel("traefik.http.Routers.app.Rule", "PathPrefix(`/app`)")
app.Container.
Expose(80).
Docker.
Container("traefik/whoami")
*app.Networks = append(*app.Networks, *marathon.NewBridgePodNetwork())
// 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)
}

View file

@ -1,98 +0,0 @@
package integration
import (
"net/http"
"os"
"time"
"github.com/gambol99/go-marathon"
"github.com/go-check/check"
"github.com/traefik/traefik/v2/integration/try"
checker "github.com/vdemeester/shakers"
)
const containerNameMarathon = "marathon"
// Marathon test suites.
type MarathonSuite struct {
BaseSuite
marathonURL string
}
func (s *MarathonSuite) SetUpSuite(c *check.C) {
s.createComposeProject(c, "marathon")
s.composeUp(c)
s.marathonURL = "http://" + s.getComposeServiceIP(c, containerNameMarathon) + ":8080"
// Wait for Marathon readiness prior to creating the client so that we
// don't run into the "all cluster members down" state right from the
// start.
err := try.GetRequest(s.marathonURL+"/v2/leader", 1*time.Minute, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
}
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 {
MarathonURL string
}{s.marathonURL})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer s.killCmd(cmd)
// Wait for Traefik to turn ready.
err = try.GetRequest("http://127.0.0.1:8000/", 2*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
// Prepare Marathon client.
config := marathon.NewDefaultConfig()
config.URL = s.marathonURL
client, err := marathon.NewClient(config)
c.Assert(err, checker.IsNil)
// Create test application to be deployed.
app := marathon.NewDockerApplication().
Name("/whoami").
CPU(0.1).
Memory(32).
AddLabel("traefik.http.Routers.rt.Rule", "PathPrefix(`/service`)")
app.Container.Docker.Bridged().
Expose(80).
Container("traefik/whoami")
// Deploy the test application.
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("traefik.http.Routers.app.Rule", "PathPrefix(`/app`)")
app.Container.Docker.Bridged().
Expose(80).
Container("traefik/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)
}

View file

@ -1,60 +0,0 @@
version: "3.8"
services:
zookeeper:
image: zookeeper:3.4.10
mesos-master:
image: mesosphere/mesos-master:1.0.1-2.0.93.ubuntu1404
# Uncomment published ports for interactive debugging.
# ports:
# - "5050:5050"
environment:
MESOS_HOSTNAME: mesos-master
MESOS_CLUSTER: local
MESOS_REGISTRY: in_memory
MESOS_LOG_DIR: /var/log
MESOS_WORK_DIR: /var/lib/mesos
MESOS_ZK: zk://zookeeper:2181/mesos
mesos-slave:
image: docker:dind
privileged: true
# Uncomment published ports for interactive debugging.
# ports:
# - "5051:5051"
# docker version in mesosphere/mesos-slave-dind:0.3.0_mesos-1.0.1_docker-1.10.3_ubuntu-14.04.5 is too old and can't
# pull images on new kernels.
command:
- "/bin/sh"
- "-c"
- "(/usr/local/bin/dockerd-entrypoint.sh &); sleep 10; set -x; \
docker -H unix:///var/run/docker.sock run -d --net=host --privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /cgroup:/cgroup -v /sys:/sys \
-v /usr/local/bin/docker:/usr/local/bin/docker \
-e MESOS_HOSTNAME=$$(hostname -i) \
-e MESOS_CONTAINERIZERS=docker,mesos \
-e MESOS_ISOLATOR=cgroups/cpu,cgroups/mem \
-e MESOS_LOG_DIR=/var/log \
-e MESOS_MASTER=zk://zookeeper:2181/mesos \
-e MESOS_PORT=5051 \
-e MESOS_WORK_DIR=/var/lib/mesos \
-e MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins \
-e MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD=90secs \
-e MESOS_DOCKER_STOP_TIMEOUT=60secs \
-e MESOS_RESOURCES='cpus:2;mem:2048;disk:20480;ports(*):[12000-12999]' \
mesosphere/mesos-slave:1.0.3; sleep 600"
marathon:
image: mesosphere/marathon:v1.3.12
# Uncomment published ports for interactive debugging.
# ports:
# - "8080:8080"
environment:
MARATHON_ZK: zk://zookeeper:2181/marathon
MARATHON_MASTER: zk://zookeeper:2181/mesos
networks:
default:
name: traefik-test-network
external: true

View file

@ -1,59 +0,0 @@
version: "3.8"
services:
zookeeper:
image: zookeeper:3.4.10
mesos-master:
image: mesosphere/mesos-master:1.4.1
# Uncomment published ports for interactive debugging.
# ports:
# - "5050:5050"
environment:
MESOS_HOSTNAME: mesos-master
MESOS_CLUSTER: local
MESOS_REGISTRY: in_memory
MESOS_LOG_DIR: /var/log
MESOS_WORK_DIR: /var/lib/mesos
MESOS_ZK: zk://zookeeper:2181/mesos
mesos-slave:
image: docker:dind
privileged: true
# Uncomment published ports for interactive debugging.
# ports:
# - "5051:5051"
command:
- "/bin/sh"
- "-c"
- "(/usr/local/bin/dockerd-entrypoint.sh &); sleep 10; set -x; \
docker -H unix:///var/run/docker.sock run -d --net=host --privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /cgroup:/cgroup -v /sys:/sys \
-v /usr/local/bin/docker:/usr/local/bin/docker \
-e MESOS_HOSTNAME=$$(hostname -i) \
-e MESOS_CONTAINERIZERS=docker,mesos \
-e MESOS_ISOLATOR=cgroups/cpu,cgroups/mem \
-e MESOS_LOG_DIR=/var/log \
-e MESOS_MASTER=zk://zookeeper:2181/mesos \
-e MESOS_PORT=5051 \
-e MESOS_WORK_DIR=/var/lib/mesos \
-e MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins \
-e MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD=90secs \
-e MESOS_DOCKER_STOP_TIMEOUT=60secs \
-e MESOS_RESOURCES='cpus:2;mem:2048;disk:20480;ports(*):[12000-12999]' \
-e MESOS_SYSTEMD_ENABLE_SUPPORT=false \
mesosphere/mesos-slave:1.4.1; sleep 600"
marathon:
image: mesosphere/marathon:v1.5.9
# Uncomment published ports for interactive debugging.
# ports:
# - "8080:8080"
environment:
MARATHON_ZK: zk://zookeeper:2181/marathon
MARATHON_MASTER: zk://zookeeper:2181/mesos
networks:
default:
name: traefik-test-network
external: true

View file

@ -18,7 +18,6 @@ import (
"github.com/traefik/traefik/v2/pkg/provider/hub"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/crd"
"github.com/traefik/traefik/v2/pkg/provider/kubernetes/ingress"
"github.com/traefik/traefik/v2/pkg/provider/marathon"
"github.com/traefik/traefik/v2/pkg/provider/rest"
"github.com/traefik/traefik/v2/pkg/tracing/jaeger"
"github.com/traefik/traefik/v2/pkg/types"
@ -237,7 +236,6 @@ func TestHandler_Overview(t *testing.T) {
Providers: &static.Providers{
Docker: &docker.Provider{},
File: &file.Provider{},
Marathon: &marathon.Provider{},
KubernetesIngress: &ingress.Provider{},
KubernetesCRD: &crd.Provider{},
Rest: &rest.Provider{},

View file

@ -25,7 +25,6 @@
"providers": [
"Docker",
"File",
"Marathon",
"KubernetesIngress",
"KubernetesCRD",
"Rest",

View file

@ -54,28 +54,6 @@
watch = true
filename = "foobar"
debugLogGeneratedTemplate = true
[providers.marathon]
constraints = "foobar"
trace = true
watch = true
endpoint = "foobar"
defaultRule = "foobar"
exposedByDefault = true
dcosToken = "foobar"
dialerTimeout = 42
responseHeaderTimeout = 42
tlsHandshakeTimeout = 42
keepAlive = 42
forceTaskHostname = true
respectReadinessChecks = true
[providers.marathon.tls]
ca = "foobar"
cert = "foobar"
key = "foobar"
insecureSkipVerify = true
[providers.marathon.basic]
httpBasicAuthUser = "foobar"
httpBasicPassword = "foobar"
[providers.kubernetesIngress]
endpoint = "foobar"
token = "foobar"

View file

@ -25,7 +25,6 @@ import (
"github.com/traefik/traefik/v2/pkg/provider/kv/etcd"
"github.com/traefik/traefik/v2/pkg/provider/kv/redis"
"github.com/traefik/traefik/v2/pkg/provider/kv/zk"
"github.com/traefik/traefik/v2/pkg/provider/marathon"
"github.com/traefik/traefik/v2/pkg/provider/nomad"
"github.com/traefik/traefik/v2/pkg/provider/rest"
"github.com/traefik/traefik/v2/pkg/tls"
@ -213,7 +212,6 @@ type Providers struct {
Docker *docker.Provider `description:"Enable Docker backend with default settings." json:"docker,omitempty" toml:"docker,omitempty" yaml:"docker,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
File *file.Provider `description:"Enable File backend with default settings." json:"file,omitempty" toml:"file,omitempty" yaml:"file,omitempty" export:"true"`
Marathon *marathon.Provider `description:"Enable Marathon backend with default settings." json:"marathon,omitempty" toml:"marathon,omitempty" yaml:"marathon,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
KubernetesIngress *ingress.Provider `description:"Enable Kubernetes backend with default settings." json:"kubernetesIngress,omitempty" toml:"kubernetesIngress,omitempty" yaml:"kubernetesIngress,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
KubernetesCRD *crd.Provider `description:"Enable Kubernetes backend with default settings." json:"kubernetesCRD,omitempty" toml:"kubernetesCRD,omitempty" yaml:"kubernetesCRD,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
KubernetesGateway *gateway.Provider `description:"Enable Kubernetes gateway api provider with default settings." json:"kubernetesGateway,omitempty" toml:"kubernetesGateway,omitempty" yaml:"kubernetesGateway,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`

View file

@ -80,10 +80,6 @@ func NewProviderAggregator(conf static.Providers) ProviderAggregator {
p.quietAddProvider(conf.Docker)
}
if conf.Marathon != nil {
p.quietAddProvider(conf.Marathon)
}
if conf.Rest != nil {
p.quietAddProvider(conf.Rest)
}

View file

@ -3,22 +3,16 @@ package constraints
import (
"errors"
"regexp"
"strings"
"github.com/vulcand/predicate"
)
// MarathonConstraintPrefix is the prefix for each label's key created from a Marathon application constraint.
// It is used in order to create a specific and unique pattern for these labels.
const MarathonConstraintPrefix = "Traefik-Marathon-505F9E15-BDC7-45E7-828D-C06C7BAB8091"
type constraintLabelFunc func(map[string]string) bool
// MatchLabels reports whether the expression matches with the given labels.
// The expression must match any logical boolean combination of:
// - `Label(labelName, labelValue)`
// - `LabelRegex(labelName, regexValue)`
// - `MarathonConstraint(field:operator:value)`.
// - `LabelRegex(labelName, regexValue)`.
func MatchLabels(labels map[string]string, expr string) (bool, error) {
if expr == "" {
return true, nil
@ -31,9 +25,8 @@ func MatchLabels(labels map[string]string, expr string) (bool, error) {
OR: orLabelFunc,
},
Functions: map[string]interface{}{
"Label": labelFn,
"LabelRegex": labelRegexFn,
"MarathonConstraint": marathonFn,
"Label": labelFn,
"LabelRegex": labelRegexFn,
},
})
if err != nil {
@ -68,19 +61,6 @@ func labelRegexFn(name, expr string) constraintLabelFunc {
}
}
func marathonFn(value string) constraintLabelFunc {
return func(labels map[string]string) bool {
for k, v := range labels {
if strings.HasPrefix(k, MarathonConstraintPrefix) {
if v == value {
return true
}
}
}
return false
}
}
func andLabelFunc(a, b constraintLabelFunc) constraintLabelFunc {
return func(labels map[string]string) bool {
return a(labels) && b(labels)

View file

@ -118,33 +118,6 @@ func TestMatchLabels(t *testing.T) {
expr: ``,
expected: true,
},
{
expr: `MarathonConstraint("bar")`,
labels: map[string]string{
"hello": "world",
MarathonConstraintPrefix + "-1": "bar",
MarathonConstraintPrefix + "-2": "foo",
},
expected: true,
},
{
expr: `MarathonConstraint("bur")`,
labels: map[string]string{
"hello": "world",
MarathonConstraintPrefix + "-1": "bar",
MarathonConstraintPrefix + "-2": "foo",
},
expected: false,
},
{
expr: `Label("hello", "world") && MarathonConstraint("bar")`,
labels: map[string]string{
"hello": "world",
MarathonConstraintPrefix + "-1": "bar",
MarathonConstraintPrefix + "-2": "foo",
},
expected: true,
},
{
expr: `LabelRegex("hello", "w\\w+")`,
labels: map[string]string{

View file

@ -1,205 +0,0 @@
package marathon
import (
"strings"
"time"
"github.com/gambol99/go-marathon"
)
const testTaskName = "taskID"
// Functions related to building applications.
func withApplications(apps ...marathon.Application) *marathon.Applications {
return &marathon.Applications{Apps: apps}
}
func application(ops ...func(*marathon.Application)) marathon.Application {
app := marathon.Application{}
app.EmptyLabels()
app.Deployments = []map[string]string{}
app.ReadinessChecks = &[]marathon.ReadinessCheck{}
app.ReadinessCheckResults = &[]marathon.ReadinessCheckResult{}
for _, op := range ops {
op(&app)
}
return app
}
func appID(name string) func(*marathon.Application) {
return func(app *marathon.Application) {
app.Name(name)
}
}
func appPorts(ports ...int) func(*marathon.Application) {
return func(app *marathon.Application) {
app.Ports = append(app.Ports, ports...)
}
}
func withLabel(key, value string) func(*marathon.Application) {
return func(app *marathon.Application) {
app.AddLabel(key, value)
}
}
func constraint(value string) func(*marathon.Application) {
return func(app *marathon.Application) {
app.AddConstraint(strings.Split(value, ":")...)
}
}
func portDefinition(port int, name string) func(*marathon.Application) {
return func(app *marathon.Application) {
app.AddPortDefinition(marathon.PortDefinition{
Port: &port,
Name: name,
})
}
}
func bridgeNetwork() func(*marathon.Application) {
return func(app *marathon.Application) {
app.SetNetwork("bridge", marathon.BridgeNetworkMode)
}
}
func containerNetwork() func(*marathon.Application) {
return func(app *marathon.Application) {
app.SetNetwork("cni", marathon.ContainerNetworkMode)
}
}
func ipAddrPerTask(port int) func(*marathon.Application) {
return func(app *marathon.Application) {
p := marathon.Port{
Number: port,
Name: "port",
}
disc := marathon.Discovery{}
disc.AddPort(p)
ipAddr := marathon.IPAddressPerTask{}
ipAddr.SetDiscovery(disc)
app.SetIPAddressPerTask(ipAddr)
}
}
func deployments(ids ...string) func(*marathon.Application) {
return func(app *marathon.Application) {
for _, id := range ids {
app.Deployments = append(app.Deployments, map[string]string{
"ID": id,
})
}
}
}
func readinessCheck(timeout time.Duration) func(*marathon.Application) {
return func(app *marathon.Application) {
app.ReadinessChecks = &[]marathon.ReadinessCheck{
{
Path: "/ready",
TimeoutSeconds: int(timeout.Seconds()),
},
}
}
}
func readinessCheckResult(taskID string, ready bool) func(*marathon.Application) {
return func(app *marathon.Application) {
*app.ReadinessCheckResults = append(*app.ReadinessCheckResults, marathon.ReadinessCheckResult{
TaskID: taskID,
Ready: ready,
})
}
}
func withTasks(tasks ...marathon.Task) func(*marathon.Application) {
return func(application *marathon.Application) {
for _, task := range tasks {
tu := task
application.Tasks = append(application.Tasks, &tu)
}
}
}
// Functions related to building tasks.
func task(ops ...func(*marathon.Task)) marathon.Task {
t := &marathon.Task{
ID: testTaskName,
// The vast majority of tests expect the task state to be TASK_RUNNING.
State: string(taskStateRunning),
}
for _, op := range ops {
op(t)
}
return *t
}
func withTaskID(id string) func(*marathon.Task) {
return func(task *marathon.Task) {
task.ID = id
}
}
func localhostTask(ops ...func(*marathon.Task)) marathon.Task {
t := task(
host("localhost"),
ipAddresses("127.0.0.1"),
taskState(taskStateRunning),
)
for _, op := range ops {
op(&t)
}
return t
}
func taskPorts(ports ...int) func(*marathon.Task) {
return func(t *marathon.Task) {
t.Ports = append(t.Ports, ports...)
}
}
func taskState(state TaskState) func(*marathon.Task) {
return func(t *marathon.Task) {
t.State = string(state)
}
}
func host(h string) func(*marathon.Task) {
return func(t *marathon.Task) {
t.Host = h
}
}
func ipAddresses(addresses ...string) func(*marathon.Task) {
return func(t *marathon.Task) {
for _, addr := range addresses {
t.IPAddresses = append(t.IPAddresses, &marathon.IPAddress{
IPAddress: addr,
Protocol: "tcp",
})
}
}
}
func startedAt(timestamp string) func(*marathon.Task) {
return func(t *marathon.Task) {
t.StartedAt = timestamp
}
}
func startedAtFromNow(offset time.Duration) func(*marathon.Task) {
return func(t *marathon.Task) {
t.StartedAt = time.Now().Add(-offset).Format(time.RFC3339)
}
}

View file

@ -1,473 +0,0 @@
package marathon
import (
"context"
"errors"
"fmt"
"math"
"net"
"strconv"
"strings"
"github.com/gambol99/go-marathon"
"github.com/rs/zerolog/log"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/config/label"
"github.com/traefik/traefik/v2/pkg/provider"
"github.com/traefik/traefik/v2/pkg/provider/constraints"
)
func (p *Provider) buildConfiguration(ctx context.Context, applications *marathon.Applications) *dynamic.Configuration {
configurations := make(map[string]*dynamic.Configuration)
for _, app := range applications.Apps {
logger := log.Ctx(ctx).With().Str("applicationID", app.ID).Logger()
ctxApp := logger.WithContext(ctx)
extraConf, err := p.getConfiguration(app)
if err != nil {
logger.Error().Err(err).Msg("Skip application")
continue
}
labels := stringValueMap(app.Labels)
if app.Constraints != nil {
for i, constraintParts := range *app.Constraints {
key := constraints.MarathonConstraintPrefix + "-" + strconv.Itoa(i)
labels[key] = strings.Join(constraintParts, ":")
}
}
if !p.keepApplication(ctxApp, extraConf, labels) {
continue
}
confFromLabel, err := label.DecodeConfiguration(labels)
if err != nil {
logger.Error().Err(err).Send()
continue
}
var tcpOrUDP bool
if len(confFromLabel.TCP.Routers) > 0 || len(confFromLabel.TCP.Services) > 0 {
tcpOrUDP = true
err := p.buildTCPServiceConfiguration(ctxApp, app, extraConf, confFromLabel.TCP)
if err != nil {
logger.Error().Err(err).Send()
continue
}
provider.BuildTCPRouterConfiguration(ctxApp, confFromLabel.TCP)
}
if len(confFromLabel.UDP.Routers) > 0 || len(confFromLabel.UDP.Services) > 0 {
tcpOrUDP = true
err := p.buildUDPServiceConfiguration(ctxApp, app, extraConf, confFromLabel.UDP)
if err != nil {
logger.Error().Err(err).Send()
} else {
provider.BuildUDPRouterConfiguration(ctxApp, confFromLabel.UDP)
}
}
if tcpOrUDP && len(confFromLabel.HTTP.Routers) == 0 &&
len(confFromLabel.HTTP.Middlewares) == 0 &&
len(confFromLabel.HTTP.Services) == 0 {
configurations[app.ID] = confFromLabel
continue
}
err = p.buildServiceConfiguration(ctxApp, app, extraConf, confFromLabel.HTTP)
if err != nil {
logger.Error().Err(err).Send()
continue
}
model := struct {
Name string
Labels map[string]string
}{
Name: app.ID,
Labels: labels,
}
serviceName := getServiceName(app)
provider.BuildRouterConfiguration(ctxApp, confFromLabel.HTTP, serviceName, p.defaultRuleTpl, model)
configurations[app.ID] = confFromLabel
}
return provider.Merge(ctx, configurations)
}
func getServiceName(app marathon.Application) string {
return strings.ReplaceAll(strings.TrimPrefix(app.ID, "/"), "/", "_")
}
func (p *Provider) buildServiceConfiguration(ctx context.Context, app marathon.Application, extraConf configuration, conf *dynamic.HTTPConfiguration) error {
appName := getServiceName(app)
logger := log.Ctx(ctx).With().Str("applicationName", appName).Logger()
if len(conf.Services) == 0 {
conf.Services = make(map[string]*dynamic.Service)
lb := &dynamic.ServersLoadBalancer{}
lb.SetDefaults()
conf.Services[appName] = &dynamic.Service{
LoadBalancer: lb,
}
}
for serviceName, service := range conf.Services {
var servers []dynamic.Server
defaultServer := dynamic.Server{}
defaultServer.SetDefaults()
if len(service.LoadBalancer.Servers) > 0 {
defaultServer = service.LoadBalancer.Servers[0]
}
for _, task := range app.Tasks {
if !p.taskFilter(ctx, *task, app) {
continue
}
server, err := p.getServer(app, *task, extraConf, defaultServer)
if err != nil {
logger.Error().Err(err).Msg("Skip task")
continue
}
servers = append(servers, server)
}
if len(servers) == 0 {
return fmt.Errorf("no server for the service %s", serviceName)
}
service.LoadBalancer.Servers = servers
}
return nil
}
func (p *Provider) buildTCPServiceConfiguration(ctx context.Context, app marathon.Application, extraConf configuration, conf *dynamic.TCPConfiguration) error {
appName := getServiceName(app)
logger := log.Ctx(ctx).With().Str("applicationName", appName).Logger()
if len(conf.Services) == 0 {
conf.Services = map[string]*dynamic.TCPService{
appName: {
LoadBalancer: new(dynamic.TCPServersLoadBalancer),
},
}
}
for serviceName, service := range conf.Services {
var servers []dynamic.TCPServer
defaultServer := dynamic.TCPServer{}
if len(service.LoadBalancer.Servers) > 0 {
defaultServer = service.LoadBalancer.Servers[0]
}
for _, task := range app.Tasks {
if p.taskFilter(ctx, *task, app) {
server, err := p.getTCPServer(app, *task, extraConf, defaultServer)
if err != nil {
logger.Error().Err(err).Msg("Skip task")
continue
}
servers = append(servers, server)
}
}
if len(servers) == 0 {
return fmt.Errorf("no server for the service %s", serviceName)
}
service.LoadBalancer.Servers = servers
}
return nil
}
func (p *Provider) buildUDPServiceConfiguration(ctx context.Context, app marathon.Application, extraConf configuration, conf *dynamic.UDPConfiguration) error {
appName := getServiceName(app)
logger := log.Ctx(ctx).With().Str("applicationName", appName).Logger()
if len(conf.Services) == 0 {
conf.Services = make(map[string]*dynamic.UDPService)
lb := &dynamic.UDPServersLoadBalancer{}
conf.Services[appName] = &dynamic.UDPService{
LoadBalancer: lb,
}
}
for serviceName, service := range conf.Services {
var servers []dynamic.UDPServer
defaultServer := dynamic.UDPServer{}
if len(service.LoadBalancer.Servers) > 0 {
defaultServer = service.LoadBalancer.Servers[0]
}
for _, task := range app.Tasks {
if p.taskFilter(ctx, *task, app) {
server, err := p.getUDPServer(app, *task, extraConf, defaultServer)
if err != nil {
logger.Error().Err(err).Msg("Skip task")
continue
}
servers = append(servers, server)
}
}
if len(servers) == 0 {
return fmt.Errorf("no server for the service %s", serviceName)
}
service.LoadBalancer.Servers = servers
}
return nil
}
func (p *Provider) keepApplication(ctx context.Context, extraConf configuration, labels map[string]string) bool {
logger := log.Ctx(ctx)
// Filter disabled application.
if !extraConf.Enable {
logger.Debug().Msg("Filtering disabled Marathon application")
return false
}
// Filter by constraints.
matches, err := constraints.MatchLabels(labels, p.Constraints)
if err != nil {
logger.Error().Err(err).Msg("Error matching constraints expression")
return false
}
if !matches {
logger.Debug().Msgf("Marathon application filtered by constraint expression: %q", p.Constraints)
return false
}
return true
}
func (p *Provider) taskFilter(ctx context.Context, task marathon.Task, application marathon.Application) bool {
if task.State != string(taskStateRunning) {
return false
}
if ready := p.readyChecker.Do(task, application); !ready {
log.Ctx(ctx).Info().Msgf("Filtering unready task %s from application %s", task.ID, application.ID)
return false
}
return true
}
func (p *Provider) getTCPServer(app marathon.Application, task marathon.Task, extraConf configuration, defaultServer dynamic.TCPServer) (dynamic.TCPServer, error) {
host, err := p.getServerHost(task, app, extraConf)
if len(host) == 0 {
return dynamic.TCPServer{}, err
}
port, err := getPort(task, app, defaultServer.Port)
if err != nil {
return dynamic.TCPServer{}, err
}
server := dynamic.TCPServer{
Address: net.JoinHostPort(host, port),
}
return server, nil
}
func (p *Provider) getUDPServer(app marathon.Application, task marathon.Task, extraConf configuration, defaultServer dynamic.UDPServer) (dynamic.UDPServer, error) {
host, err := p.getServerHost(task, app, extraConf)
if len(host) == 0 {
return dynamic.UDPServer{}, err
}
port, err := getPort(task, app, defaultServer.Port)
if err != nil {
return dynamic.UDPServer{}, err
}
server := dynamic.UDPServer{
Address: net.JoinHostPort(host, port),
}
return server, nil
}
func (p *Provider) getServer(app marathon.Application, task marathon.Task, extraConf configuration, defaultServer dynamic.Server) (dynamic.Server, error) {
host, err := p.getServerHost(task, app, extraConf)
if len(host) == 0 {
return dynamic.Server{}, err
}
port, err := getPort(task, app, defaultServer.Port)
if err != nil {
return dynamic.Server{}, err
}
server := dynamic.Server{
URL: fmt.Sprintf("%s://%s", defaultServer.Scheme, net.JoinHostPort(host, port)),
}
return server, nil
}
func (p *Provider) getServerHost(task marathon.Task, app marathon.Application, extraConf configuration) (string, error) {
networks := app.Networks
var hostFlag bool
if networks == nil {
hostFlag = app.IPAddressPerTask == nil
} else {
hostFlag = (*networks)[0].Mode != marathon.ContainerNetworkMode
}
if hostFlag || p.ForceTaskHostname {
if len(task.Host) == 0 {
return "", fmt.Errorf("host is undefined for task %q app %q", task.ID, app.ID)
}
return task.Host, nil
}
numTaskIPAddresses := len(task.IPAddresses)
switch numTaskIPAddresses {
case 0:
return "", fmt.Errorf("missing IP address for Marathon application %s on task %s", app.ID, task.ID)
case 1:
return task.IPAddresses[0].IPAddress, nil
default:
if extraConf.Marathon.IPAddressIdx == math.MinInt32 {
return "", fmt.Errorf("found %d task IP addresses but missing IP address index for Marathon application %s on task %s",
numTaskIPAddresses, app.ID, task.ID)
}
if extraConf.Marathon.IPAddressIdx < 0 || extraConf.Marathon.IPAddressIdx > numTaskIPAddresses {
return "", fmt.Errorf("cannot use IP address index to select from %d task IP addresses for Marathon application %s on task %s",
numTaskIPAddresses, app.ID, task.ID)
}
return task.IPAddresses[extraConf.Marathon.IPAddressIdx].IPAddress, nil
}
}
func getPort(task marathon.Task, app marathon.Application, serverPort string) (string, error) {
port, err := processPorts(app, task, serverPort)
if err != nil {
return "", fmt.Errorf("unable to process ports for %s %s: %w", app.ID, task.ID, err)
}
return strconv.Itoa(port), nil
}
// processPorts returns the configured port.
// An explicitly specified port is preferred. If none is specified, it selects
// one of the available port. The first such found port is returned unless an
// optional index is provided.
func processPorts(app marathon.Application, task marathon.Task, serverPort string) (int, error) {
if len(serverPort) > 0 && !(strings.HasPrefix(serverPort, "index:") || strings.HasPrefix(serverPort, "name:")) {
port, err := strconv.Atoi(serverPort)
if err != nil {
return 0, err
}
if port <= 0 {
return 0, fmt.Errorf("explicitly specified port %d must be greater than zero", port)
} else if port > 0 {
return port, nil
}
}
if strings.HasPrefix(serverPort, "name:") {
name := strings.TrimPrefix(serverPort, "name:")
port := retrieveNamedPort(app, name)
if port == 0 {
return 0, fmt.Errorf("no port with name %s", name)
}
return port, nil
}
ports := retrieveAvailablePorts(app, task)
if len(ports) == 0 {
return 0, errors.New("no port found")
}
portIndex := 0
if strings.HasPrefix(serverPort, "index:") {
indexString := strings.TrimPrefix(serverPort, "index:")
index, err := strconv.Atoi(indexString)
if err != nil {
return 0, err
}
if index < 0 || index > len(ports)-1 {
return 0, fmt.Errorf("index %d must be within range (0, %d)", index, len(ports)-1)
}
portIndex = index
}
return ports[portIndex], nil
}
func retrieveNamedPort(app marathon.Application, name string) int {
// Using port definition if available
if app.PortDefinitions != nil && len(*app.PortDefinitions) > 0 {
for _, def := range *app.PortDefinitions {
if def.Port != nil && *def.Port > 0 && def.Name == name {
return *def.Port
}
}
}
// If using IP-per-task using this port definition
if app.IPAddressPerTask != nil && app.IPAddressPerTask.Discovery != nil && len(*(app.IPAddressPerTask.Discovery.Ports)) > 0 {
for _, def := range *(app.IPAddressPerTask.Discovery.Ports) {
if def.Number > 0 && def.Name == name {
return def.Number
}
}
}
return 0
}
func retrieveAvailablePorts(app marathon.Application, task marathon.Task) []int {
// Using default port configuration
if len(task.Ports) > 0 {
return task.Ports
}
// Using port definition if available
if app.PortDefinitions != nil && len(*app.PortDefinitions) > 0 {
var ports []int
for _, def := range *app.PortDefinitions {
if def.Port != nil {
ports = append(ports, *def.Port)
}
}
return ports
}
// If using IP-per-task using this port definition
if app.IPAddressPerTask != nil && app.IPAddressPerTask.Discovery != nil && len(*(app.IPAddressPerTask.Discovery.Ports)) > 0 {
var ports []int
for _, def := range *(app.IPAddressPerTask.Discovery.Ports) {
ports = append(ports, def.Number)
}
return ports
}
return []int{}
}

File diff suppressed because it is too large Load diff

View file

@ -1,24 +0,0 @@
package marathon
import (
"errors"
"github.com/gambol99/go-marathon"
"github.com/stretchr/testify/mock"
"github.com/traefik/traefik/v2/pkg/provider/marathon/mocks"
)
type fakeClient struct {
mocks.Marathon
}
func newFakeClient(applicationsError bool, applications marathon.Applications) *fakeClient {
// create an instance of our test object
fakeClient := new(fakeClient)
if applicationsError {
fakeClient.On("Applications", mock.Anything).Return(nil, errors.New("fake Marathon server error"))
} else {
fakeClient.On("Applications", mock.Anything).Return(&applications, nil)
}
return fakeClient
}

View file

@ -1,42 +0,0 @@
package marathon
import (
"math"
"github.com/gambol99/go-marathon"
"github.com/traefik/traefik/v2/pkg/config/label"
)
type configuration struct {
Enable bool
Marathon specificConfiguration
}
type specificConfiguration struct {
IPAddressIdx int
}
func (p *Provider) getConfiguration(app marathon.Application) (configuration, error) {
labels := stringValueMap(app.Labels)
conf := configuration{
Enable: p.ExposedByDefault,
Marathon: specificConfiguration{
IPAddressIdx: math.MinInt32,
},
}
err := label.Decode(labels, &conf, "traefik.marathon.", "traefik.enable")
if err != nil {
return configuration{}, err
}
return conf, nil
}
func stringValueMap(mp *map[string]string) map[string]string {
if mp != nil {
return *mp
}
return make(map[string]string)
}

View file

@ -1,136 +0,0 @@
package marathon
import (
"math"
"testing"
"github.com/gambol99/go-marathon"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetConfiguration(t *testing.T) {
testCases := []struct {
desc string
app marathon.Application
p Provider
expected configuration
}{
{
desc: "Empty labels",
app: marathon.Application{
Constraints: &[][]string{},
Labels: &map[string]string{},
},
p: Provider{
ExposedByDefault: false,
},
expected: configuration{
Enable: false,
Marathon: specificConfiguration{
IPAddressIdx: math.MinInt32,
},
},
},
{
desc: "label enable",
app: marathon.Application{
Constraints: &[][]string{},
Labels: &map[string]string{
"traefik.enable": "true",
},
},
p: Provider{
ExposedByDefault: false,
},
expected: configuration{
Enable: true,
Marathon: specificConfiguration{
IPAddressIdx: math.MinInt32,
},
},
},
{
desc: "Use ip address index",
app: marathon.Application{
Constraints: &[][]string{},
Labels: &map[string]string{
"traefik.marathon.IPAddressIdx": "4",
},
},
p: Provider{
ExposedByDefault: false,
},
expected: configuration{
Enable: false,
Marathon: specificConfiguration{
IPAddressIdx: 4,
},
},
},
{
desc: "Use marathon constraints",
app: marathon.Application{
Constraints: &[][]string{
{"key", "value"},
},
Labels: &map[string]string{},
},
p: Provider{
ExposedByDefault: false,
},
expected: configuration{
Enable: false,
Marathon: specificConfiguration{
IPAddressIdx: math.MinInt32,
},
},
},
{
desc: "ExposedByDefault and no enable label",
app: marathon.Application{
Constraints: &[][]string{},
Labels: &map[string]string{},
},
p: Provider{
ExposedByDefault: true,
},
expected: configuration{
Enable: true,
Marathon: specificConfiguration{
IPAddressIdx: math.MinInt32,
},
},
},
{
desc: "ExposedByDefault and enable label false",
app: marathon.Application{
Constraints: &[][]string{},
Labels: &map[string]string{
"traefik.enable": "false",
},
},
p: Provider{
ExposedByDefault: true,
},
expected: configuration{
Enable: false,
Marathon: specificConfiguration{
IPAddressIdx: math.MinInt32,
},
},
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
extraConf, err := test.p.getConfiguration(test.app)
require.NoError(t, err)
assert.Equal(t, test.expected, extraConf)
})
}
}

View file

@ -1,221 +0,0 @@
package marathon
import (
"context"
"fmt"
"net"
"net/http"
"net/url"
"text/template"
"time"
"github.com/cenkalti/backoff/v4"
"github.com/gambol99/go-marathon"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
ptypes "github.com/traefik/paerser/types"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/job"
"github.com/traefik/traefik/v2/pkg/logs"
"github.com/traefik/traefik/v2/pkg/provider"
"github.com/traefik/traefik/v2/pkg/safe"
"github.com/traefik/traefik/v2/pkg/types"
)
const (
// DefaultTemplateRule The default template for the default rule.
DefaultTemplateRule = "Host(`{{ normalize .Name }}`)"
marathonEventIDs = marathon.EventIDApplications |
marathon.EventIDAddHealthCheck |
marathon.EventIDDeploymentSuccess |
marathon.EventIDDeploymentFailed |
marathon.EventIDDeploymentInfo |
marathon.EventIDDeploymentStepSuccess |
marathon.EventIDDeploymentStepFailed
)
// TaskState denotes the Mesos state a task can have.
type TaskState string
const (
taskStateRunning TaskState = "TASK_RUNNING"
taskStateStaging TaskState = "TASK_STAGING"
)
var _ provider.Provider = (*Provider)(nil)
// Provider holds configuration of the provider.
type Provider struct {
Constraints string `description:"Constraints is an expression that Traefik matches against the application's labels to determine whether to create any route for that application." json:"constraints,omitempty" toml:"constraints,omitempty" yaml:"constraints,omitempty" export:"true"`
Trace bool `description:"Display additional provider logs." json:"trace,omitempty" toml:"trace,omitempty" yaml:"trace,omitempty" export:"true"`
Watch bool `description:"Watch provider." json:"watch,omitempty" toml:"watch,omitempty" yaml:"watch,omitempty" export:"true"`
Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
ExposedByDefault bool `description:"Expose Marathon apps by default." json:"exposedByDefault,omitempty" toml:"exposedByDefault,omitempty" yaml:"exposedByDefault,omitempty" export:"true"`
DCOSToken string `description:"DCOSToken for DCOS environment, This will override the Authorization header." json:"dcosToken,omitempty" toml:"dcosToken,omitempty" yaml:"dcosToken,omitempty" loggable:"false"`
TLS *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
DialerTimeout ptypes.Duration `description:"Set a dialer timeout for Marathon." json:"dialerTimeout,omitempty" toml:"dialerTimeout,omitempty" yaml:"dialerTimeout,omitempty" export:"true"`
ResponseHeaderTimeout ptypes.Duration `description:"Set a response header timeout for Marathon." json:"responseHeaderTimeout,omitempty" toml:"responseHeaderTimeout,omitempty" yaml:"responseHeaderTimeout,omitempty" export:"true"`
TLSHandshakeTimeout ptypes.Duration `description:"Set a TLS handshake timeout for Marathon." json:"tlsHandshakeTimeout,omitempty" toml:"tlsHandshakeTimeout,omitempty" yaml:"tlsHandshakeTimeout,omitempty" export:"true"`
KeepAlive ptypes.Duration `description:"Set a TCP Keep Alive time." json:"keepAlive,omitempty" toml:"keepAlive,omitempty" yaml:"keepAlive,omitempty" export:"true"`
ForceTaskHostname bool `description:"Force to use the task's hostname." json:"forceTaskHostname,omitempty" toml:"forceTaskHostname,omitempty" yaml:"forceTaskHostname,omitempty" export:"true"`
Basic *Basic `description:"Enable basic authentication." json:"basic,omitempty" toml:"basic,omitempty" yaml:"basic,omitempty" export:"true"`
RespectReadinessChecks bool `description:"Filter out tasks with non-successful readiness checks during deployments." json:"respectReadinessChecks,omitempty" toml:"respectReadinessChecks,omitempty" yaml:"respectReadinessChecks,omitempty" export:"true"`
readyChecker *readinessChecker
marathonClient marathon.Marathon
defaultRuleTpl *template.Template
}
// SetDefaults sets the default values.
func (p *Provider) SetDefaults() {
p.Watch = true
p.Endpoint = "http://127.0.0.1:8080"
p.ExposedByDefault = true
p.DialerTimeout = ptypes.Duration(5 * time.Second)
p.ResponseHeaderTimeout = ptypes.Duration(60 * time.Second)
p.TLSHandshakeTimeout = ptypes.Duration(5 * time.Second)
p.KeepAlive = ptypes.Duration(10 * time.Second)
p.DefaultRule = DefaultTemplateRule
}
// Basic holds basic authentication specific configurations.
type Basic struct {
HTTPBasicAuthUser string `description:"Basic authentication User." json:"httpBasicAuthUser,omitempty" toml:"httpBasicAuthUser,omitempty" yaml:"httpBasicAuthUser,omitempty" loggable:"false"`
HTTPBasicPassword string `description:"Basic authentication Password." json:"httpBasicPassword,omitempty" toml:"httpBasicPassword,omitempty" yaml:"httpBasicPassword,omitempty" loggable:"false"`
}
// Init the provider.
func (p *Provider) Init() error {
fm := template.FuncMap{
"strsToItfs": func(values []string) []interface{} {
var r []interface{}
for _, v := range values {
r = append(r, v)
}
return r
},
}
defaultRuleTpl, err := provider.MakeDefaultRuleTemplate(p.DefaultRule, fm)
if err != nil {
return fmt.Errorf("error while parsing default rule: %w", err)
}
p.defaultRuleTpl = defaultRuleTpl
return nil
}
// Provide allows the marathon provider to provide configurations to traefik
// using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
logger := log.With().Str(logs.ProviderName, "marathon").Logger()
ctx := logger.WithContext(context.Background())
operation := func() error {
confg := marathon.NewDefaultConfig()
confg.URL = p.Endpoint
confg.EventsTransport = marathon.EventsTransportSSE
if p.Trace {
confg.LogOutput = logs.NoLevel(logger, zerolog.DebugLevel)
}
if p.Basic != nil {
confg.HTTPBasicAuthUser = p.Basic.HTTPBasicAuthUser
confg.HTTPBasicPassword = p.Basic.HTTPBasicPassword
}
var rc *readinessChecker
if p.RespectReadinessChecks {
logger.Debug().Msg("Enabling Marathon readiness checker")
rc = defaultReadinessChecker(p.Trace)
}
p.readyChecker = rc
if len(p.DCOSToken) > 0 {
confg.DCOSToken = p.DCOSToken
}
TLSConfig, err := p.TLS.CreateTLSConfig(ctx)
if err != nil {
return fmt.Errorf("unable to create client TLS configuration: %w", err)
}
confg.HTTPClient = &http.Client{
Transport: &http.Transport{
DialContext: (&net.Dialer{
KeepAlive: time.Duration(p.KeepAlive),
Timeout: time.Duration(p.DialerTimeout),
}).DialContext,
ResponseHeaderTimeout: time.Duration(p.ResponseHeaderTimeout),
TLSHandshakeTimeout: time.Duration(p.TLSHandshakeTimeout),
TLSClientConfig: TLSConfig,
},
}
client, err := marathon.NewClient(confg)
if err != nil {
logger.Error().Err(err).Msg("Failed to create a client for marathon")
return err
}
p.marathonClient = client
if p.Watch {
update, err := client.AddEventsListener(marathonEventIDs)
if err != nil {
logger.Error().Err(err).Msg("Failed to register for events")
return err
}
pool.GoCtx(func(ctxPool context.Context) {
defer close(update)
for {
select {
case <-ctxPool.Done():
return
case event := <-update:
logger.Debug().Msgf("Received provider event %s", event)
conf := p.getConfigurations(ctx)
if conf != nil {
configurationChan <- dynamic.Message{
ProviderName: "marathon",
Configuration: conf,
}
}
}
}
})
}
configuration := p.getConfigurations(ctx)
configurationChan <- dynamic.Message{
ProviderName: "marathon",
Configuration: configuration,
}
return nil
}
notify := func(err error, time time.Duration) {
logger.Error().Err(err).Msgf("Provider error, retrying in %s", time)
}
err := backoff.RetryNotify(safe.OperationWithRecover(operation), backoff.WithContext(job.NewBackOff(backoff.NewExponentialBackOff()), ctx), notify)
if err != nil {
logger.Error().Err(err).Msg("Cannot retrieve data")
}
return nil
}
func (p *Provider) getConfigurations(ctx context.Context) *dynamic.Configuration {
applications, err := p.getApplications()
if err != nil {
log.Ctx(ctx).Error().Err(err).Msg("Failed to retrieve Marathon applications")
return nil
}
return p.buildConfiguration(ctx, applications)
}
func (p *Provider) getApplications() (*marathon.Applications, error) {
v := url.Values{}
v.Add("embed", "apps.tasks")
v.Add("embed", "apps.deployments")
v.Add("embed", "apps.readiness")
return p.marathonClient.Applications(v)
}

File diff suppressed because it is too large Load diff

View file

@ -1,122 +0,0 @@
package marathon
import (
"time"
"github.com/gambol99/go-marathon"
"github.com/rs/zerolog/log"
)
const (
// readinessCheckDefaultTimeout is the default timeout for a readiness
// check if no check timeout is specified on the application spec. This
// should really never be the case, but better be safe than sorry.
readinessCheckDefaultTimeout = 10 * time.Second
// readinessCheckSafetyMargin is some buffer duration to account for
// small offsets in readiness check execution.
readinessCheckSafetyMargin = 5 * time.Second
readinessLogHeader = "Marathon readiness check: "
)
type readinessChecker struct {
checkDefaultTimeout time.Duration
checkSafetyMargin time.Duration
traceLogging bool
}
func defaultReadinessChecker(isTraceLogging bool) *readinessChecker {
return &readinessChecker{
checkDefaultTimeout: readinessCheckDefaultTimeout,
checkSafetyMargin: readinessCheckSafetyMargin,
traceLogging: isTraceLogging,
}
}
func (rc *readinessChecker) Do(task marathon.Task, app marathon.Application) bool {
if rc == nil {
// Readiness checker disabled.
return true
}
switch {
case len(app.Deployments) == 0:
// We only care about readiness during deployments; post-deployment readiness
// can be covered by a periodic post-deployment probe (i.e., Traefik health checks).
rc.tracef("task %s app %s: ready = true [no deployment ongoing]", task.ID, app.ID)
return true
case app.ReadinessChecks == nil || len(*app.ReadinessChecks) == 0:
// Applications without configured readiness checks are always considered
// ready.
rc.tracef("task %s app %s: ready = true [no readiness checks on app]", task.ID, app.ID)
return true
}
// Loop through all readiness check results and return the results for
// matching task IDs.
if app.ReadinessCheckResults != nil {
for _, readinessCheckResult := range *app.ReadinessCheckResults {
if readinessCheckResult.TaskID == task.ID {
rc.tracef("task %s app %s: ready = %t [evaluating readiness check ready state]", task.ID, app.ID, readinessCheckResult.Ready)
return readinessCheckResult.Ready
}
}
}
// There's a corner case sometimes hit where the first new task of a
// deployment goes from TASK_STAGING to TASK_RUNNING without a corresponding
// readiness check result being included in the API response. This only happens
// in a very short (yet unlucky) time frame and does not repeat for subsequent
// tasks of the same deployment.
// Complicating matters, the situation may occur for both initially deploying
// applications as well as rolling-upgraded ones where one or more tasks from
// a previous deployment exist already and are joined by new tasks from a
// subsequent deployment. We must always make sure that pre-existing tasks
// maintain their ready state while newly launched tasks must be considered
// unready until a check result appears.
// We distinguish the two cases by comparing the current time with the start
// time of the task: It should take Marathon at most one readiness check timeout
// interval (plus some safety margin to account for the delayed nature of
// distributed systems) for readiness check results to be returned along the API
// response. Once the task turns old enough, we assume it to be part of a
// pre-existing deployment and mark it as ready. Note that it is okay to err
// on the side of caution and consider a task unready until the safety time
// window has elapsed because a newly created task should be readiness-checked
// and be given a result fairly shortly after its creation (i.e., on the scale
// of seconds).
readinessCheckTimeoutSecs := (*app.ReadinessChecks)[0].TimeoutSeconds
readinessCheckTimeout := time.Duration(readinessCheckTimeoutSecs) * time.Second
if readinessCheckTimeout == 0 {
rc.tracef("task %s app %s: readiness check timeout not set, using default value %s", task.ID, app.ID, rc.checkDefaultTimeout)
readinessCheckTimeout = rc.checkDefaultTimeout
} else {
readinessCheckTimeout += rc.checkSafetyMargin
}
startTime, err := time.Parse(time.RFC3339, task.StartedAt)
if err != nil {
// An unparseable start time should never occur; if it does, we assume the
// problem should be surfaced as quickly as possible, which is easiest if
// we shun the task from rotation.
log.Warn().Err(err).Msgf("Failed to parse start-time %s of task %s from application %s (assuming unready)", task.StartedAt, task.ID, app.ID)
return false
}
since := time.Since(startTime)
if since < readinessCheckTimeout {
rc.tracef("task %s app %s: ready = false [task with start-time %s not within assumed check timeout window of %s (elapsed time since task start: %s)]", task.ID, app.ID, startTime.Format(time.RFC3339), readinessCheckTimeout, since)
return false
}
// Finally, we can be certain this task is not part of the deployment (i.e.,
// it's an old task that's going to transition into the TASK_KILLING and/or
// TASK_KILLED state as new tasks' readiness checks gradually turn green.)
rc.tracef("task %s app %s: ready = true [task with start-time %s not involved in deployment (elapsed time since task start: %s)]", task.ID, app.ID, startTime.Format(time.RFC3339), since)
return true
}
func (rc *readinessChecker) tracef(format string, args ...interface{}) {
if rc.traceLogging {
log.Debug().Msgf(readinessLogHeader+format, args...)
}
}

View file

@ -1,134 +0,0 @@
package marathon
import (
"testing"
"time"
"github.com/gambol99/go-marathon"
)
func testReadinessChecker() *readinessChecker {
return defaultReadinessChecker(false)
}
func TestDisabledReadinessChecker(t *testing.T) {
var rc *readinessChecker
tsk := task()
app := application(
deployments("deploymentId"),
readinessCheck(0),
readinessCheckResult(testTaskName, false),
)
if ready := rc.Do(tsk, app); !ready {
t.Error("expected ready = true")
}
}
func TestEnabledReadinessChecker(t *testing.T) {
tests := []struct {
desc string
task marathon.Task
app marathon.Application
rc readinessChecker
expectedReady bool
}{
{
desc: "no deployment running",
task: task(),
app: application(),
expectedReady: true,
},
{
desc: "no readiness checks defined",
task: task(),
app: application(deployments("deploymentId")),
expectedReady: true,
},
{
desc: "readiness check result negative",
task: task(),
app: application(
deployments("deploymentId"),
readinessCheck(0),
readinessCheckResult("otherTaskID", true),
readinessCheckResult(testTaskName, false),
),
expectedReady: false,
},
{
desc: "readiness check result positive",
task: task(),
app: application(
deployments("deploymentId"),
readinessCheck(0),
readinessCheckResult("otherTaskID", false),
readinessCheckResult(testTaskName, true),
),
expectedReady: true,
},
{
desc: "no readiness check result with default timeout",
task: task(startedAtFromNow(3 * time.Minute)),
app: application(
deployments("deploymentId"),
readinessCheck(0),
),
rc: readinessChecker{
checkDefaultTimeout: 5 * time.Minute,
},
expectedReady: false,
},
{
desc: "no readiness check result with readiness check timeout",
task: task(startedAtFromNow(4 * time.Minute)),
app: application(
deployments("deploymentId"),
readinessCheck(3*time.Minute),
),
rc: readinessChecker{
checkSafetyMargin: 3 * time.Minute,
},
expectedReady: false,
},
{
desc: "invalid task start time",
task: task(startedAt("invalid")),
app: application(
deployments("deploymentId"),
readinessCheck(0),
),
expectedReady: false,
},
{
desc: "task not involved in deployment",
task: task(startedAtFromNow(1 * time.Hour)),
app: application(
deployments("deploymentId"),
readinessCheck(0),
),
rc: readinessChecker{
checkDefaultTimeout: 10 * time.Second,
},
expectedReady: true,
},
}
for _, test := range tests {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
rc := testReadinessChecker()
if test.rc.checkDefaultTimeout > 0 {
rc.checkDefaultTimeout = test.rc.checkDefaultTimeout
}
if test.rc.checkSafetyMargin > 0 {
rc.checkSafetyMargin = test.rc.checkSafetyMargin
}
actualReady := test.rc.Do(test.task, test.app)
if actualReady != test.expectedReady {
t.Errorf("actual ready = %t, expected ready = %t", actualReady, test.expectedReady)
}
})
}
}

View file

@ -28,7 +28,6 @@ import (
"github.com/traefik/traefik/v2/pkg/provider/kv/etcd"
"github.com/traefik/traefik/v2/pkg/provider/kv/redis"
"github.com/traefik/traefik/v2/pkg/provider/kv/zk"
"github.com/traefik/traefik/v2/pkg/provider/marathon"
"github.com/traefik/traefik/v2/pkg/provider/rest"
traefiktls "github.com/traefik/traefik/v2/pkg/tls"
"github.com/traefik/traefik/v2/pkg/tracing/datadog"
@ -610,32 +609,6 @@ func TestDo_staticConfiguration(t *testing.T) {
HTTPClientTimeout: 42,
}
config.Providers.Marathon = &marathon.Provider{
Constraints: `Label("foo", "bar")`,
Trace: true,
Watch: true,
Endpoint: "foobar",
DefaultRule: "PathPrefix(`/`)",
ExposedByDefault: true,
DCOSToken: "foobar",
TLS: &types.ClientTLS{
CA: "myCa",
Cert: "mycert.pem",
Key: "mycert.key",
InsecureSkipVerify: true,
},
DialerTimeout: 42,
ResponseHeaderTimeout: 42,
TLSHandshakeTimeout: 42,
KeepAlive: 42,
ForceTaskHostname: true,
Basic: &marathon.Basic{
HTTPBasicAuthUser: "user",
HTTPBasicPassword: "password",
},
RespectReadinessChecks: true,
}
config.Providers.KubernetesIngress = &ingress.Provider{
Endpoint: "MyEndpoint",
Token: "MyToken",

View file

@ -112,31 +112,6 @@
"filename": "file Filename",
"debugLogGeneratedTemplate": true
},
"marathon": {
"constraints": "Label(\"foo\", \"bar\")",
"trace": true,
"watch": true,
"endpoint": "xxxx",
"defaultRule": "xxxx",
"exposedByDefault": true,
"dcosToken": "xxxx",
"tls": {
"ca": "xxxx",
"cert": "xxxx",
"key": "xxxx",
"insecureSkipVerify": true
},
"dialerTimeout": "42ns",
"responseHeaderTimeout": "42ns",
"tlsHandshakeTimeout": "42ns",
"keepAlive": "42ns",
"forceTaskHostname": true,
"basic": {
"httpBasicAuthUser": "xxxx",
"httpBasicPassword": "xxxx"
},
"respectReadinessChecks": true
},
"kubernetesIngress": {
"endpoint": "xxxx",
"token": "xxxx",

View file

@ -65,7 +65,6 @@
"Docker": null,
"File": null,
"Web": null,
"Marathon": null,
"Consul": null,
"ConsulCatalog": null,
"Etcd": null,
@ -73,7 +72,6 @@
"Boltdb": null,
"KubernetesIngress": null,
"KubernetesCRD": null,
"Mesos": null,
"Eureka": null,
"ECS": null,
"DynamoDB": null,

View file

@ -65,7 +65,6 @@
"Docker": null,
"File": null,
"Web": null,
"Marathon": null,
"Consul": null,
"ConsulCatalog": null,
"Etcd": null,
@ -73,7 +72,6 @@
"Boltdb": null,
"KubernetesIngress": null,
"KubernetesCRD": null,
"Mesos": null,
"Eureka": null,
"ECS": null,
"DynamoDB": null,