Adds weight on ServersLoadBalancer
This commit is contained in:
parent
f4f3dbe1f5
commit
3174c69c66
12 changed files with 187 additions and 2 deletions
|
@ -178,6 +178,7 @@
|
|||
- "traefik.http.services.service02.loadbalancer.sticky.cookie.secure=true"
|
||||
- "traefik.http.services.service02.loadbalancer.server.port=foobar"
|
||||
- "traefik.http.services.service02.loadbalancer.server.scheme=foobar"
|
||||
- "traefik.http.services.service02.loadbalancer.server.weight=42"
|
||||
- "traefik.tcp.middlewares.tcpmiddleware01.ipallowlist.sourcerange=foobar, foobar"
|
||||
- "traefik.tcp.middlewares.tcpmiddleware02.ipwhitelist.sourcerange=foobar, foobar"
|
||||
- "traefik.tcp.middlewares.tcpmiddleware03.inflightconn.amount=42"
|
||||
|
|
|
@ -58,9 +58,11 @@
|
|||
|
||||
[[http.services.Service02.loadBalancer.servers]]
|
||||
url = "foobar"
|
||||
weight = 42
|
||||
|
||||
[[http.services.Service02.loadBalancer.servers]]
|
||||
url = "foobar"
|
||||
weight = 42
|
||||
[http.services.Service02.loadBalancer.healthCheck]
|
||||
scheme = "foobar"
|
||||
mode = "foobar"
|
||||
|
|
|
@ -65,7 +65,9 @@ http:
|
|||
maxAge: 42
|
||||
servers:
|
||||
- url: foobar
|
||||
weight: 42
|
||||
- url: foobar
|
||||
weight: 42
|
||||
healthCheck:
|
||||
scheme: foobar
|
||||
mode: foobar
|
||||
|
|
|
@ -240,7 +240,9 @@ THIS FILE MUST NOT BE EDITED BY HAND
|
|||
| `traefik/http/services/Service02/loadBalancer/passHostHeader` | `true` |
|
||||
| `traefik/http/services/Service02/loadBalancer/responseForwarding/flushInterval` | `42s` |
|
||||
| `traefik/http/services/Service02/loadBalancer/servers/0/url` | `foobar` |
|
||||
| `traefik/http/services/Service02/loadBalancer/servers/0/weight` | `42` |
|
||||
| `traefik/http/services/Service02/loadBalancer/servers/1/url` | `foobar` |
|
||||
| `traefik/http/services/Service02/loadBalancer/servers/1/weight` | `42` |
|
||||
| `traefik/http/services/Service02/loadBalancer/serversTransport` | `foobar` |
|
||||
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/httpOnly` | `true` |
|
||||
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/maxAge` | `42` |
|
||||
|
|
|
@ -143,6 +143,36 @@ The `url` option point to a specific instance.
|
|||
url = "http://private-ip-server-1/"
|
||||
```
|
||||
|
||||
The `weight` option allows for weighted load balancing on the servers.
|
||||
|
||||
??? example "A Service with Two Servers with Weight -- Using the [File Provider](../../providers/file.md)"
|
||||
|
||||
```yaml tab="YAML"
|
||||
## Dynamic configuration
|
||||
http:
|
||||
services:
|
||||
my-service:
|
||||
loadBalancer:
|
||||
servers:
|
||||
- url: "http://private-ip-server-1/"
|
||||
weight: 2
|
||||
- url: "http://private-ip-server-2/"
|
||||
weight: 1
|
||||
|
||||
```
|
||||
|
||||
```toml tab="TOML"
|
||||
## Dynamic configuration
|
||||
[http.services]
|
||||
[http.services.my-service.loadBalancer]
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-1/"
|
||||
weight = 2
|
||||
[[http.services.my-service.loadBalancer.servers]]
|
||||
url = "http://private-ip-server-2/"
|
||||
weight = 1
|
||||
```
|
||||
|
||||
#### Load-balancing
|
||||
|
||||
For now, only round robin load balancing is supported:
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -55,6 +56,56 @@ func (s *DockerSuite) TestSimpleConfiguration() {
|
|||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestWRRServer() {
|
||||
tempObjects := struct {
|
||||
DockerHost string
|
||||
DefaultRule string
|
||||
}{
|
||||
DockerHost: s.getDockerHost(),
|
||||
DefaultRule: "Host(`{{ normalize .Name }}.docker.localhost`)",
|
||||
}
|
||||
|
||||
file := s.adaptFile("fixtures/docker/simple.toml", tempObjects)
|
||||
|
||||
s.composeUp()
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
whoami1IP := s.getComposeServiceIP("wrr-server")
|
||||
whoami2IP := s.getComposeServiceIP("wrr-server2")
|
||||
|
||||
// Expected a 404 as we did not configure anything
|
||||
err := try.GetRequest("http://127.0.0.1:8000/", 500*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = try.GetRequest("http://127.0.0.1:8080/api/http/services", 1000*time.Millisecond, try.BodyContains("wrr-server"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
repartition := map[string]int{}
|
||||
for i := 0; i < 4; i++ {
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
|
||||
req.Host = "my.wrr.host"
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
response, err := http.DefaultClient.Do(req)
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
|
||||
|
||||
body, err := io.ReadAll(response.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
if strings.Contains(string(body), whoami1IP) {
|
||||
repartition[whoami1IP]++
|
||||
}
|
||||
if strings.Contains(string(body), whoami2IP) {
|
||||
repartition[whoami2IP]++
|
||||
}
|
||||
}
|
||||
|
||||
assert.Equal(s.T(), 3, repartition[whoami1IP])
|
||||
assert.Equal(s.T(), 1, repartition[whoami2IP])
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestDefaultDockerContainers() {
|
||||
tempObjects := struct {
|
||||
DockerHost string
|
||||
|
|
35
integration/fixtures/wrr_server.toml
Normal file
35
integration/fixtures/wrr_server.toml
Normal file
|
@ -0,0 +1,35 @@
|
|||
[global]
|
||||
checkNewVersion = false
|
||||
sendAnonymousUsage = false
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
[log]
|
||||
level = "DEBUG"
|
||||
noColor = true
|
||||
|
||||
[entryPoints]
|
||||
|
||||
[entryPoints.web]
|
||||
address = ":8000"
|
||||
|
||||
[providers.file]
|
||||
filename = "{{ .SelfFilename }}"
|
||||
|
||||
## dynamic configuration ##
|
||||
|
||||
[http.routers]
|
||||
[http.routers.router]
|
||||
service = "service1"
|
||||
rule = "Path(`/whoami`)"
|
||||
|
||||
[http.services]
|
||||
|
||||
[http.services.service1.loadBalancer]
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "{{ .Server1 }}"
|
||||
weight = 3
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "{{ .Server2 }}"
|
||||
|
|
@ -36,3 +36,14 @@ services:
|
|||
labels:
|
||||
traefik.http.Routers.Super.Rule: Host(`my.super.host`)
|
||||
traefik.http.Services.powpow.LoadBalancer.server.Port: 2375
|
||||
|
||||
wrr-server:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.http.Routers.wrr-server.Rule: Host(`my.wrr.host`)
|
||||
traefik.http.Services.wrr-server.LoadBalancer.server.Weight: 4
|
||||
wrr-server2:
|
||||
image: traefik/whoami
|
||||
labels:
|
||||
traefik.http.Routers.wrr-server.Rule: Host(`my.wrr.host`)
|
||||
traefik.http.Services.wrr-server.LoadBalancer.server.Weight: 1
|
||||
|
|
|
@ -809,6 +809,49 @@ func (s *SimpleSuite) TestUDPServiceConfigErrors() {
|
|||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestWRRServer() {
|
||||
s.createComposeProject("base")
|
||||
|
||||
s.composeUp()
|
||||
defer s.composeDown()
|
||||
|
||||
whoami1IP := s.getComposeServiceIP("whoami1")
|
||||
whoami2IP := s.getComposeServiceIP("whoami2")
|
||||
|
||||
file := s.adaptFile("fixtures/wrr_server.toml", struct {
|
||||
Server1 string
|
||||
Server2 string
|
||||
}{Server1: "http://" + whoami1IP, Server2: "http://" + whoami2IP})
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
err := try.GetRequest("http://127.0.0.1:8080/api/http/services", 1000*time.Millisecond, try.BodyContains("service1"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
repartition := map[string]int{}
|
||||
for i := 0; i < 4; i++ {
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
response, err := http.DefaultClient.Do(req)
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
|
||||
|
||||
body, err := io.ReadAll(response.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
if strings.Contains(string(body), whoami1IP) {
|
||||
repartition[whoami1IP]++
|
||||
}
|
||||
if strings.Contains(string(body), whoami2IP) {
|
||||
repartition[whoami2IP]++
|
||||
}
|
||||
}
|
||||
|
||||
assert.Equal(s.T(), 3, repartition[whoami1IP])
|
||||
assert.Equal(s.T(), 1, repartition[whoami2IP])
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestWRR() {
|
||||
s.createComposeProject("base")
|
||||
|
||||
|
|
|
@ -227,6 +227,7 @@ func (r *ResponseForwarding) SetDefaults() {
|
|||
// Server holds the server configuration.
|
||||
type Server struct {
|
||||
URL string `json:"url,omitempty" toml:"url,omitempty" yaml:"url,omitempty" label:"-"`
|
||||
Weight *int `json:"weight,omitempty" toml:"weight,omitempty" yaml:"weight,omitempty" label:"weight"`
|
||||
Scheme string `json:"-" toml:"-" yaml:"-" file:"-"`
|
||||
Port string `json:"-" toml:"-" yaml:"-" file:"-"`
|
||||
}
|
||||
|
|
|
@ -1128,6 +1128,11 @@ func (in *RouterTLSConfig) DeepCopy() *RouterTLSConfig {
|
|||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Server) DeepCopyInto(out *Server) {
|
||||
*out = *in
|
||||
if in.Weight != nil {
|
||||
in, out := &in.Weight, &out.Weight
|
||||
*out = new(int)
|
||||
**out = **in
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1180,7 +1185,9 @@ func (in *ServersLoadBalancer) DeepCopyInto(out *ServersLoadBalancer) {
|
|||
if in.Servers != nil {
|
||||
in, out := &in.Servers, &out.Servers
|
||||
*out = make([]Server, len(*in))
|
||||
copy(*out, *in)
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.HealthCheck != nil {
|
||||
in, out := &in.HealthCheck, &out.HealthCheck
|
||||
|
|
|
@ -319,7 +319,7 @@ func (m *Manager) getLoadBalancerServiceHandler(ctx context.Context, serviceName
|
|||
|
||||
proxy = tracingMiddle.NewService(ctx, serviceName, proxy)
|
||||
|
||||
lb.Add(proxyName, proxy, nil)
|
||||
lb.Add(proxyName, proxy, server.Weight)
|
||||
|
||||
// servers are considered UP by default.
|
||||
info.UpdateServerStatus(target.String(), runtime.StatusUp)
|
||||
|
|
Loading…
Reference in a new issue