Merge pull request #20 from EmileVauge/configuration-enhancements
Configuration on cicuitbreakers and load balancers
This commit is contained in:
commit
62ee9b3c0d
9 changed files with 222 additions and 66 deletions
|
@ -1,5 +1,10 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type GlobalConfiguration struct {
|
type GlobalConfiguration struct {
|
||||||
Port string
|
Port string
|
||||||
GraceTimeOut int64
|
GraceTimeOut int64
|
||||||
|
@ -28,6 +33,16 @@ func NewGlobalConfiguration() *GlobalConfiguration {
|
||||||
|
|
||||||
type Backend struct {
|
type Backend struct {
|
||||||
Servers map[string]Server
|
Servers map[string]Server
|
||||||
|
CircuitBreaker *CircuitBreaker
|
||||||
|
LoadBalancer *LoadBalancer
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoadBalancer struct {
|
||||||
|
Method string
|
||||||
|
}
|
||||||
|
|
||||||
|
type CircuitBreaker struct {
|
||||||
|
Expression string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
@ -46,6 +61,34 @@ type Frontend struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Configuration struct {
|
type Configuration struct {
|
||||||
Backends map[string]Backend
|
Backends map[string]*Backend
|
||||||
Frontends map[string]Frontend
|
Frontends map[string]*Frontend
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load Balancer Method
|
||||||
|
type LoadBalancerMethod uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// wrr (default) = Weighted Round Robin
|
||||||
|
wrr LoadBalancerMethod = iota
|
||||||
|
// drr = Dynamic Round Robin
|
||||||
|
drr
|
||||||
|
)
|
||||||
|
|
||||||
|
var loadBalancerMethodNames = []string{
|
||||||
|
"wrr",
|
||||||
|
"drr",
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLoadBalancerMethod(loadBalancer *LoadBalancer) (LoadBalancerMethod, error) {
|
||||||
|
if loadBalancer != nil {
|
||||||
|
for i, name := range loadBalancerMethodNames {
|
||||||
|
if strings.EqualFold(name, loadBalancer.Method) {
|
||||||
|
return LoadBalancerMethod(i), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wrr, ErrInvalidLoadBalancerMethod
|
||||||
|
}
|
||||||
|
|
||||||
|
var ErrInvalidLoadBalancerMethod = errors.New("Invalid method, using default")
|
||||||
|
|
22
consul.go
22
consul.go
|
@ -48,6 +48,8 @@ var ConsulFuncMap = template.FuncMap{
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error getting key ", joinedKeys, err)
|
log.Error("Error getting key ", joinedKeys, err)
|
||||||
return ""
|
return ""
|
||||||
|
} else if keyPair == nil {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return string(keyPair.Value)
|
return string(keyPair.Value)
|
||||||
},
|
},
|
||||||
|
@ -75,11 +77,13 @@ func (provider *ConsulProvider) Provide(configurationChan chan<- *Configuration)
|
||||||
consulClient, _ := api.NewClient(config)
|
consulClient, _ := api.NewClient(config)
|
||||||
provider.consulClient = consulClient
|
provider.consulClient = consulClient
|
||||||
if provider.Watch {
|
if provider.Watch {
|
||||||
var waitIndex uint64
|
|
||||||
keypairs, meta, err := consulClient.KV().Keys("", "", nil)
|
keypairs, meta, err := consulClient.KV().Keys("", "", nil)
|
||||||
if keypairs == nil && err == nil {
|
if keypairs == nil {
|
||||||
log.Error("Key was not found.")
|
log.Error("Key was not found")
|
||||||
}
|
} else if err != nil {
|
||||||
|
log.Error("Error connecting to consul %s", err)
|
||||||
|
} else {
|
||||||
|
var waitIndex uint64
|
||||||
waitIndex = meta.LastIndex
|
waitIndex = meta.LastIndex
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -87,17 +91,21 @@ func (provider *ConsulProvider) Provide(configurationChan chan<- *Configuration)
|
||||||
WaitIndex: waitIndex,
|
WaitIndex: waitIndex,
|
||||||
}
|
}
|
||||||
keypairs, meta, err := consulClient.KV().Keys("", "", &opts)
|
keypairs, meta, err := consulClient.KV().Keys("", "", &opts)
|
||||||
if keypairs == nil && err == nil {
|
if keypairs == nil {
|
||||||
log.Error("Key was not found.")
|
log.Error("Key was not found")
|
||||||
}
|
} else if err != nil {
|
||||||
|
log.Error("Error connecting to consul %s", err)
|
||||||
|
} else {
|
||||||
waitIndex = meta.LastIndex
|
waitIndex = meta.LastIndex
|
||||||
configuration := provider.loadConsulConfig()
|
configuration := provider.loadConsulConfig()
|
||||||
if configuration != nil {
|
if configuration != nil {
|
||||||
configurationChan <- configuration
|
configurationChan <- configuration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
configuration := provider.loadConsulConfig()
|
configuration := provider.loadConsulConfig()
|
||||||
configurationChan <- configuration
|
configurationChan <- configuration
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,12 +39,21 @@ Frontends can be defined using the following rules:
|
||||||
### HTTP Backends
|
### HTTP Backends
|
||||||
|
|
||||||
A backend is responsible to load-balance the traffic coming from one or more frontends to a set of http servers.
|
A backend is responsible to load-balance the traffic coming from one or more frontends to a set of http servers.
|
||||||
Various types of load-balancing is supported:
|
Various methods of load-balancing is supported:
|
||||||
|
|
||||||
* Weighted round robin
|
* ```wrr```: Weighted Round Robin
|
||||||
* Rebalancer: increases weights on servers that perform better than others. It also rolls back to original weights if the servers have changed.
|
* ```drr```: Dynamic Round Robin: increases weights on servers that perform better than others. It also rolls back to original weights if the servers have changed.
|
||||||
|
|
||||||
A circuit breaker can also be applied to a backend, preventing high loads on failing servers.
|
A circuit breaker can also be applied to a backend, preventing high loads on failing servers.
|
||||||
|
It can be configured using:
|
||||||
|
|
||||||
|
* Methods: ```LatencyAtQuantileMS```, ```NetworkErrorRatio```, ```ResponseCodeRatio```
|
||||||
|
* Operators: ```AND```, ```OR```, ```EQ```, ```NEQ```, ```LT```, ```LE```, ```GT```, ```GE```
|
||||||
|
|
||||||
|
For example:
|
||||||
|
* ```NetworkErrorRatio() > 0.5```
|
||||||
|
* ```LatencyAtQuantileMS(50.0) > 50```
|
||||||
|
* ```ResponseCodeRatio(500, 600, 0, 600) > 0.5```
|
||||||
|
|
||||||
## <a id="global"></a> Global configuration
|
## <a id="global"></a> Global configuration
|
||||||
|
|
||||||
|
@ -115,6 +124,8 @@ logLevel = "DEBUG"
|
||||||
# rules
|
# rules
|
||||||
[backends]
|
[backends]
|
||||||
[backends.backend1]
|
[backends.backend1]
|
||||||
|
[backends.backend1.circuitbreaker]
|
||||||
|
expression = "NetworkErrorRatio() > 0.5"
|
||||||
[backends.backend1.servers.server1]
|
[backends.backend1.servers.server1]
|
||||||
url = "http://172.17.0.2:80"
|
url = "http://172.17.0.2:80"
|
||||||
weight = 10
|
weight = 10
|
||||||
|
@ -122,11 +133,16 @@ logLevel = "DEBUG"
|
||||||
url = "http://172.17.0.3:80"
|
url = "http://172.17.0.3:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
[backends.backend2]
|
[backends.backend2]
|
||||||
|
[backends.backend2.LoadBalancer]
|
||||||
|
method = "drr"
|
||||||
[backends.backend2.servers.server1]
|
[backends.backend2.servers.server1]
|
||||||
url = "http://172.17.0.4:80"
|
url = "http://172.17.0.4:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
[backends.backend2.servers.server2]
|
||||||
|
url = "http://172.17.0.5:80"
|
||||||
|
weight = 2
|
||||||
|
|
||||||
[frontends]
|
[frontends]
|
||||||
[frontends.frontend1]
|
[frontends.frontend1]
|
||||||
backend = "backend2"
|
backend = "backend2"
|
||||||
[frontends.frontend1.routes.test_1]
|
[frontends.frontend1.routes.test_1]
|
||||||
|
@ -138,6 +154,7 @@ logLevel = "DEBUG"
|
||||||
rule = "Path"
|
rule = "Path"
|
||||||
value = "/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```:
|
||||||
|
@ -156,6 +173,8 @@ filename = "rules.toml"
|
||||||
# rules.toml
|
# rules.toml
|
||||||
[backends]
|
[backends]
|
||||||
[backends.backend1]
|
[backends.backend1]
|
||||||
|
[backends.backend1.circuitbreaker]
|
||||||
|
expression = "NetworkErrorRatio() > 0.5"
|
||||||
[backends.backend1.servers.server1]
|
[backends.backend1.servers.server1]
|
||||||
url = "http://172.17.0.2:80"
|
url = "http://172.17.0.2:80"
|
||||||
weight = 10
|
weight = 10
|
||||||
|
@ -163,9 +182,14 @@ filename = "rules.toml"
|
||||||
url = "http://172.17.0.3:80"
|
url = "http://172.17.0.3:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
[backends.backend2]
|
[backends.backend2]
|
||||||
|
[backends.backend2.LoadBalancer]
|
||||||
|
method = "drr"
|
||||||
[backends.backend2.servers.server1]
|
[backends.backend2.servers.server1]
|
||||||
url = "http://172.17.0.4:80"
|
url = "http://172.17.0.4:80"
|
||||||
weight = 1
|
weight = 1
|
||||||
|
[backends.backend2.servers.server2]
|
||||||
|
url = "http://172.17.0.5:80"
|
||||||
|
weight = 2
|
||||||
|
|
||||||
[frontends]
|
[frontends]
|
||||||
[frontends.frontend1]
|
[frontends.frontend1]
|
||||||
|
@ -178,6 +202,7 @@ filename = "rules.toml"
|
||||||
[frontends.frontend2.routes.test_2]
|
[frontends.frontend2.routes.test_2]
|
||||||
rule = "Path"
|
rule = "Path"
|
||||||
value = "/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:
|
||||||
|
|
|
@ -13,8 +13,8 @@ type CircuitBreaker struct {
|
||||||
circuitBreaker *cbreaker.CircuitBreaker
|
circuitBreaker *cbreaker.CircuitBreaker
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCircuitBreaker(next http.Handler, options ...cbreaker.CircuitBreakerOption) *CircuitBreaker {
|
func NewCircuitBreaker(next http.Handler, expression string, options ...cbreaker.CircuitBreakerOption) *CircuitBreaker {
|
||||||
circuitBreaker, _ := cbreaker.New(next, "NetworkErrorRatio() > 0.5", options...)
|
circuitBreaker, _ := cbreaker.New(next, expression, options...)
|
||||||
return &CircuitBreaker{circuitBreaker}
|
return &CircuitBreaker{circuitBreaker}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,19 @@
|
||||||
{{range $backends}}
|
{{range $backends}}
|
||||||
{{$backend := .}}
|
{{$backend := .}}
|
||||||
{{$servers := "servers/" | List $backend }}
|
{{$servers := "servers/" | List $backend }}
|
||||||
|
|
||||||
|
{{$circuitBreaker := Get . "circuitbreaker/" "expression"}}
|
||||||
|
{{with $circuitBreaker}}
|
||||||
|
[backends.{{Last $backend}}.circuitBreaker]
|
||||||
|
expression = "{{$circuitBreaker}}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{$loadBalancer := Get . "loadbalancer/" "method"}}
|
||||||
|
{{with $loadBalancer}}
|
||||||
|
[backends.{{Last $backend}}.loadBalancer]
|
||||||
|
method = "{{$loadBalancer}}"
|
||||||
|
{{end}}
|
||||||
|
|
||||||
{{range $servers}}
|
{{range $servers}}
|
||||||
[backends.{{Last $backend}}.servers.{{Last .}}]
|
[backends.{{Last $backend}}.servers.{{Last .}}]
|
||||||
url = "{{Get . "/url"}}"
|
url = "{{Get . "/url"}}"
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-heading">{{$keyFrontends}}</div>
|
<div class="panel-heading">{{$keyFrontends}}</div>
|
||||||
<div class="panel-body">
|
<div class="panel-body">
|
||||||
<!--<button type="button" class="btn btn-info">{{$valueFrontends.Backend}}</button>-->
|
|
||||||
<a class="btn btn-info" role="button" data-toggle="collapse" href="#{{$valueFrontends.Backend}}" aria-expanded="false">
|
<a class="btn btn-info" role="button" data-toggle="collapse" href="#{{$valueFrontends.Backend}}" aria-expanded="false">
|
||||||
{{$valueFrontends.Backend}}
|
{{$valueFrontends.Backend}}
|
||||||
</a>
|
</a>
|
||||||
|
@ -60,6 +59,18 @@
|
||||||
{{range $keyBackends, $valueBackends := .Configuration.Backends}}
|
{{range $keyBackends, $valueBackends := .Configuration.Backends}}
|
||||||
<div class="panel panel-primary" id="{{$keyBackends}}">
|
<div class="panel panel-primary" id="{{$keyBackends}}">
|
||||||
<div class="panel-heading">{{$keyBackends}}</div>
|
<div class="panel-heading">{{$keyBackends}}</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
{{with $valueBackends.LoadBalancer}}
|
||||||
|
<a class="btn btn-info" role="button">
|
||||||
|
Load Balancer: {{.Method}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
{{with $valueBackends.CircuitBreaker}}
|
||||||
|
<a class="btn btn-info" role="button">
|
||||||
|
Circuit Breaker: {{.Expression}}
|
||||||
|
</a>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
<table class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
<tr>
|
<tr>
|
||||||
<td><em>Server</em></td>
|
<td><em>Server</em></td>
|
||||||
|
|
25
tests/consul-config.sh
Executable file
25
tests/consul-config.sh
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# backend 1
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "NetworkErrorRatio() > 0.5" http://localhost:8500/v1/kv/backends/backend1/circuitbreaker/expression
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "http://172.17.0.2:80" http://localhost:8500/v1/kv/backends/backend1/servers/server1/url
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "10" http://localhost:8500/v1/kv/backends/backend1/servers/server1/weight
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "http://172.17.0.3:80" http://localhost:8500/v1/kv/backends/backend1/servers/server2/url
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "1" http://localhost:8500/v1/kv/backends/backend1/servers/server2/weight
|
||||||
|
|
||||||
|
# backend 2
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "drr" http://localhost:8500/v1/kv/backends/backend2/loadbalancer/method
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "http://172.17.0.4:80" http://localhost:8500/v1/kv/backends/backend2/servers/server1/url
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "1" http://localhost:8500/v1/kv/backends/backend2/servers/server1/weight
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "http://172.17.0.5:80" http://localhost:8500/v1/kv/backends/backend2/servers/server2/url
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "2" http://localhost:8500/v1/kv/backends/backend2/servers/server2/weight
|
||||||
|
|
||||||
|
# frontend 1
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "backend2" http://localhost:8500/v1/kv/frontends/frontend1/backend
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "Host" http://localhost:8500/v1/kv/frontends/frontend1/routes/test_1/rule
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "test.localhost" http://localhost:8500/v1/kv/frontends/frontend1/routes/test_1/value
|
||||||
|
|
||||||
|
# frontend 2
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "backend1" http://localhost:8500/v1/kv/frontends/frontend2/backend
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "Path" http://localhost:8500/v1/kv/frontends/frontend2/routes/test_2/rule
|
||||||
|
curl -i -H "Accept: application/json" -X PUT -d "/test" http://localhost:8500/v1/kv/frontends/frontend2/routes/test_2/value
|
43
traefik.go
43
traefik.go
|
@ -225,27 +225,54 @@ func LoadConfig(configuration *Configuration, globalConfiguration *GlobalConfigu
|
||||||
}
|
}
|
||||||
if backends[frontend.Backend] == nil {
|
if backends[frontend.Backend] == nil {
|
||||||
log.Debugf("Creating backend %s", frontend.Backend)
|
log.Debugf("Creating backend %s", frontend.Backend)
|
||||||
lb, _ := roundrobin.New(fwd)
|
var lb http.Handler
|
||||||
rb, _ := roundrobin.NewRebalancer(lb, roundrobin.RebalancerLogger(oxyLogger))
|
rr, _ := roundrobin.New(fwd)
|
||||||
|
lbMethod, err := NewLoadBalancerMethod(configuration.Backends[frontend.Backend].LoadBalancer)
|
||||||
|
if err != nil {
|
||||||
|
configuration.Backends[frontend.Backend].LoadBalancer = &LoadBalancer{Method: "wrr"}
|
||||||
|
}
|
||||||
|
switch lbMethod {
|
||||||
|
case drr:
|
||||||
|
log.Debugf("Creating load-balancer drr")
|
||||||
|
rebalancer, _ := roundrobin.NewRebalancer(rr, roundrobin.RebalancerLogger(oxyLogger))
|
||||||
|
lb = rebalancer
|
||||||
for serverName, server := range configuration.Backends[frontend.Backend].Servers {
|
for serverName, server := range configuration.Backends[frontend.Backend].Servers {
|
||||||
url, err := url.Parse(server.URL)
|
url, err := url.Parse(server.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
log.Debugf("Creating server %s %s", serverName, url.String())
|
log.Debugf("Creating server %s %s", serverName, url.String())
|
||||||
rb.UpsertServer(url, roundrobin.Weight(server.Weight))
|
rebalancer.UpsertServer(url, roundrobin.Weight(server.Weight))
|
||||||
}
|
}
|
||||||
backends[frontend.Backend] = rb
|
case wrr:
|
||||||
|
log.Debugf("Creating load-balancer wrr")
|
||||||
|
lb = rr
|
||||||
|
for serverName, server := range configuration.Backends[frontend.Backend].Servers {
|
||||||
|
url, err := url.Parse(server.URL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
log.Debugf("Creating server %s %s", serverName, url.String())
|
||||||
|
rr.UpsertServer(url, roundrobin.Weight(server.Weight))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var negroni = negroni.New()
|
||||||
|
if configuration.Backends[frontend.Backend].CircuitBreaker != nil {
|
||||||
|
log.Debugf("Creating circuit breaker %s", configuration.Backends[frontend.Backend].CircuitBreaker.Expression)
|
||||||
|
negroni.Use(middlewares.NewCircuitBreaker(lb, configuration.Backends[frontend.Backend].CircuitBreaker.Expression, cbreaker.Logger(oxyLogger)))
|
||||||
|
} else {
|
||||||
|
negroni.UseHandler(lb)
|
||||||
|
}
|
||||||
|
backends[frontend.Backend] = negroni
|
||||||
} else {
|
} else {
|
||||||
log.Debugf("Reusing backend %s", frontend.Backend)
|
log.Debugf("Reusing backend %s", frontend.Backend)
|
||||||
}
|
}
|
||||||
// stream.New(backends[frontend.Backend], stream.Retry("IsNetworkError() && Attempts() <= " + strconv.Itoa(globalConfiguration.Replay)), stream.Logger(oxyLogger))
|
// stream.New(backends[frontend.Backend], stream.Retry("IsNetworkError() && Attempts() <= " + strconv.Itoa(globalConfiguration.Replay)), stream.Logger(oxyLogger))
|
||||||
var negroni = negroni.New()
|
|
||||||
negroni.Use(middlewares.NewCircuitBreaker(backends[frontend.Backend], cbreaker.Logger(oxyLogger)))
|
newRoute.Handler(backends[frontend.Backend])
|
||||||
newRoute.Handler(negroni)
|
|
||||||
err := newRoute.GetError()
|
err := newRoute.GetError()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Error building route ", err)
|
log.Error("Error building route: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return router, nil
|
return router, nil
|
||||||
|
|
|
@ -187,7 +187,7 @@
|
||||||
#
|
#
|
||||||
# Required
|
# Required
|
||||||
#
|
#
|
||||||
# endpoint = "http://127.0.0.1:8500"
|
# endpoint = "127.0.0.1:8500"
|
||||||
|
|
||||||
# Enable watch Consul changes
|
# Enable watch Consul changes
|
||||||
#
|
#
|
||||||
|
@ -214,6 +214,8 @@
|
||||||
################################################################
|
################################################################
|
||||||
# [backends]
|
# [backends]
|
||||||
# [backends.backend1]
|
# [backends.backend1]
|
||||||
|
# [backends.backend1.circuitbreaker]
|
||||||
|
# expression = "NetworkErrorRatio() > 0.5"
|
||||||
# [backends.backend1.servers.server1]
|
# [backends.backend1.servers.server1]
|
||||||
# url = "http://172.17.0.2:80"
|
# url = "http://172.17.0.2:80"
|
||||||
# weight = 10
|
# weight = 10
|
||||||
|
@ -221,6 +223,8 @@
|
||||||
# url = "http://172.17.0.3:80"
|
# url = "http://172.17.0.3:80"
|
||||||
# weight = 1
|
# weight = 1
|
||||||
# [backends.backend2]
|
# [backends.backend2]
|
||||||
|
# [backends.backend2.LoadBalancer]
|
||||||
|
# method = "drr"
|
||||||
# [backends.backend2.servers.server1]
|
# [backends.backend2.servers.server1]
|
||||||
# url = "http://172.17.0.4:80"
|
# url = "http://172.17.0.4:80"
|
||||||
# weight = 1
|
# weight = 1
|
||||||
|
|
Loading…
Reference in a new issue