Merge pull request #266 from containous/refactor-frontend-rules
Refactor frontends rules
This commit is contained in:
commit
733cbb5304
26 changed files with 335 additions and 426 deletions
307
docs/index.md
307
docs/index.md
|
@ -2,25 +2,25 @@
|
||||||
<img src="http://traefik.github.io/traefik.logo.svg" alt="Træfɪk" title="Træfɪk" />
|
<img src="http://traefik.github.io/traefik.logo.svg" alt="Træfɪk" title="Træfɪk" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
# <a id="top"></a> Documentation
|
# Documentation
|
||||||
|
|
||||||
- [Basics](#basics)
|
- [Basics](#basics)
|
||||||
- [Launch configuration](#launch)
|
- [Launch configuration](#launch-configuration)
|
||||||
- [Global configuration](#global)
|
- [Global configuration](#global-configuration)
|
||||||
- [File backend](#file)
|
- [File backend](#file-backend)
|
||||||
- [API backend](#api)
|
- [API backend](#api-backend)
|
||||||
- [Docker backend](#docker)
|
- [Docker backend](#docker-backend)
|
||||||
- [Mesos/Marathon backend](#marathon)
|
- [Mesos/Marathon backend](#marathon-backend)
|
||||||
- [Consul backend](#consul)
|
- [Consul backend](#consul-backend)
|
||||||
- [Consul catalog backend](#consulcatalog)
|
- [Consul catalog backend](#consul-catalog-backend)
|
||||||
- [Etcd backend](#etcd)
|
- [Etcd backend](#etcd-backend)
|
||||||
- [Zookeeper backend](#zk)
|
- [Zookeeper backend](#zookeeper-backend)
|
||||||
- [Boltdb backend](#boltdb)
|
- [Boltdb backend](#boltdb-backend)
|
||||||
- [Atomic configuration changes](#atomicconfig)
|
- [Atomic configuration changes](#atomic-configuration-changes)
|
||||||
- [Benchmarks](#benchmarks)
|
- [Benchmarks](#benchmarks)
|
||||||
|
|
||||||
|
|
||||||
## <a id="basics"></a> Basics
|
## Basics
|
||||||
|
|
||||||
|
|
||||||
Træfɪk is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
Træfɪk is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease.
|
||||||
|
@ -28,12 +28,12 @@ It supports several backends ([Docker :whale:](https://www.docker.com/), [Mesos/
|
||||||
|
|
||||||
Basically, Træfɪk is a http router, which sends traffic from frontends to http backends, following rules you have configured.
|
Basically, Træfɪk is a http router, which sends traffic from frontends to http backends, following rules you have configured.
|
||||||
|
|
||||||
### <a id="frontends"></a> Frontends
|
### Frontends
|
||||||
|
|
||||||
Frontends can be defined using the following rules:
|
Frontends can be defined using the following rules:
|
||||||
|
|
||||||
- `Headers`: Headers adds a matcher for request header values. It accepts a sequence of key/value pairs to be matched. For example: `application/json`
|
- `Headers`: Headers adds a matcher for request header values. It accepts a sequence of key/value pairs to be matched. For example: `Content-Type, application/json`
|
||||||
- `HeadersRegexp`: Regular expressions can be used with headers as well. It accepts a sequence of key/value pairs, where the value has regex support. For example: `application/(text|json)`
|
- `HeadersRegexp`: Regular expressions can be used with headers as well. It accepts a sequence of key/value pairs, where the value has regex support. For example: `Content-Type, application/(text|json)`
|
||||||
- `Host`: Host adds a matcher for the URL host. It accepts a template with zero or more URL variables enclosed by `{}`. Variables can define an optional regexp pattern to be matched: `www.traefik.io`, `{subdomain:[a-z]+}.traefik.io`
|
- `Host`: Host adds a matcher for the URL host. It accepts a template with zero or more URL variables enclosed by `{}`. Variables can define an optional regexp pattern to be matched: `www.traefik.io`, `{subdomain:[a-z]+}.traefik.io`
|
||||||
- `Methods`: Methods adds a matcher for HTTP methods. It accepts a sequence of one or more methods to be matched, e.g.: `GET`, `POST`, `PUT`
|
- `Methods`: Methods adds a matcher for HTTP methods. It accepts a sequence of one or more methods to be matched, e.g.: `GET`, `POST`, `PUT`
|
||||||
- `Path`: Path adds a matcher for the URL path. It accepts a template with zero or more URL variables enclosed by `{}`. The template must start with a `/`. For exemple `/products/` `/articles/{category}/{id:[0-9]+}`
|
- `Path`: Path adds a matcher for the URL path. It accepts a template with zero or more URL variables enclosed by `{}`. The template must start with a `/`. For exemple `/products/` `/articles/{category}/{id:[0-9]+}`
|
||||||
|
@ -70,7 +70,7 @@ For example:
|
||||||
- `ResponseCodeRatio(500, 600, 0, 600) > 0.5`: ratio of response codes in range [500-600) to [0-600)
|
- `ResponseCodeRatio(500, 600, 0, 600) > 0.5`: ratio of response codes in range [500-600) to [0-600)
|
||||||
|
|
||||||
|
|
||||||
## <a id="launch"></a> Launch configuration
|
## Launch configuration
|
||||||
|
|
||||||
Træfɪk can be configured using a TOML file configuration, arguments, or both.
|
Træfɪk can be configured using a TOML file configuration, arguments, or both.
|
||||||
By default, Træfɪk will try to find a `traefik.toml` in the following places:
|
By default, Træfɪk will try to find a `traefik.toml` in the following places:
|
||||||
|
@ -176,7 +176,7 @@ Flags:
|
||||||
Use "traefik [command] --help" for more information about a command.
|
Use "traefik [command] --help" for more information about a command.
|
||||||
```
|
```
|
||||||
|
|
||||||
## <a id="global"></a> Global configuration
|
## Global configuration
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
# traefik.toml
|
# traefik.toml
|
||||||
|
@ -432,24 +432,21 @@ entryPoint = "https"
|
||||||
[frontends.frontend1]
|
[frontends.frontend1]
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
[frontends.frontend1.routes.test_1]
|
[frontends.frontend1.routes.test_1]
|
||||||
rule = "Host"
|
rule = "Host:test.localhost"
|
||||||
value = "test.localhost"
|
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
[frontends.frontend2.routes.test_1]
|
[frontends.frontend2.routes.test_1]
|
||||||
rule = "Host"
|
rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||||
value = "{subdomain:[a-z]+}.localhost"
|
|
||||||
[frontends.frontend3]
|
[frontends.frontend3]
|
||||||
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
rule = "Path"
|
rule = "Path:/test"
|
||||||
value = "/test"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## <a id="file"></a> File backend
|
## File backend
|
||||||
|
|
||||||
Like any other reverse proxy, Træfɪk can be configured with a file. You have two choices:
|
Like any other reverse proxy, Træfɪk can be configured with a file. You have two choices:
|
||||||
|
|
||||||
|
@ -502,20 +499,17 @@ logLevel = "DEBUG"
|
||||||
[frontends.frontend1]
|
[frontends.frontend1]
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
[frontends.frontend1.routes.test_1]
|
[frontends.frontend1.routes.test_1]
|
||||||
rule = "Host"
|
rule = "Host:test.localhost"
|
||||||
value = "test.localhost"
|
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
[frontends.frontend2.routes.test_1]
|
[frontends.frontend2.routes.test_1]
|
||||||
rule = "Host"
|
rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||||
value = "{subdomain:[a-z]+}.localhost"
|
|
||||||
[frontends.frontend3]
|
[frontends.frontend3]
|
||||||
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
rule = "Path"
|
rule = "Path:/test"
|
||||||
value = "/test"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
- or put your rules in a separate file, for example `rules.tml`:
|
- or put your rules in a separate file, for example `rules.tml`:
|
||||||
|
@ -569,20 +563,17 @@ filename = "rules.toml"
|
||||||
[frontends.frontend1]
|
[frontends.frontend1]
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
[frontends.frontend1.routes.test_1]
|
[frontends.frontend1.routes.test_1]
|
||||||
rule = "Host"
|
rule = "Host:test.localhost"
|
||||||
value = "test.localhost"
|
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
[frontends.frontend2.routes.test_1]
|
[frontends.frontend2.routes.test_1]
|
||||||
rule = "Host"
|
rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||||
value = "{subdomain:[a-z]+}.localhost"
|
|
||||||
[frontends.frontend3]
|
[frontends.frontend3]
|
||||||
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
rule = "Path"
|
rule = "Path:/test"
|
||||||
value = "/test"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
If you want Træfɪk to watch file changes automatically, just add:
|
If you want Træfɪk to watch file changes automatically, just add:
|
||||||
|
@ -592,7 +583,7 @@ If you want Træfɪk to watch file changes automatically, just add:
|
||||||
watch = true
|
watch = true
|
||||||
```
|
```
|
||||||
|
|
||||||
## <a id="api"></a> API backend
|
## API backend
|
||||||
|
|
||||||
Træfik can be configured using a restful api.
|
Træfik can be configured using a restful api.
|
||||||
To enable it:
|
To enable it:
|
||||||
|
@ -669,8 +660,7 @@ $ curl -s "http://localhost:8080/api" | jq .
|
||||||
"frontend2": {
|
"frontend2": {
|
||||||
"routes": {
|
"routes": {
|
||||||
"test_2": {
|
"test_2": {
|
||||||
"value": "/test",
|
"rule": "Path:/test"
|
||||||
"rule": "Path"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backend": "backend1"
|
"backend": "backend1"
|
||||||
|
@ -678,8 +668,7 @@ $ curl -s "http://localhost:8080/api" | jq .
|
||||||
"frontend1": {
|
"frontend1": {
|
||||||
"routes": {
|
"routes": {
|
||||||
"test_1": {
|
"test_1": {
|
||||||
"value": "test.localhost",
|
"rule": "Host:test.localhost"
|
||||||
"rule": "Host"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"backend": "backend2"
|
"backend": "backend2"
|
||||||
|
@ -736,7 +725,7 @@ $ curl -s "http://localhost:8080/api" | jq .
|
||||||
- `/api/providers/{provider}/frontends/{frontend}/routes/{route}`: `GET` a route in a frontend
|
- `/api/providers/{provider}/frontends/{frontend}/routes/{route}`: `GET` a route in a frontend
|
||||||
|
|
||||||
|
|
||||||
## <a id="docker"></a> Docker backend
|
## Docker backend
|
||||||
|
|
||||||
Træfɪk can be configured to use Docker as a backend configuration:
|
Træfɪk can be configured to use Docker as a backend configuration:
|
||||||
|
|
||||||
|
@ -792,14 +781,13 @@ Labels can be used on containers to override default behaviour:
|
||||||
- `traefik.protocol=https`: override the default `http` protocol
|
- `traefik.protocol=https`: override the default `http` protocol
|
||||||
- `traefik.weight=10`: assign this weight to the container
|
- `traefik.weight=10`: assign this weight to the container
|
||||||
- `traefik.enable=false`: disable this container in Træfɪk
|
- `traefik.enable=false`: disable this container in Træfɪk
|
||||||
- `traefik.frontend.rule=Host`: override the default frontend rule (Default: Host). See [frontends](#frontends).
|
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`). See [frontends](#frontends).
|
||||||
- `traefik.frontend.value=test.example.com`: override the default frontend value (Default: `{containerName}.{domain}`) See [frontends](#frontends). Must be associated with label traefik.frontend.rule.
|
|
||||||
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
||||||
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||||
* `traefik.domain=traefik.localhost`: override the default domain
|
* `traefik.domain=traefik.localhost`: override the default domain
|
||||||
|
|
||||||
|
|
||||||
## <a id="marathon"></a> Marathon backend
|
## Marathon backend
|
||||||
|
|
||||||
Træfɪk can be configured to use Marathon as a backend configuration:
|
Træfɪk can be configured to use Marathon as a backend configuration:
|
||||||
|
|
||||||
|
@ -873,13 +861,12 @@ Labels can be used on containers to override default behaviour:
|
||||||
- `traefik.protocol=https`: override the default `http` protocol
|
- `traefik.protocol=https`: override the default `http` protocol
|
||||||
- `traefik.weight=10`: assign this weight to the application
|
- `traefik.weight=10`: assign this weight to the application
|
||||||
- `traefik.enable=false`: disable this application in Træfɪk
|
- `traefik.enable=false`: disable this application in Træfɪk
|
||||||
- `traefik.frontend.rule=Host`: override the default frontend rule (Default: Host). See [frontends](#frontends).
|
- `traefik.frontend.rule=Host:test.traefik.io`: override the default frontend rule (Default: `Host:{containerName}.{domain}`). See [frontends](#frontends).
|
||||||
- `traefik.frontend.value=test.example.com`: override the default frontend value (Default: `{appName}.{domain}`) See [frontends](#frontends). Must be associated with label traefik.frontend.rule.
|
|
||||||
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
- `traefik.frontend.passHostHeader=true`: forward client `Host` header to the backend.
|
||||||
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
- `traefik.frontend.entryPoints=http,https`: assign this frontend to entry points `http` and `https`. Overrides `defaultEntryPoints`.
|
||||||
* `traefik.domain=traefik.localhost`: override the default domain
|
* `traefik.domain=traefik.localhost`: override the default domain
|
||||||
|
|
||||||
## <a id="consul"></a> Consul backend
|
## Consul backend
|
||||||
|
|
||||||
Træfɪk can be configured to use Consul as a backend configuration:
|
Træfɪk can be configured to use Consul as a backend configuration:
|
||||||
|
|
||||||
|
@ -929,48 +916,41 @@ prefix = "traefik"
|
||||||
# insecureskipverify = true
|
# insecureskipverify = true
|
||||||
```
|
```
|
||||||
|
|
||||||
The Keys-Values structure should look (using `prefix = "/traefik"`):
|
Please refer to the [Key Value storage structure](#key-value-storage-structure) section to get documentation en traefik KV structure.
|
||||||
|
|
||||||
- backend 1
|
## Consul catalog backend
|
||||||
|
|
||||||
| Key | Value |
|
Træfɪk can be configured to use service discovery catalog of Consul as a backend configuration:
|
||||||
|--------------------------------------------------------|-----------------------------|
|
|
||||||
| `/traefik/backends/backend1/circuitbreaker/expression` | `NetworkErrorRatio() > 0.5` |
|
|
||||||
| `/traefik/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
|
|
||||||
| `/traefik/backends/backend1/servers/server1/weight` | `10` |
|
|
||||||
| `/traefik/backends/backend1/servers/server2/url` | `http://172.17.0.3:80` |
|
|
||||||
| `/traefik/backends/backend1/servers/server2/weight` | `1` |
|
|
||||||
|
|
||||||
- backend 2
|
```toml
|
||||||
|
################################################################
|
||||||
|
# Consul Catalog configuration backend
|
||||||
|
################################################################
|
||||||
|
|
||||||
| Key | Value |
|
# Enable Consul Catalog configuration backend
|
||||||
|-----------------------------------------------------|------------------------|
|
#
|
||||||
| `/traefik/backends/backend2/loadbalancer/method` | `drr` |
|
# Optional
|
||||||
| `/traefik/backends/backend2/servers/server1/url` | `http://172.17.0.4:80` |
|
#
|
||||||
| `/traefik/backends/backend2/servers/server1/weight` | `1` |
|
[consulCatalog]
|
||||||
| `/traefik/backends/backend2/servers/server2/url` | `http://172.17.0.5:80` |
|
|
||||||
| `/traefik/backends/backend2/servers/server2/weight` | `2` |
|
|
||||||
|
|
||||||
- frontend 1
|
# Consul server endpoint
|
||||||
|
#
|
||||||
|
# Required
|
||||||
|
#
|
||||||
|
endpoint = "127.0.0.1:8500"
|
||||||
|
|
||||||
| Key | Value |
|
# Default domain used.
|
||||||
|----------------------------------------------------|------------------|
|
#
|
||||||
| `/traefik/frontends/frontend1/backend` | `backend2` |
|
# Optional
|
||||||
| `/traefik/frontends/frontend1/routes/test_1/rule` | `Host` |
|
#
|
||||||
| `/traefik/frontends/frontend1/routes/test_1/value` | `test.localhost` |
|
domain = "consul.localhost"
|
||||||
|
```
|
||||||
|
|
||||||
- frontend 2
|
This backend will create routes matching on hostname based on the service name
|
||||||
|
used in consul.
|
||||||
| Key | Value |
|
|
||||||
|----------------------------------------------------|------------|
|
|
||||||
| `/traefik/frontends/frontend2/backend` | `backend1` |
|
|
||||||
| `/traefik/frontends/frontend2/passHostHeader` | `true` |
|
|
||||||
| `/traefik/frontends/frontend2/entrypoints` |`http,https`|
|
|
||||||
| `/traefik/frontends/frontend2/routes/test_2/rule` | `Path` |
|
|
||||||
| `/traefik/frontends/frontend2/routes/test_2/value` | `/test` |
|
|
||||||
|
|
||||||
|
|
||||||
## <a id="etcd"></a> Etcd backend
|
## Etcd backend
|
||||||
|
|
||||||
Træfɪk can be configured to use Etcd as a backend configuration:
|
Træfɪk can be configured to use Etcd as a backend configuration:
|
||||||
|
|
||||||
|
@ -1020,79 +1000,10 @@ Træfɪk can be configured to use Etcd as a backend configuration:
|
||||||
# insecureskipverify = true
|
# insecureskipverify = true
|
||||||
```
|
```
|
||||||
|
|
||||||
The Keys-Values structure should look (using `prefix = "/traefik"`):
|
Please refer to the [Key Value storage structure](#key-value-storage-structure) section to get documentation en traefik KV structure.
|
||||||
|
|
||||||
- backend 1
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|--------------------------------------------------------|-----------------------------|
|
|
||||||
| `/traefik/backends/backend1/circuitbreaker/expression` | `NetworkErrorRatio() > 0.5` |
|
|
||||||
| `/traefik/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
|
|
||||||
| `/traefik/backends/backend1/servers/server1/weight` | `10` |
|
|
||||||
| `/traefik/backends/backend1/servers/server2/url` | `http://172.17.0.3:80` |
|
|
||||||
| `/traefik/backends/backend1/servers/server2/weight` | `1` |
|
|
||||||
|
|
||||||
- backend 2
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|-----------------------------------------------------|------------------------|
|
|
||||||
| `/traefik/backends/backend2/loadbalancer/method` | `drr` |
|
|
||||||
| `/traefik/backends/backend2/servers/server1/url` | `http://172.17.0.4:80` |
|
|
||||||
| `/traefik/backends/backend2/servers/server1/weight` | `1` |
|
|
||||||
| `/traefik/backends/backend2/servers/server2/url` | `http://172.17.0.5:80` |
|
|
||||||
| `/traefik/backends/backend2/servers/server2/weight` | `2` |
|
|
||||||
|
|
||||||
- frontend 1
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|----------------------------------------------------|------------------|
|
|
||||||
| `/traefik/frontends/frontend1/backend` | `backend2` |
|
|
||||||
| `/traefik/frontends/frontend1/routes/test_1/rule` | `Host` |
|
|
||||||
| `/traefik/frontends/frontend1/routes/test_1/value` | `test.localhost` |
|
|
||||||
|
|
||||||
- frontend 2
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|----------------------------------------------------|------------|
|
|
||||||
| `/traefik/frontends/frontend2/backend` | `backend1` |
|
|
||||||
| `/traefik/frontends/frontend2/passHostHeader` | `true` |
|
|
||||||
| `/traefik/frontends/frontend2/entrypoints` |`http,https`|
|
|
||||||
| `/traefik/frontends/frontend2/routes/test_2/rule` | `Path` |
|
|
||||||
| `/traefik/frontends/frontend2/routes/test_2/value` | `/test` |
|
|
||||||
|
|
||||||
|
|
||||||
## <a id="consulcatalog"></a> Consul catalog backend
|
## Zookeeper backend
|
||||||
|
|
||||||
Træfɪk can be configured to use service discovery catalog of Consul as a backend configuration:
|
|
||||||
|
|
||||||
```toml
|
|
||||||
################################################################
|
|
||||||
# Consul Catalog configuration backend
|
|
||||||
################################################################
|
|
||||||
|
|
||||||
# Enable Consul Catalog configuration backend
|
|
||||||
#
|
|
||||||
# Optional
|
|
||||||
#
|
|
||||||
[consulCatalog]
|
|
||||||
|
|
||||||
# Consul server endpoint
|
|
||||||
#
|
|
||||||
# Required
|
|
||||||
#
|
|
||||||
endpoint = "127.0.0.1:8500"
|
|
||||||
|
|
||||||
# Default domain used.
|
|
||||||
#
|
|
||||||
# Optional
|
|
||||||
#
|
|
||||||
domain = "consul.localhost"
|
|
||||||
```
|
|
||||||
|
|
||||||
This backend will create routes matching on hostname based on the service name
|
|
||||||
used in consul.
|
|
||||||
|
|
||||||
## <a id="zk"></a> Zookeeper backend
|
|
||||||
|
|
||||||
Træfɪk can be configured to use Zookeeper as a backend configuration:
|
Træfɪk can be configured to use Zookeeper as a backend configuration:
|
||||||
|
|
||||||
|
@ -1131,48 +1042,10 @@ Træfɪk can be configured to use Zookeeper as a backend configuration:
|
||||||
#
|
#
|
||||||
# filename = "zookeeper.tmpl"
|
# filename = "zookeeper.tmpl"
|
||||||
```
|
```
|
||||||
The Keys-Values structure should look (using `prefix = "/traefik"`):
|
|
||||||
|
|
||||||
- backend 1
|
Please refer to the [Key Value storage structure](#key-value-storage-structure) section to get documentation en traefik KV structure.
|
||||||
|
|
||||||
| Key | Value |
|
## BoltDB backend
|
||||||
|--------------------------------------------------------|-----------------------------|
|
|
||||||
| `/traefik/backends/backend1/circuitbreaker/expression` | `NetworkErrorRatio() > 0.5` |
|
|
||||||
| `/traefik/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
|
|
||||||
| `/traefik/backends/backend1/servers/server1/weight` | `10` |
|
|
||||||
| `/traefik/backends/backend1/servers/server2/url` | `http://172.17.0.3:80` |
|
|
||||||
| `/traefik/backends/backend1/servers/server2/weight` | `1` |
|
|
||||||
|
|
||||||
- backend 2
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|-----------------------------------------------------|------------------------|
|
|
||||||
| `/traefik/backends/backend2/loadbalancer/method` | `drr` |
|
|
||||||
| `/traefik/backends/backend2/servers/server1/url` | `http://172.17.0.4:80` |
|
|
||||||
| `/traefik/backends/backend2/servers/server1/weight` | `1` |
|
|
||||||
| `/traefik/backends/backend2/servers/server2/url` | `http://172.17.0.5:80` |
|
|
||||||
| `/traefik/backends/backend2/servers/server2/weight` | `2` |
|
|
||||||
|
|
||||||
- frontend 1
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|---------------------------------------------------|------------------|
|
|
||||||
| `/traefik/frontends/frontend1/backend | `backend2` |
|
|
||||||
| `/traefik/frontends/frontend1/routes/test_1/rule | `Host` |
|
|
||||||
| `/traefik/frontends/frontend1/routes/test_1/value | `test.localhost` |
|
|
||||||
|
|
||||||
- frontend 2
|
|
||||||
|
|
||||||
| Key | Value |
|
|
||||||
|----------------------------------------------------|------------|
|
|
||||||
| `/traefik/frontends/frontend2/backend` | `backend1` |
|
|
||||||
| `/traefik/frontends/frontend2/passHostHeader` | `true` |
|
|
||||||
| `/traefik/frontends/frontend2/entrypoints` |`http,https`|
|
|
||||||
| `/traefik/frontends/frontend2/routes/test_2/rule` | `Path` |
|
|
||||||
| `/traefik/frontends/frontend2/routes/test_2/value` | `/test` |
|
|
||||||
|
|
||||||
|
|
||||||
## <a id="boltdb"></a> BoltDB backend
|
|
||||||
|
|
||||||
Træfɪk can be configured to use BoltDB as a backend configuration:
|
Træfɪk can be configured to use BoltDB as a backend configuration:
|
||||||
|
|
||||||
|
@ -1212,7 +1085,49 @@ Træfɪk can be configured to use BoltDB as a backend configuration:
|
||||||
# filename = "boltdb.tmpl"
|
# filename = "boltdb.tmpl"
|
||||||
```
|
```
|
||||||
|
|
||||||
## <a id="atomicconfig"></a> Atomic configuration changes
|
Please refer to the [Key Value storage structure](#key-value-storage-structure) section to get documentation en traefik KV structure.
|
||||||
|
|
||||||
|
## Key-value storage structure
|
||||||
|
|
||||||
|
The Keys-Values structure should look (using `prefix = "/traefik"`):
|
||||||
|
|
||||||
|
- backend 1
|
||||||
|
|
||||||
|
| Key | Value |
|
||||||
|
|--------------------------------------------------------|-----------------------------|
|
||||||
|
| `/traefik/backends/backend1/circuitbreaker/expression` | `NetworkErrorRatio() > 0.5` |
|
||||||
|
| `/traefik/backends/backend1/servers/server1/url` | `http://172.17.0.2:80` |
|
||||||
|
| `/traefik/backends/backend1/servers/server1/weight` | `10` |
|
||||||
|
| `/traefik/backends/backend1/servers/server2/url` | `http://172.17.0.3:80` |
|
||||||
|
| `/traefik/backends/backend1/servers/server2/weight` | `1` |
|
||||||
|
|
||||||
|
- backend 2
|
||||||
|
|
||||||
|
| Key | Value |
|
||||||
|
|-----------------------------------------------------|------------------------|
|
||||||
|
| `/traefik/backends/backend2/loadbalancer/method` | `drr` |
|
||||||
|
| `/traefik/backends/backend2/servers/server1/url` | `http://172.17.0.4:80` |
|
||||||
|
| `/traefik/backends/backend2/servers/server1/weight` | `1` |
|
||||||
|
| `/traefik/backends/backend2/servers/server2/url` | `http://172.17.0.5:80` |
|
||||||
|
| `/traefik/backends/backend2/servers/server2/weight` | `2` |
|
||||||
|
|
||||||
|
- frontend 1
|
||||||
|
|
||||||
|
| Key | Value |
|
||||||
|
|---------------------------------------------------|-----------------------|
|
||||||
|
| `/traefik/frontends/frontend1/backend` | `backend2` |
|
||||||
|
| `/traefik/frontends/frontend1/routes/test_1/rule` | `Host:test.localhost` |
|
||||||
|
|
||||||
|
- frontend 2
|
||||||
|
|
||||||
|
| Key | Value |
|
||||||
|
|----------------------------------------------------|--------------|
|
||||||
|
| `/traefik/frontends/frontend2/backend` | `backend1` |
|
||||||
|
| `/traefik/frontends/frontend2/passHostHeader` | `true` |
|
||||||
|
| `/traefik/frontends/frontend2/entrypoints` | `http,https` |
|
||||||
|
| `/traefik/frontends/frontend2/routes/test_2/rule` | `Path:/test` |
|
||||||
|
|
||||||
|
## Atomic configuration changes
|
||||||
|
|
||||||
The [Etcd](https://github.com/coreos/etcd/issues/860) and [Consul](https://github.com/hashicorp/consul/issues/886) backends do not support updating multiple keys atomically. As a result, it may be possible for Træfɪk to read an intermediate configuration state despite judicious use of the `--providersThrottleDuration` flag. To solve this problem, Træfɪk supports a special key called `/traefik/alias`. If set, Træfɪk use the value as an alternative key prefix.
|
The [Etcd](https://github.com/coreos/etcd/issues/860) and [Consul](https://github.com/hashicorp/consul/issues/886) backends do not support updating multiple keys atomically. As a result, it may be possible for Træfɪk to read an intermediate configuration state despite judicious use of the `--providersThrottleDuration` flag. To solve this problem, Træfɪk supports a special key called `/traefik/alias`. If set, Træfɪk use the value as an alternative key prefix.
|
||||||
|
|
||||||
|
@ -1251,7 +1166,7 @@ Once the `/traefik/alias` key is updated, the new `/traefik_configurations/2` co
|
||||||
Note that Træfɪk *will not watch for key changes in the `/traefik_configurations` prefix*. It will only watch for changes in the `/traefik` prefix. Further, if the `/traefik/alias` key is set, all other sibling keys with the `/traefik` prefix are ignored.
|
Note that Træfɪk *will not watch for key changes in the `/traefik_configurations` prefix*. It will only watch for changes in the `/traefik` prefix. Further, if the `/traefik/alias` key is set, all other sibling keys with the `/traefik` prefix are ignored.
|
||||||
|
|
||||||
|
|
||||||
## <a id="benchmarks"></a> Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
Here are some early Benchmarks between Nginx, HA-Proxy and Træfɪk acting as simple load balancers between two servers.
|
Here are some early Benchmarks between Nginx, HA-Proxy and Træfɪk acting as simple load balancers between two servers.
|
||||||
|
|
||||||
|
|
6
glide.lock
generated
6
glide.lock
generated
|
@ -1,5 +1,5 @@
|
||||||
hash: 21d4e8dc80c87101568a719ecf01d1af9a1b58f03c5c9dc864a8cb1005ddc160
|
hash: a8cca3f2e5bde6b96d0c195402b14606877bc8630cd7f2f06e65e0884c6a008b
|
||||||
updated: 2016-03-29T21:50:20.577439177+02:00
|
updated: 2016-03-29T23:24:08.772606184+02:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/alecthomas/template
|
- name: github.com/alecthomas/template
|
||||||
version: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0
|
version: b867cc6ab45cece8143cfcc6fc9c77cf3f2c23c0
|
||||||
|
@ -264,7 +264,7 @@ imports:
|
||||||
subpackages:
|
subpackages:
|
||||||
- bson
|
- bson
|
||||||
- name: gopkg.in/square/go-jose.v1
|
- name: gopkg.in/square/go-jose.v1
|
||||||
version: 7d9df93c5ee8a09ed250b3b2360972fa29b4bb3c
|
version: 40d457b439244b546f023d056628e5184136899b
|
||||||
subpackages:
|
subpackages:
|
||||||
- cipher
|
- cipher
|
||||||
- json
|
- json
|
||||||
|
|
|
@ -44,7 +44,7 @@ import:
|
||||||
ref: 6b4e7dc5e3143b85ea77909c72caf89416fc2915
|
ref: 6b4e7dc5e3143b85ea77909c72caf89416fc2915
|
||||||
- package: github.com/gambol99/go-marathon
|
- package: github.com/gambol99/go-marathon
|
||||||
ref: ade11d1dc2884ee1f387078fc28509559b6235d1
|
ref: ade11d1dc2884ee1f387078fc28509559b6235d1
|
||||||
- package: github.com/mailgun/predicate
|
- package: github.com/vulcand/predicate
|
||||||
ref: cb0bff91a7ab7cf7571e661ff883fc997bc554a3
|
ref: cb0bff91a7ab7cf7571e661ff883fc997bc554a3
|
||||||
- package: github.com/thoas/stats
|
- package: github.com/thoas/stats
|
||||||
ref: 54ed61c2b47e263ae2f01b86837b0c4bd1da28e8
|
ref: 54ed61c2b47e263ae2f01b86837b0c4bd1da28e8
|
||||||
|
|
|
@ -133,8 +133,7 @@ func (s *DockerSuite) TestDockerContainersWithLabels(c *check.C) {
|
||||||
defer os.Remove(file)
|
defer os.Remove(file)
|
||||||
// Start a container with some labels
|
// Start a container with some labels
|
||||||
labels := map[string]string{
|
labels := map[string]string{
|
||||||
"traefik.frontend.rule": "Host",
|
"traefik.frontend.rule": "Host:my.super.host",
|
||||||
"traefik.frontend.value": "my.super.host",
|
|
||||||
}
|
}
|
||||||
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blabla")
|
s.startContainerWithLabels(c, "swarm:1.0.0", labels, "manage", "token://blabla")
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,8 @@ logLevel = "DEBUG"
|
||||||
[frontends.frontend1]
|
[frontends.frontend1]
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
[frontends.frontend1.routes.test_1]
|
[frontends.frontend1.routes.test_1]
|
||||||
rule = "Host"
|
rule = "Host:test.localhost"
|
||||||
value = "test.localhost"
|
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
[frontends.frontend2.routes.test_2]
|
[frontends.frontend2.routes.test_2]
|
||||||
rule = "Path"
|
rule = "Path:/test"
|
||||||
value = "/test"
|
|
||||||
|
|
|
@ -27,10 +27,8 @@ defaultEntryPoints = ["https"]
|
||||||
[frontends.frontend1]
|
[frontends.frontend1]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
[frontends.frontend1.routes.test_1]
|
[frontends.frontend1.routes.test_1]
|
||||||
rule = "Host"
|
rule = "Host:snitest.com"
|
||||||
value = "snitest.com"
|
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
[frontends.frontend2.routes.test_2]
|
[frontends.frontend2.routes.test_2]
|
||||||
rule = "Host"
|
rule = "Host:snitest.org"
|
||||||
value = "snitest.org"
|
|
||||||
|
|
|
@ -20,3 +20,8 @@ func (s *StripPrefix) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetHandler sets handler
|
||||||
|
func (s *StripPrefix) SetHandler(Handler http.Handler) {
|
||||||
|
s.Handler = Handler
|
||||||
|
}
|
|
@ -89,7 +89,7 @@ func (provider *ConsulCatalog) getBackend(node *api.ServiceEntry) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *ConsulCatalog) getFrontendValue(service string) string {
|
func (provider *ConsulCatalog) getFrontendValue(service string) string {
|
||||||
return service + "." + provider.Domain
|
return "Host:" + service + "." + provider.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *ConsulCatalog) buildConfig(catalog []catalogUpdate) *types.Configuration {
|
func (provider *ConsulCatalog) buildConfig(catalog []catalogUpdate) *types.Configuration {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/hashicorp/consul/api"
|
"github.com/hashicorp/consul/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestConsulCatalogGetFrontendValue(t *testing.T) {
|
func TestConsulCatalogGetFrontendRule(t *testing.T) {
|
||||||
provider := &ConsulCatalog{
|
provider := &ConsulCatalog{
|
||||||
Domain: "localhost",
|
Domain: "localhost",
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ func TestConsulCatalogGetFrontendValue(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
service: "foo",
|
service: "foo",
|
||||||
expected: "foo.localhost",
|
expected: "Host:foo.localhost",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,8 +78,7 @@ func TestConsulCatalogBuildConfig(t *testing.T) {
|
||||||
Backend: "backend-test",
|
Backend: "backend-test",
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
"route-host-test": {
|
"route-host-test": {
|
||||||
Rule: "Host",
|
Rule: "Host:test.localhost",
|
||||||
Value: "test.localhost",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,7 +2,6 @@ package provider
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
@ -108,7 +107,6 @@ func (provider *Docker) loadDockerConfig(containersInspected []docker.Container)
|
||||||
"getProtocol": provider.getProtocol,
|
"getProtocol": provider.getProtocol,
|
||||||
"getPassHostHeader": provider.getPassHostHeader,
|
"getPassHostHeader": provider.getPassHostHeader,
|
||||||
"getEntryPoints": provider.getEntryPoints,
|
"getEntryPoints": provider.getEntryPoints,
|
||||||
"getFrontendValue": provider.getFrontendValue,
|
|
||||||
"getFrontendRule": provider.getFrontendRule,
|
"getFrontendRule": provider.getFrontendRule,
|
||||||
"replace": replace,
|
"replace": replace,
|
||||||
}
|
}
|
||||||
|
@ -154,47 +152,37 @@ func containerFilter(container docker.Container) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
labels, err := getLabels(container, []string{"traefik.frontend.rule", "traefik.frontend.value"})
|
|
||||||
if len(labels) != 0 && err != nil {
|
|
||||||
log.Debugf("Filtering bad labeled container %s", container.Name)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Docker) getFrontendName(container docker.Container) string {
|
func (provider *Docker) getFrontendName(container docker.Container) string {
|
||||||
// Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78
|
// Replace '.' with '-' in quoted keys because of this issue https://github.com/BurntSushi/toml/issues/78
|
||||||
frontendName := fmt.Sprintf("%s-%s", provider.getFrontendRule(container), provider.getFrontendValue(container))
|
return normalize(provider.getFrontendRule(container))
|
||||||
frontendName = strings.Replace(frontendName, "[", "", -1)
|
|
||||||
frontendName = strings.Replace(frontendName, "]", "", -1)
|
|
||||||
|
|
||||||
return strings.Replace(frontendName, ".", "-", -1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFrontendValue returns the frontend value for the specified container, using
|
|
||||||
// it's label. It returns a default one if the label is not present.
|
|
||||||
func (provider *Docker) getFrontendValue(container docker.Container) string {
|
|
||||||
if label, err := getLabel(container, "traefik.frontend.value"); err == nil {
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
return getEscapedName(container.Name) + "." + provider.Domain
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFrontendRule returns the frontend rule for the specified container, using
|
// GetFrontendRule returns the frontend rule for the specified container, using
|
||||||
// it's label. It returns a default one (Host) if the label is not present.
|
// it's label. It returns a default one (Host) if the label is not present.
|
||||||
func (provider *Docker) getFrontendRule(container docker.Container) string {
|
func (provider *Docker) getFrontendRule(container docker.Container) string {
|
||||||
|
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
|
||||||
|
// TODO: backwards compatibility with DEPRECATED rule.Value
|
||||||
|
if value, ok := container.Config.Labels["traefik.frontend.value"]; ok {
|
||||||
|
log.Warnf("Label traefik.frontend.value=%s is DEPRECATED (will be removed in v1.0.0), please refer to the rule label: https://github.com/containous/traefik/blob/master/docs/index.md#docker", value)
|
||||||
|
rule, _ := container.Config.Labels["traefik.frontend.rule"]
|
||||||
|
return rule + ":" + value
|
||||||
|
}
|
||||||
|
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
|
||||||
|
|
||||||
if label, err := getLabel(container, "traefik.frontend.rule"); err == nil {
|
if label, err := getLabel(container, "traefik.frontend.rule"); err == nil {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "Host"
|
return "Host:" + getEscapedName(container.Name) + "." + provider.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Docker) getBackend(container docker.Container) string {
|
func (provider *Docker) getBackend(container docker.Container) string {
|
||||||
if label, err := getLabel(container, "traefik.backend"); err == nil {
|
if label, err := getLabel(container, "traefik.backend"); err == nil {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return getEscapedName(container.Name)
|
return normalize(container.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Docker) getPort(container docker.Container) string {
|
func (provider *Docker) getPort(container docker.Container) string {
|
||||||
|
@ -211,7 +199,7 @@ func (provider *Docker) getWeight(container docker.Container) string {
|
||||||
if label, err := getLabel(container, "traefik.weight"); err == nil {
|
if label, err := getLabel(container, "traefik.weight"); err == nil {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "0"
|
return "1"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Docker) getDomain(container docker.Container) string {
|
func (provider *Docker) getDomain(container docker.Container) string {
|
||||||
|
|
|
@ -30,18 +30,18 @@ func TestDockerGetFrontendName(t *testing.T) {
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.rule": "Header",
|
"traefik.frontend.rule": "Headers:User-Agent,bat/0.1.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "Header-bar-docker-localhost",
|
expected: "Headers-User-Agent-bat-0-1-0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.value": "foo.bar",
|
"traefik.frontend.rule": "Host:foo.bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -52,24 +52,22 @@ func TestDockerGetFrontendName(t *testing.T) {
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.value": "foo.bar",
|
"traefik.frontend.rule": "Path:/test",
|
||||||
"traefik.frontend.rule": "Header",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "Header-foo-bar",
|
expected: "Path-test",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.value": "[foo.bar]",
|
"traefik.frontend.rule": "PathPrefix:/test2",
|
||||||
"traefik.frontend.rule": "Header",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "Header-foo-bar",
|
expected: "PathPrefix-test2",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +79,7 @@ func TestDockerGetFrontendName(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDockerGetFrontendValue(t *testing.T) {
|
func TestDockerGetFrontendRule(t *testing.T) {
|
||||||
provider := &Docker{
|
provider := &Docker{
|
||||||
Domain: "docker.localhost",
|
Domain: "docker.localhost",
|
||||||
}
|
}
|
||||||
|
@ -95,60 +93,36 @@ func TestDockerGetFrontendValue(t *testing.T) {
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Config: &docker.Config{},
|
Config: &docker.Config{},
|
||||||
},
|
},
|
||||||
expected: "foo.docker.localhost",
|
expected: "Host:foo.docker.localhost",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Config: &docker.Config{},
|
Config: &docker.Config{},
|
||||||
},
|
},
|
||||||
expected: "bar.docker.localhost",
|
expected: "Host:bar.docker.localhost",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.value": "foo.bar",
|
"traefik.frontend.rule": "Host:foo.bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "foo.bar",
|
expected: "Host:foo.bar",
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, e := range containers {
|
|
||||||
actual := provider.getFrontendValue(e.container)
|
|
||||||
if actual != e.expected {
|
|
||||||
t.Fatalf("expected %q, got %q", e.expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDockerGetFrontendRule(t *testing.T) {
|
|
||||||
provider := &Docker{}
|
|
||||||
|
|
||||||
containers := []struct {
|
|
||||||
container docker.Container
|
|
||||||
expected string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
container: docker.Container{
|
|
||||||
Name: "foo",
|
|
||||||
Config: &docker.Config{},
|
|
||||||
},
|
|
||||||
expected: "Host",
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
Name: "test",
|
Name: "test",
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.rule": "foo",
|
"traefik.frontend.rule": "Path:/test",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "foo",
|
expected: "Path:/test",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +255,7 @@ func TestDockerGetWeight(t *testing.T) {
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Config: &docker.Config{},
|
Config: &docker.Config{},
|
||||||
},
|
},
|
||||||
expected: "0",
|
expected: "1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
|
@ -535,7 +509,7 @@ func TestDockerTraefikFilter(t *testing.T) {
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.rule": "Host",
|
"traefik.frontend.rule": "Host:foo.bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NetworkSettings: &docker.NetworkSettings{
|
NetworkSettings: &docker.NetworkSettings{
|
||||||
|
@ -544,22 +518,7 @@ func TestDockerTraefikFilter(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: false,
|
expected: true,
|
||||||
},
|
|
||||||
{
|
|
||||||
container: docker.Container{
|
|
||||||
Config: &docker.Config{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"traefik.frontend.value": "foo.bar",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
NetworkSettings: &docker.NetworkSettings{
|
|
||||||
Ports: map[docker.Port][]docker.PortBinding{
|
|
||||||
"80/tcp": {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: false,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
|
@ -634,8 +593,7 @@ func TestDockerTraefikFilter(t *testing.T) {
|
||||||
container: docker.Container{
|
container: docker.Container{
|
||||||
Config: &docker.Config{
|
Config: &docker.Config{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.rule": "Host",
|
"traefik.frontend.rule": "Host:foo.bar",
|
||||||
"traefik.frontend.value": "foo.bar",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
NetworkSettings: &docker.NetworkSettings{
|
NetworkSettings: &docker.NetworkSettings{
|
||||||
|
@ -651,7 +609,7 @@ func TestDockerTraefikFilter(t *testing.T) {
|
||||||
for _, e := range containers {
|
for _, e := range containers {
|
||||||
actual := containerFilter(e.container)
|
actual := containerFilter(e.container)
|
||||||
if actual != e.expected {
|
if actual != e.expected {
|
||||||
t.Fatalf("expected %v, got %v", e.expected, actual)
|
t.Fatalf("expected %v for %+v, got %+v", e.expected, e, actual)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -690,8 +648,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
`"route-frontend-Host-test-docker-localhost"`: {
|
`"route-frontend-Host-test-docker-localhost"`: {
|
||||||
Rule: "Host",
|
Rule: "Host:test.docker.localhost",
|
||||||
Value: "test.docker.localhost",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -701,6 +658,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
Servers: map[string]types.Server{
|
Servers: map[string]types.Server{
|
||||||
"server-test": {
|
"server-test": {
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
Weight: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
|
@ -741,7 +699,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
"80/tcp": {},
|
"80/tcp": {},
|
||||||
},
|
},
|
||||||
Networks: map[string]docker.ContainerNetwork{
|
Networks: map[string]docker.ContainerNetwork{
|
||||||
"bridgde": {
|
"bridge": {
|
||||||
IPAddress: "127.0.0.1",
|
IPAddress: "127.0.0.1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -754,8 +712,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
EntryPoints: []string{"http", "https"},
|
EntryPoints: []string{"http", "https"},
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
`"route-frontend-Host-test1-docker-localhost"`: {
|
`"route-frontend-Host-test1-docker-localhost"`: {
|
||||||
Rule: "Host",
|
Rule: "Host:test1.docker.localhost",
|
||||||
Value: "test1.docker.localhost",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -764,8 +721,7 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
`"route-frontend-Host-test2-docker-localhost"`: {
|
`"route-frontend-Host-test2-docker-localhost"`: {
|
||||||
Rule: "Host",
|
Rule: "Host:test2.docker.localhost",
|
||||||
Value: "test2.docker.localhost",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -775,9 +731,11 @@ func TestDockerLoadDockerConfig(t *testing.T) {
|
||||||
Servers: map[string]types.Server{
|
Servers: map[string]types.Server{
|
||||||
"server-test1": {
|
"server-test1": {
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
Weight: 1,
|
||||||
},
|
},
|
||||||
"server-test2": {
|
"server-test2": {
|
||||||
URL: "http://127.0.0.1:80",
|
URL: "http://127.0.0.1:80",
|
||||||
|
Weight: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
CircuitBreaker: nil,
|
CircuitBreaker: nil,
|
||||||
|
|
|
@ -96,7 +96,6 @@ func (provider *Marathon) loadMarathonConfig() *types.Configuration {
|
||||||
"getProtocol": provider.getProtocol,
|
"getProtocol": provider.getProtocol,
|
||||||
"getPassHostHeader": provider.getPassHostHeader,
|
"getPassHostHeader": provider.getPassHostHeader,
|
||||||
"getEntryPoints": provider.getEntryPoints,
|
"getEntryPoints": provider.getEntryPoints,
|
||||||
"getFrontendValue": provider.getFrontendValue,
|
|
||||||
"getFrontendRule": provider.getFrontendRule,
|
"getFrontendRule": provider.getFrontendRule,
|
||||||
"getFrontendBackend": provider.getFrontendBackend,
|
"getFrontendBackend": provider.getFrontendBackend,
|
||||||
"replace": replace,
|
"replace": replace,
|
||||||
|
@ -309,22 +308,21 @@ func (provider *Marathon) getEntryPoints(application marathon.Application) []str
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getFrontendValue returns the frontend value for the specified application, using
|
|
||||||
// it's label. It returns a default one if the label is not present.
|
|
||||||
func (provider *Marathon) getFrontendValue(application marathon.Application) string {
|
|
||||||
if label, err := provider.getLabel(application, "traefik.frontend.value"); err == nil {
|
|
||||||
return label
|
|
||||||
}
|
|
||||||
return getEscapedName(application.ID) + "." + provider.Domain
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFrontendRule returns the frontend rule for the specified application, using
|
// getFrontendRule returns the frontend rule for the specified application, using
|
||||||
// it's label. It returns a default one (Host) if the label is not present.
|
// it's label. It returns a default one (Host) if the label is not present.
|
||||||
func (provider *Marathon) getFrontendRule(application marathon.Application) string {
|
func (provider *Marathon) getFrontendRule(application marathon.Application) string {
|
||||||
|
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
|
||||||
|
// TODO: backwards compatibility with DEPRECATED rule.Value
|
||||||
|
if value, err := provider.getLabel(application, "traefik.frontend.value"); err == nil {
|
||||||
|
log.Warnf("Label traefik.frontend.value=%s is DEPRECATED, please refer to the rule label: https://github.com/containous/traefik/blob/master/docs/index.md#marathon", value)
|
||||||
|
rule, _ := provider.getLabel(application, "traefik.frontend.rule")
|
||||||
|
return rule + ":" + value
|
||||||
|
}
|
||||||
|
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
|
||||||
if label, err := provider.getLabel(application, "traefik.frontend.rule"); err == nil {
|
if label, err := provider.getLabel(application, "traefik.frontend.rule"); err == nil {
|
||||||
return label
|
return label
|
||||||
}
|
}
|
||||||
return "Host"
|
return "Host:" + getEscapedName(application.ID) + "." + provider.Domain
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Marathon) getBackend(task marathon.Task, applications []marathon.Application) string {
|
func (provider *Marathon) getBackend(task marathon.Task, applications []marathon.Application) string {
|
||||||
|
|
|
@ -86,8 +86,7 @@ func TestMarathonLoadConfig(t *testing.T) {
|
||||||
EntryPoints: []string{},
|
EntryPoints: []string{},
|
||||||
Routes: map[string]types.Route{
|
Routes: map[string]types.Route{
|
||||||
`route-host-test`: {
|
`route-host-test`: {
|
||||||
Rule: "Host",
|
Rule: "Host:test.docker.localhost",
|
||||||
Value: "test.docker.localhost",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -831,7 +830,7 @@ func TestMarathonGetEntryPoints(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMarathonGetFrontendValue(t *testing.T) {
|
func TestMarathonGetFrontendRule(t *testing.T) {
|
||||||
provider := &Marathon{
|
provider := &Marathon{
|
||||||
Domain: "docker.localhost",
|
Domain: "docker.localhost",
|
||||||
}
|
}
|
||||||
|
@ -842,50 +841,21 @@ func TestMarathonGetFrontendValue(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
application: marathon.Application{},
|
application: marathon.Application{},
|
||||||
expected: ".docker.localhost",
|
expected: "Host:.docker.localhost",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
application: marathon.Application{
|
application: marathon.Application{
|
||||||
ID: "test",
|
ID: "test",
|
||||||
},
|
},
|
||||||
expected: "test.docker.localhost",
|
expected: "Host:test.docker.localhost",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
application: marathon.Application{
|
application: marathon.Application{
|
||||||
Labels: map[string]string{
|
Labels: map[string]string{
|
||||||
"traefik.frontend.value": "foo.bar",
|
"traefik.frontend.rule": "Host:foo.bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: "foo.bar",
|
expected: "Host:foo.bar",
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, a := range applications {
|
|
||||||
actual := provider.getFrontendValue(a.application)
|
|
||||||
if actual != a.expected {
|
|
||||||
t.Fatalf("expected %q, got %q", a.expected, actual)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMarathonGetFrontendRule(t *testing.T) {
|
|
||||||
provider := &Marathon{}
|
|
||||||
|
|
||||||
applications := []struct {
|
|
||||||
application marathon.Application
|
|
||||||
expected string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
application: marathon.Application{},
|
|
||||||
expected: "Host",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
application: marathon.Application{
|
|
||||||
Labels: map[string]string{
|
|
||||||
"traefik.frontend.rule": "Header",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: "Header",
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
"github.com/containous/traefik/autogen"
|
"github.com/containous/traefik/autogen"
|
||||||
"github.com/containous/traefik/types"
|
"github.com/containous/traefik/types"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Provider defines methods of a provider.
|
// Provider defines methods of a provider.
|
||||||
|
@ -67,3 +68,11 @@ func replace(s1 string, s2 string, s3 string) string {
|
||||||
func getEscapedName(name string) string {
|
func getEscapedName(name string) string {
|
||||||
return strings.Replace(strings.TrimPrefix(name, "/"), "/", "-", -1)
|
return strings.Replace(strings.TrimPrefix(name, "/"), "/", "-", -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func normalize(name string) string {
|
||||||
|
fargs := func(c rune) bool {
|
||||||
|
return !unicode.IsLetter(c) && !unicode.IsNumber(c)
|
||||||
|
}
|
||||||
|
// get function
|
||||||
|
return strings.Join(strings.FieldsFunc(name, fargs), "-")
|
||||||
|
}
|
||||||
|
|
92
rules.go
Normal file
92
rules.go
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Rules holds rule parsing and configuration
|
||||||
|
type Rules struct {
|
||||||
|
route *serverRoute
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rules) host(host string) *mux.Route {
|
||||||
|
return r.route.route.Host(host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rules) path(path string) *mux.Route {
|
||||||
|
return r.route.route.Path(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rules) pathPrefix(path string) *mux.Route {
|
||||||
|
return r.route.route.PathPrefix(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rules) pathStrip(path string) *mux.Route {
|
||||||
|
r.route.stripPrefix = path
|
||||||
|
return r.route.route.Path(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rules) pathPrefixStrip(path string) *mux.Route {
|
||||||
|
r.route.stripPrefix = path
|
||||||
|
return r.route.route.PathPrefix(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rules) methods(methods ...string) *mux.Route {
|
||||||
|
return r.route.route.Methods(methods...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rules) headers(headers ...string) *mux.Route {
|
||||||
|
return r.route.route.Headers(headers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Rules) headersRegexp(headers ...string) *mux.Route {
|
||||||
|
return r.route.route.HeadersRegexp(headers...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse parses rules expressions
|
||||||
|
func (r *Rules) Parse(expression string) (*mux.Route, error) {
|
||||||
|
functions := map[string]interface{}{
|
||||||
|
"Host": r.host,
|
||||||
|
"Path": r.path,
|
||||||
|
"PathStrip": r.pathStrip,
|
||||||
|
"PathPrefix": r.pathPrefix,
|
||||||
|
"PathPrefixStrip": r.pathPrefixStrip,
|
||||||
|
"Methods": r.methods,
|
||||||
|
"Headers": r.headers,
|
||||||
|
"HeadersRegexp": r.headersRegexp,
|
||||||
|
}
|
||||||
|
f := func(c rune) bool {
|
||||||
|
return c == ':' || c == '='
|
||||||
|
}
|
||||||
|
// get function
|
||||||
|
parsedFunctions := strings.FieldsFunc(expression, f)
|
||||||
|
if len(parsedFunctions) != 2 {
|
||||||
|
return nil, errors.New("Error parsing rule: " + expression)
|
||||||
|
}
|
||||||
|
parsedFunction, ok := functions[parsedFunctions[0]]
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("Error parsing rule: " + expression + ". Unknow function: " + parsedFunctions[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
fargs := func(c rune) bool {
|
||||||
|
return c == ',' || c == ';'
|
||||||
|
}
|
||||||
|
// get function
|
||||||
|
parsedArgs := strings.FieldsFunc(parsedFunctions[1], fargs)
|
||||||
|
if len(parsedArgs) == 0 {
|
||||||
|
return nil, errors.New("Error parsing args from rule: " + expression)
|
||||||
|
}
|
||||||
|
|
||||||
|
inputs := make([]reflect.Value, len(parsedArgs))
|
||||||
|
for i := range parsedArgs {
|
||||||
|
inputs[i] = reflect.ValueOf(parsedArgs[i])
|
||||||
|
}
|
||||||
|
method := reflect.ValueOf(parsedFunction)
|
||||||
|
if method.IsValid() {
|
||||||
|
return method.Call(inputs)[0].Interface().(*mux.Route), nil
|
||||||
|
}
|
||||||
|
return nil, errors.New("Method not found: " + parsedFunctions[0])
|
||||||
|
}
|
|
@ -21,20 +21,18 @@ git config --global user.email "emile@vauge.com"
|
||||||
git config --global user.name "Emile Vauge"
|
git config --global user.name "Emile Vauge"
|
||||||
git clone https://github.com/containous/traefik-library-image.git
|
git clone https://github.com/containous/traefik-library-image.git
|
||||||
cd traefik-library-image
|
cd traefik-library-image
|
||||||
git remote rm origin
|
|
||||||
git remote add origin https://emilevauge:${GITHUB_TOKEN}@github.com/containous/traefik-library-image.git
|
|
||||||
./update.sh $VERSION
|
./update.sh $VERSION
|
||||||
git add -A
|
git add -A
|
||||||
echo $VERSION | git commit --file -
|
echo $VERSION | git commit --file -
|
||||||
echo $VERSION | git tag -a $VERSION --file -
|
echo $VERSION | git tag -a $VERSION --file -
|
||||||
git push --follow-tags -u origin master
|
git push -q --follow-tags https://emilevauge:${GITHUB_TOKEN}@github.com/containous/traefik-library-image.git
|
||||||
|
|
||||||
# create docker image emilevauge/traefik (compatibility)
|
# create docker image emilevauge/traefik (compatibility)
|
||||||
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
docker login -e $DOCKER_EMAIL -u $DOCKER_USER -p $DOCKER_PASS
|
||||||
docker tag containous/traefik emilevauge/traefik:latest
|
docker tag containous/traefik emilevauge/traefik:latest
|
||||||
docker push emilevauge/traefik:latest
|
docker push emilevauge/traefik:latest
|
||||||
docker tag emilevauge/traefik:latest emilevauge/traefik:${VERSION}
|
docker tag emilevauge/traefik:latest emilevauge/traefik:${VERSION}
|
||||||
docker push emilevauge/traefik:${VERSION}
|
docker push -q emilevauge/traefik:${VERSION}
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
rm -Rf traefik-library-image/
|
rm -Rf traefik-library-image/
|
||||||
|
|
77
server.go
77
server.go
|
@ -55,6 +55,11 @@ type serverEntryPoint struct {
|
||||||
httpRouter *middlewares.HandlerSwitcher
|
httpRouter *middlewares.HandlerSwitcher
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type serverRoute struct {
|
||||||
|
route *mux.Route
|
||||||
|
stripPrefix string
|
||||||
|
}
|
||||||
|
|
||||||
// NewServer returns an initialized Server.
|
// NewServer returns an initialized Server.
|
||||||
func NewServer(globalConfiguration GlobalConfiguration) *Server {
|
func NewServer(globalConfiguration GlobalConfiguration) *Server {
|
||||||
server := new(Server)
|
server := new(Server)
|
||||||
|
@ -354,23 +359,22 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
if _, ok := serverEntryPoints[entryPointName]; !ok {
|
if _, ok := serverEntryPoints[entryPointName]; !ok {
|
||||||
return nil, errors.New("Undefined entrypoint: " + entryPointName)
|
return nil, errors.New("Undefined entrypoint: " + entryPointName)
|
||||||
}
|
}
|
||||||
newRoute := serverEntryPoints[entryPointName].httpRouter.GetHandler().NewRoute().Name(frontendName)
|
newServerRoute := &serverRoute{route: serverEntryPoints[entryPointName].httpRouter.GetHandler().NewRoute().Name(frontendName)}
|
||||||
for routeName, route := range frontend.Routes {
|
for routeName, route := range frontend.Routes {
|
||||||
log.Debugf("Creating route %s %s:%s", routeName, route.Rule, route.Value)
|
err := getRoute(newServerRoute, &route)
|
||||||
route, err := getRoute(newRoute, route.Rule, route.Value)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
newRoute = route
|
log.Debugf("Creating route %s %s", routeName, route.Rule)
|
||||||
}
|
}
|
||||||
entryPoint := globalConfiguration.EntryPoints[entryPointName]
|
entryPoint := globalConfiguration.EntryPoints[entryPointName]
|
||||||
if entryPoint.Redirect != nil {
|
if entryPoint.Redirect != nil {
|
||||||
if redirectHandlers[entryPointName] != nil {
|
if redirectHandlers[entryPointName] != nil {
|
||||||
newRoute.Handler(redirectHandlers[entryPointName])
|
newServerRoute.route.Handler(redirectHandlers[entryPointName])
|
||||||
} else if handler, err := server.loadEntryPointConfig(entryPointName, entryPoint); err != nil {
|
} else if handler, err := server.loadEntryPointConfig(entryPointName, entryPoint); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else {
|
} else {
|
||||||
newRoute.Handler(handler)
|
newServerRoute.route.Handler(handler)
|
||||||
redirectHandlers[entryPointName] = handler
|
redirectHandlers[entryPointName] = handler
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -448,9 +452,9 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Reusing backend %s", frontend.Backend)
|
log.Debugf("Reusing backend %s", frontend.Backend)
|
||||||
}
|
}
|
||||||
server.wireFrontendBackend(frontend.Routes, newRoute, backends[frontend.Backend])
|
server.wireFrontendBackend(newServerRoute, backends[frontend.Backend])
|
||||||
}
|
}
|
||||||
err := newRoute.GetError()
|
err := newServerRoute.route.GetError()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error building route: %s", err)
|
log.Errorf("Error building route: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -460,29 +464,15 @@ func (server *Server) loadConfig(configurations configs, globalConfiguration Glo
|
||||||
return serverEntryPoints, nil
|
return serverEntryPoints, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (server *Server) wireFrontendBackend(routes map[string]types.Route, newRoute *mux.Route, handler http.Handler) {
|
func (server *Server) wireFrontendBackend(serverRoute *serverRoute, handler http.Handler) {
|
||||||
// strip prefix
|
// strip prefix
|
||||||
var strip bool
|
if len(serverRoute.stripPrefix) > 0 {
|
||||||
for _, route := range routes {
|
serverRoute.route.Handler(&middlewares.StripPrefix{
|
||||||
switch route.Rule {
|
Prefix: serverRoute.stripPrefix,
|
||||||
case "PathStrip":
|
|
||||||
newRoute.Handler(&middlewares.StripPrefix{
|
|
||||||
Prefix: route.Value,
|
|
||||||
Handler: handler,
|
Handler: handler,
|
||||||
})
|
})
|
||||||
strip = true
|
} else {
|
||||||
break
|
serverRoute.route.Handler(handler)
|
||||||
case "PathPrefixStrip":
|
|
||||||
newRoute.Handler(&middlewares.StripPrefix{
|
|
||||||
Prefix: route.Value,
|
|
||||||
Handler: handler,
|
|
||||||
})
|
|
||||||
strip = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !strip {
|
|
||||||
newRoute.Handler(handler)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,32 +512,29 @@ func (server *Server) buildDefaultHTTPRouter() *mux.Router {
|
||||||
return router
|
return router
|
||||||
}
|
}
|
||||||
|
|
||||||
func getRoute(any interface{}, rule string, value ...interface{}) (*mux.Route, error) {
|
func getRoute(serverRoute *serverRoute, route *types.Route) error {
|
||||||
switch rule {
|
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
|
||||||
case "PathStrip":
|
// TODO: backwards compatibility with DEPRECATED rule.Value
|
||||||
rule = "Path"
|
if len(route.Value) > 0 {
|
||||||
case "PathPrefixStrip":
|
route.Rule += ":" + route.Value
|
||||||
rule = "PathPrefix"
|
log.Warnf("Value %s is DEPRECATED (will be removed in v1.0.0), please refer to the new frontend notation: https://github.com/containous/traefik/blob/master/docs/index.md#-frontends", route.Value)
|
||||||
}
|
}
|
||||||
inputs := make([]reflect.Value, len(value))
|
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
|
||||||
for i := range value {
|
|
||||||
inputs[i] = reflect.ValueOf(value[i])
|
rules := Rules{route: serverRoute}
|
||||||
|
newRoute, err := rules.Parse(route.Rule)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
method := reflect.ValueOf(any).MethodByName(rule)
|
serverRoute.route = newRoute
|
||||||
if method.IsValid() {
|
return nil
|
||||||
return method.Call(inputs)[0].Interface().(*mux.Route), nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("Method not found: " + rule)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortedFrontendNamesForConfig(configuration *types.Configuration) []string {
|
func sortedFrontendNamesForConfig(configuration *types.Configuration) []string {
|
||||||
keys := []string{}
|
keys := []string{}
|
||||||
|
|
||||||
for key := range configuration.Frontends {
|
for key := range configuration.Frontends {
|
||||||
keys = append(keys, key)
|
keys = append(keys, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,5 @@
|
||||||
backend = "backend-{{.}}"
|
backend = "backend-{{.}}"
|
||||||
passHostHeader = false
|
passHostHeader = false
|
||||||
[frontends.frontend-{{.}}.routes.route-host-{{.}}]
|
[frontends.frontend-{{.}}.routes.route-host-{{.}}]
|
||||||
rule = "Host"
|
rule = "{{getFrontendValue .}}"
|
||||||
value = "{{getFrontendValue .}}"
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -13,5 +13,4 @@
|
||||||
{{end}}]
|
{{end}}]
|
||||||
[frontends."frontend-{{$frontend}}".routes."route-frontend-{{$frontend}}"]
|
[frontends."frontend-{{$frontend}}".routes."route-frontend-{{$frontend}}"]
|
||||||
rule = "{{getFrontendRule $container}}"
|
rule = "{{getFrontendRule $container}}"
|
||||||
value = "{{getFrontendValue $container}}"
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -37,6 +37,5 @@
|
||||||
{{range $routes}}
|
{{range $routes}}
|
||||||
[frontends.{{$frontend}}.routes.{{Last .}}]
|
[frontends.{{$frontend}}.routes.{{Last .}}]
|
||||||
rule = "{{Get "" . "/rule"}}"
|
rule = "{{Get "" . "/rule"}}"
|
||||||
value = "{{Get "" . "/value"}}"
|
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -14,5 +14,4 @@
|
||||||
{{end}}]
|
{{end}}]
|
||||||
[frontends.frontend{{.ID | replace "/" "-"}}.routes.route-host{{.ID | replace "/" "-"}}]
|
[frontends.frontend{{.ID | replace "/" "-"}}.routes.route-host{{.ID | replace "/" "-"}}]
|
||||||
rule = "{{getFrontendRule .}}"
|
rule = "{{getFrontendRule .}}"
|
||||||
value = "{{getFrontendValue .}}"
|
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
],
|
],
|
||||||
"labels": {
|
"labels": {
|
||||||
"traefik.weight": "1",
|
"traefik.weight": "1",
|
||||||
"traefik.protocole": "http"
|
"traefik.protocole": "http",
|
||||||
|
"traefik.frontend.rule" : "Headers:Host,test.localhost"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -513,17 +513,14 @@
|
||||||
# [frontends.frontend1]
|
# [frontends.frontend1]
|
||||||
# backend = "backend2"
|
# backend = "backend2"
|
||||||
# [frontends.frontend1.routes.test_1]
|
# [frontends.frontend1.routes.test_1]
|
||||||
# rule = "Host"
|
# rule = "Host:test.localhost"
|
||||||
# value = "test.localhost"
|
|
||||||
# [frontends.frontend2]
|
# [frontends.frontend2]
|
||||||
# backend = "backend1"
|
# backend = "backend1"
|
||||||
# passHostHeader = true
|
# passHostHeader = true
|
||||||
# entrypoints = ["https"] # overrides defaultEntryPoints
|
# entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
# [frontends.frontend2.routes.test_1]
|
# [frontends.frontend2.routes.test_1]
|
||||||
# rule = "Host"
|
# rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||||
# value = "{subdomain:[a-z]+}.localhost"
|
|
||||||
# [frontends.frontend3]
|
# [frontends.frontend3]
|
||||||
# entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
# entrypoints = ["http", "https"] # overrides defaultEntryPoints
|
||||||
# backend = "backend2"
|
# backend = "backend2"
|
||||||
# rule = "Path"
|
# rule = "Path:/test"
|
||||||
# value = "/test"
|
|
|
@ -31,7 +31,10 @@ type Server struct {
|
||||||
// Route holds route configuration.
|
// Route holds route configuration.
|
||||||
type Route struct {
|
type Route struct {
|
||||||
Rule string `json:"rule,omitempty"`
|
Rule string `json:"rule,omitempty"`
|
||||||
|
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
|
||||||
|
// TODO: backwards compatibility with DEPRECATED rule.Value
|
||||||
Value string `json:"value,omitempty"`
|
Value string `json:"value,omitempty"`
|
||||||
|
// ⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frontend holds frontend configuration.
|
// Frontend holds frontend configuration.
|
||||||
|
|
|
@ -7,12 +7,10 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td><em>Route</em></td>
|
<td><em>Route</em></td>
|
||||||
<td><em>Rule</em></td>
|
<td><em>Rule</em></td>
|
||||||
<td><em>Value</em></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-ng-repeat="(routeId, route) in frontendCtrl.frontend.routes">
|
<tr data-ng-repeat="(routeId, route) in frontendCtrl.frontend.routes">
|
||||||
<td>{{routeId}}</td>
|
<td>{{routeId}}</td>
|
||||||
<td>{{route.rule}}</td>
|
<td><code>{{route.rule}}</code></td>
|
||||||
<td><code>{{route.value}}</code></td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<nav class="navbar navbar-default">
|
<nav class="navbar navbar-default">
|
||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<a class="navbar-brand traefik-text" ui-sref="provider"><img src="traefik.icon.png"/></a>
|
<a class="navbar-brand traefik-text" ui-sref="provider"><img height="16" src="traefik.icon.png"/></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="collapse navbar-collapse">
|
<div class="collapse navbar-collapse">
|
||||||
|
|
Loading…
Reference in a new issue