Remove Marathon provider
This commit is contained in:
parent
2ad1fd725a
commit
2b67f1f66f
80 changed files with 11 additions and 7802 deletions
|
@ -11,7 +11,7 @@
|
|||
[](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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
# ...
|
||||
```
|
|
@ -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)
|
||||
|
|
|
@ -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",
|
|
@ -1,2 +0,0 @@
|
|||
"traefik.enable": "true",
|
||||
"traefik.marathon.ipaddressidx": "42",
|
|
@ -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"
|
||||
}
|
||||
```
|
|
@ -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```)
|
||||
|
||||
|
|
|
@ -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```)
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
|
@ -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."
|
||||
|
||||
|
|
|
@ -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).
|
|
@ -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
2
go.mod
|
@ -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
4
go.sum
|
@ -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=
|
||||
|
|
|
@ -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
|
|
@ -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{})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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{},
|
||||
|
|
1
pkg/api/testdata/overview-providers.json
vendored
1
pkg/api/testdata/overview-providers.json
vendored
|
@ -25,7 +25,6 @@
|
|||
"providers": [
|
||||
"Docker",
|
||||
"File",
|
||||
"Marathon",
|
||||
"KubernetesIngress",
|
||||
"KubernetesCRD",
|
||||
"Rest",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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...)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
2
pkg/redactor/testdata/example.json
vendored
2
pkg/redactor/testdata/example.json
vendored
|
@ -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,
|
||||
|
|
2
pkg/redactor/testdata/expected.json
vendored
2
pkg/redactor/testdata/expected.json
vendored
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue