feat: add highest random weight in kubernetes CRD
This commit is contained in:
parent
c09d3fb03c
commit
634f892370
17 changed files with 1328 additions and 24 deletions
48
integration/fixtures/highest_random_weight.toml
Normal file
48
integration/fixtures/highest_random_weight.toml
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
[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 = "hrw"
|
||||
rule = "Path(`/whoami`)"
|
||||
|
||||
|
||||
[http.services]
|
||||
[http.services.hrw.highestRandomWeight]
|
||||
[[http.services.hrw.highestRandomWeight.services]]
|
||||
name = "service1"
|
||||
weight = 10
|
||||
[[http.services.hrw.highestRandomWeight.services]]
|
||||
name = "service2"
|
||||
weight = 20
|
||||
[[http.services.hrw.highestRandomWeight.services]]
|
||||
name = "service3"
|
||||
weight = 30
|
||||
|
||||
[http.services.service1.loadBalancer]
|
||||
[[http.services.service1.loadBalancer.servers]]
|
||||
url = "{{ .Service1Server }}"
|
||||
[http.services.service2.loadBalancer]
|
||||
[[http.services.service2.loadBalancer.servers]]
|
||||
url = "{{ .Service2Server }}"
|
||||
[http.services.service3.loadBalancer]
|
||||
[[http.services.service3.loadBalancer.servers]]
|
||||
url = "{{ .Service3Server }}"
|
||||
|
|
@ -331,11 +331,12 @@ spec:
|
|||
strategy:
|
||||
description: |-
|
||||
Strategy defines the load balancing strategy between the servers.
|
||||
Supported values are: wrr (Weighed round-robin) and p2c (Power of two choices).
|
||||
Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), and hrw (Highest Random Weight).
|
||||
RoundRobin value is deprecated and supported for backward compatibility.
|
||||
enum:
|
||||
- wrr
|
||||
- p2c
|
||||
- hrw
|
||||
- RoundRobin
|
||||
type: string
|
||||
weight:
|
||||
|
|
@ -1292,11 +1293,12 @@ spec:
|
|||
strategy:
|
||||
description: |-
|
||||
Strategy defines the load balancing strategy between the servers.
|
||||
Supported values are: wrr (Weighed round-robin) and p2c (Power of two choices).
|
||||
Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), and hrw (Highest Random Weight).
|
||||
RoundRobin value is deprecated and supported for backward compatibility.
|
||||
enum:
|
||||
- wrr
|
||||
- p2c
|
||||
- hrw
|
||||
- RoundRobin
|
||||
type: string
|
||||
weight:
|
||||
|
|
@ -2791,6 +2793,243 @@ spec:
|
|||
spec:
|
||||
description: TraefikServiceSpec defines the desired state of a TraefikService.
|
||||
properties:
|
||||
highestRandomWeight:
|
||||
description: HighestRandomWeight defines the highest random weight
|
||||
service configuration.
|
||||
properties:
|
||||
services:
|
||||
description: Services defines the list of Kubernetes Service and/or
|
||||
TraefikService to load-balance, with weight.
|
||||
items:
|
||||
description: Service defines an upstream HTTP service to proxy
|
||||
traffic to.
|
||||
properties:
|
||||
healthCheck:
|
||||
description: Healthcheck defines health checks for ExternalName
|
||||
services.
|
||||
properties:
|
||||
followRedirects:
|
||||
description: |-
|
||||
FollowRedirects defines whether redirects should be followed during the health check calls.
|
||||
Default: true
|
||||
type: boolean
|
||||
headers:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: Headers defines custom headers to be sent
|
||||
to the health check endpoint.
|
||||
type: object
|
||||
hostname:
|
||||
description: Hostname defines the value of hostname
|
||||
in the Host header of the health check request.
|
||||
type: string
|
||||
interval:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: |-
|
||||
Interval defines the frequency of the health check calls for healthy targets.
|
||||
Default: 30s
|
||||
x-kubernetes-int-or-string: true
|
||||
method:
|
||||
description: Method defines the healthcheck method.
|
||||
type: string
|
||||
mode:
|
||||
description: |-
|
||||
Mode defines the health check mode.
|
||||
If defined to grpc, will use the gRPC health check protocol to probe the server.
|
||||
Default: http
|
||||
type: string
|
||||
path:
|
||||
description: Path defines the server URL path for the
|
||||
health check endpoint.
|
||||
type: string
|
||||
port:
|
||||
description: Port defines the server URL port for the
|
||||
health check endpoint.
|
||||
type: integer
|
||||
scheme:
|
||||
description: Scheme replaces the server URL scheme for
|
||||
the health check endpoint.
|
||||
type: string
|
||||
status:
|
||||
description: Status defines the expected HTTP status
|
||||
code of the response to the health check request.
|
||||
type: integer
|
||||
timeout:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: |-
|
||||
Timeout defines the maximum duration Traefik will wait for a health check request before considering the server unhealthy.
|
||||
Default: 5s
|
||||
x-kubernetes-int-or-string: true
|
||||
unhealthyInterval:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: |-
|
||||
UnhealthyInterval defines the frequency of the health check calls for unhealthy targets.
|
||||
When UnhealthyInterval is not defined, it defaults to the Interval value.
|
||||
Default: 30s
|
||||
x-kubernetes-int-or-string: true
|
||||
type: object
|
||||
kind:
|
||||
description: Kind defines the kind of the Service.
|
||||
enum:
|
||||
- Service
|
||||
- TraefikService
|
||||
type: string
|
||||
name:
|
||||
description: |-
|
||||
Name defines the name of the referenced Kubernetes Service or TraefikService.
|
||||
The differentiation between the two is specified in the Kind field.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace defines the namespace of the referenced
|
||||
Kubernetes Service or TraefikService.
|
||||
type: string
|
||||
nativeLB:
|
||||
description: |-
|
||||
NativeLB controls, when creating the load-balancer,
|
||||
whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP.
|
||||
The Kubernetes Service itself does load-balance to the pods.
|
||||
By default, NativeLB is false.
|
||||
type: boolean
|
||||
nodePortLB:
|
||||
description: |-
|
||||
NodePortLB controls, when creating the load-balancer,
|
||||
whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort.
|
||||
It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.
|
||||
By default, NodePortLB is false.
|
||||
type: boolean
|
||||
passHostHeader:
|
||||
description: |-
|
||||
PassHostHeader defines whether the client Host header is forwarded to the upstream Kubernetes Service.
|
||||
By default, passHostHeader is true.
|
||||
type: boolean
|
||||
passiveHealthCheck:
|
||||
description: PassiveHealthCheck defines passive health checks
|
||||
for ExternalName services.
|
||||
properties:
|
||||
failureWindow:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: FailureWindow defines the time window during
|
||||
which the failed attempts must occur for the server
|
||||
to be marked as unhealthy. It also defines for how
|
||||
long the server will be considered unhealthy.
|
||||
x-kubernetes-int-or-string: true
|
||||
maxFailedAttempts:
|
||||
description: MaxFailedAttempts is the number of consecutive
|
||||
failed attempts allowed within the failure window
|
||||
before marking the server as unhealthy.
|
||||
type: integer
|
||||
type: object
|
||||
port:
|
||||
anyOf:
|
||||
- type: integer
|
||||
- type: string
|
||||
description: |-
|
||||
Port defines the port of a Kubernetes Service.
|
||||
This can be a reference to a named port.
|
||||
x-kubernetes-int-or-string: true
|
||||
responseForwarding:
|
||||
description: ResponseForwarding defines how Traefik forwards
|
||||
the response from the upstream Kubernetes Service to the
|
||||
client.
|
||||
properties:
|
||||
flushInterval:
|
||||
description: |-
|
||||
FlushInterval defines the interval, in milliseconds, in between flushes to the client while copying the response body.
|
||||
A negative value means to flush immediately after each write to the client.
|
||||
This configuration is ignored when ReverseProxy recognizes a response as a streaming response;
|
||||
for such responses, writes are flushed to the client immediately.
|
||||
Default: 100ms
|
||||
type: string
|
||||
type: object
|
||||
scheme:
|
||||
description: |-
|
||||
Scheme defines the scheme to use for the request to the upstream Kubernetes Service.
|
||||
It defaults to https when Kubernetes Service port is 443, http otherwise.
|
||||
type: string
|
||||
serversTransport:
|
||||
description: |-
|
||||
ServersTransport defines the name of ServersTransport resource to use.
|
||||
It allows to configure the transport between Traefik and your servers.
|
||||
Can only be used on a Kubernetes Service.
|
||||
type: string
|
||||
sticky:
|
||||
description: |-
|
||||
Sticky defines the sticky sessions configuration.
|
||||
More info: https://doc.traefik.io/traefik/v3.5/routing/services/#sticky-sessions
|
||||
properties:
|
||||
cookie:
|
||||
description: Cookie defines the sticky cookie configuration.
|
||||
properties:
|
||||
domain:
|
||||
description: |-
|
||||
Domain defines the host to which the cookie will be sent.
|
||||
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#domaindomain-value
|
||||
type: string
|
||||
httpOnly:
|
||||
description: HTTPOnly defines whether the cookie
|
||||
can be accessed by client-side APIs, such as JavaScript.
|
||||
type: boolean
|
||||
maxAge:
|
||||
description: |-
|
||||
MaxAge defines the number of seconds until the cookie expires.
|
||||
When set to a negative number, the cookie expires immediately.
|
||||
When set to zero, the cookie never expires.
|
||||
type: integer
|
||||
name:
|
||||
description: Name defines the Cookie name.
|
||||
type: string
|
||||
path:
|
||||
description: |-
|
||||
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
|
||||
When not provided the cookie will be sent on every request to the domain.
|
||||
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
|
||||
type: string
|
||||
sameSite:
|
||||
description: |-
|
||||
SameSite defines the same site policy.
|
||||
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
|
||||
enum:
|
||||
- none
|
||||
- lax
|
||||
- strict
|
||||
type: string
|
||||
secure:
|
||||
description: Secure defines whether the cookie can
|
||||
only be transmitted over an encrypted connection
|
||||
(i.e. HTTPS).
|
||||
type: boolean
|
||||
type: object
|
||||
type: object
|
||||
strategy:
|
||||
description: |-
|
||||
Strategy defines the load balancing strategy between the servers.
|
||||
Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), and hrw (Highest Random Weight).
|
||||
RoundRobin value is deprecated and supported for backward compatibility.
|
||||
enum:
|
||||
- wrr
|
||||
- p2c
|
||||
- hrw
|
||||
- RoundRobin
|
||||
type: string
|
||||
weight:
|
||||
description: |-
|
||||
Weight defines the weight and should only be specified when Name references a TraefikService object
|
||||
(and to be precise, one that embeds a Weighted Round Robin).
|
||||
minimum: 0
|
||||
type: integer
|
||||
required:
|
||||
- name
|
||||
type: object
|
||||
type: array
|
||||
type: object
|
||||
mirroring:
|
||||
description: Mirroring defines the Mirroring service configuration.
|
||||
properties:
|
||||
|
|
@ -3100,11 +3339,12 @@ spec:
|
|||
strategy:
|
||||
description: |-
|
||||
Strategy defines the load balancing strategy between the servers.
|
||||
Supported values are: wrr (Weighed round-robin) and p2c (Power of two choices).
|
||||
Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), and hrw (Highest Random Weight).
|
||||
RoundRobin value is deprecated and supported for backward compatibility.
|
||||
enum:
|
||||
- wrr
|
||||
- p2c
|
||||
- hrw
|
||||
- RoundRobin
|
||||
type: string
|
||||
weight:
|
||||
|
|
@ -3246,11 +3486,12 @@ spec:
|
|||
strategy:
|
||||
description: |-
|
||||
Strategy defines the load balancing strategy between the servers.
|
||||
Supported values are: wrr (Weighed round-robin) and p2c (Power of two choices).
|
||||
Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), and hrw (Highest Random Weight).
|
||||
RoundRobin value is deprecated and supported for backward compatibility.
|
||||
enum:
|
||||
- wrr
|
||||
- p2c
|
||||
- hrw
|
||||
- RoundRobin
|
||||
type: string
|
||||
weight:
|
||||
|
|
@ -3479,11 +3720,12 @@ spec:
|
|||
strategy:
|
||||
description: |-
|
||||
Strategy defines the load balancing strategy between the servers.
|
||||
Supported values are: wrr (Weighed round-robin) and p2c (Power of two choices).
|
||||
Supported values are: wrr (Weighed round-robin), p2c (Power of two choices), and hrw (Highest Random Weight).
|
||||
RoundRobin value is deprecated and supported for backward compatibility.
|
||||
enum:
|
||||
- wrr
|
||||
- p2c
|
||||
- hrw
|
||||
- RoundRobin
|
||||
type: string
|
||||
weight:
|
||||
|
|
|
|||
|
|
@ -28,6 +28,23 @@ spec:
|
|||
- name: whoami
|
||||
port: 80
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: TraefikService
|
||||
metadata:
|
||||
name: hrw1
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
highestRandomWeight:
|
||||
services:
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 10
|
||||
- name: whoami
|
||||
port: 80
|
||||
weight: 20
|
||||
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
|
|
@ -47,6 +64,22 @@ spec:
|
|||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: test4.route
|
||||
namespace: default
|
||||
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`foo.com`) && PathPrefix(`/hrw1`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: hrw1
|
||||
kind: TraefikService
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: api.route
|
||||
namespace: default
|
||||
|
|
|
|||
|
|
@ -1217,6 +1217,74 @@ func (s *SimpleSuite) TestMirrorCanceled() {
|
|||
assert.Equal(s.T(), int32(0), val2)
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestHighestRandomWeight() {
|
||||
var count1, count2, count3 int32
|
||||
|
||||
service1 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
atomic.AddInt32(&count1, 1)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
service2 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
atomic.AddInt32(&count2, 1)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
service3 := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
|
||||
atomic.AddInt32(&count3, 1)
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}))
|
||||
|
||||
service1Server := service1.URL
|
||||
service2Server := service2.URL
|
||||
service3Server := service3.URL
|
||||
|
||||
file := s.adaptFile("fixtures/highest_random_weight.toml", struct {
|
||||
Service1Server string
|
||||
Service2Server string
|
||||
Service3Server string
|
||||
}{Service1Server: service1Server, Service2Server: service2Server, Service3Server: service3Server})
|
||||
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
|
||||
err := try.GetRequest("http://127.0.0.1:8080/api/http/services", 3*time.Second, try.BodyContains("service1", "service2", "service3", "hrw"))
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// Make 10 requests from the same client (127.0.0.1) - should all go to the same service
|
||||
client := &http.Client{}
|
||||
for range 10 {
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000/whoami", nil)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
response, err := client.Do(req)
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), http.StatusOK, response.StatusCode)
|
||||
response.Body.Close()
|
||||
}
|
||||
|
||||
// Check if all requests went to the same service
|
||||
val1 := atomic.LoadInt32(&count1)
|
||||
val2 := atomic.LoadInt32(&count2)
|
||||
val3 := atomic.LoadInt32(&count3)
|
||||
|
||||
// All requests should have been handled (total should be 10)
|
||||
assert.Equal(s.T(), int32(10), val1+val2+val3)
|
||||
|
||||
// All requests from same remoteAddr (127.0.0.1) should go to exactly one service
|
||||
servicesUsed := 0
|
||||
if val1 > 0 {
|
||||
servicesUsed++
|
||||
}
|
||||
if val2 > 0 {
|
||||
servicesUsed++
|
||||
}
|
||||
if val3 > 0 {
|
||||
servicesUsed++
|
||||
}
|
||||
|
||||
assert.Equal(s.T(), 1, servicesUsed, "All requests from same remoteAddr should go to exactly one service")
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestSecureAPI() {
|
||||
s.createComposeProject("base")
|
||||
|
||||
|
|
|
|||
36
integration/testdata/rawdata-crd.json
vendored
36
integration/testdata/rawdata-crd.json
vendored
|
|
@ -78,6 +78,24 @@
|
|||
"web"
|
||||
]
|
||||
},
|
||||
"default-test4-route-466d8d3a547de55dfe8a@kubernetescrd": {
|
||||
"entryPoints": [
|
||||
"web"
|
||||
],
|
||||
"service": "default-hrw1",
|
||||
"rule": "Host(`foo.com`) \u0026\u0026 PathPrefix(`/hrw1`)",
|
||||
"priority": 38,
|
||||
"observability": {
|
||||
"accessLogs": true,
|
||||
"metrics": true,
|
||||
"tracing": true,
|
||||
"traceVerbosity": "minimal"
|
||||
},
|
||||
"status": "enabled",
|
||||
"using": [
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"default-testst-route-60ad45fcb5fc1f5f3629@kubernetescrd": {
|
||||
"entryPoints": [
|
||||
"web"
|
||||
|
|
@ -157,6 +175,24 @@
|
|||
"dashboard@internal": {
|
||||
"status": "enabled"
|
||||
},
|
||||
"default-hrw1@kubernetescrd": {
|
||||
"highestRandomWeight": {
|
||||
"services": [
|
||||
{
|
||||
"name": "default-whoami-80",
|
||||
"weight": 10
|
||||
},
|
||||
{
|
||||
"name": "default-whoami-80",
|
||||
"weight": 20
|
||||
}
|
||||
]
|
||||
},
|
||||
"status": "enabled",
|
||||
"usedBy": [
|
||||
"default-test4-route-466d8d3a547de55dfe8a@kubernetescrd"
|
||||
]
|
||||
},
|
||||
"default-mirror1@kubernetescrd": {
|
||||
"mirroring": {
|
||||
"service": "default-whoami-80",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue