mirror of
https://github.com/traefik/traefik.git
synced 2025-09-20 21:31:14 +02:00
feat: add highest random weight in kubernetes CRD
This commit is contained in:
parent
c09d3fb03c
commit
634f892370
@ -331,11 +331,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -1292,11 +1293,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -2791,6 +2793,243 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
description: TraefikServiceSpec defines the desired state of a TraefikService.
|
description: TraefikServiceSpec defines the desired state of a TraefikService.
|
||||||
properties:
|
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:
|
mirroring:
|
||||||
description: Mirroring defines the Mirroring service configuration.
|
description: Mirroring defines the Mirroring service configuration.
|
||||||
properties:
|
properties:
|
||||||
@ -3100,11 +3339,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -3246,11 +3486,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -3479,11 +3720,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
|
@ -331,11 +331,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
|
@ -484,11 +484,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
|
@ -44,6 +44,243 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
description: TraefikServiceSpec defines the desired state of a TraefikService.
|
description: TraefikServiceSpec defines the desired state of a TraefikService.
|
||||||
properties:
|
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:
|
mirroring:
|
||||||
description: Mirroring defines the Mirroring service configuration.
|
description: Mirroring defines the Mirroring service configuration.
|
||||||
properties:
|
properties:
|
||||||
@ -353,11 +590,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -499,11 +737,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -732,11 +971,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
|
@ -3,11 +3,12 @@ title: "Traefik Kubernetes Services Documentation"
|
|||||||
description: "Learn how to configure routing and load balancing in Traefik Proxy to reach Services, which handle incoming requests. Read the technical documentation."
|
description: "Learn how to configure routing and load balancing in Traefik Proxy to reach Services, which handle incoming requests. Read the technical documentation."
|
||||||
---
|
---
|
||||||
|
|
||||||
A `TraefikService` is a custom resource that sits on top of the Kubernetes Services. It enables advanced load-balancing features such as a [Weighted Round Robin](#weighted-round-robin) load balancing or a [Mirroring](#mirroring) between your Kubernetes Services.
|
A `TraefikService` is a custom resource that sits on top of the Kubernetes Services. It enables advanced load-balancing features such as a [Weighted Round Robin](#weighted-round-robin) load balancing, a [Highest Random Weight](#highest-random-weight) load balancing, or a [Mirroring](#mirroring) between your Kubernetes Services.
|
||||||
|
|
||||||
Services configure how to reach the actual endpoints that will eventually handle incoming requests. In Traefik, the target service can be either a standard [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/)—which exposes a pod—or a TraefikService. The latter allows you to combine advanced load-balancing options like:
|
Services configure how to reach the actual endpoints that will eventually handle incoming requests. In Traefik, the target service can be either a standard [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/)—which exposes a pod—or a TraefikService. The latter allows you to combine advanced load-balancing options like:
|
||||||
|
|
||||||
- [Weighted Round Robin load balancing](#weighted-round-robin).
|
- [Weighted Round Robin load balancing](#weighted-round-robin).
|
||||||
|
- [Highest Random Weight load balancing](#highest-random-weight).
|
||||||
- [Mirroring](#mirroring).
|
- [Mirroring](#mirroring).
|
||||||
|
|
||||||
## Weighted Round Robin
|
## Weighted Round Robin
|
||||||
@ -255,6 +256,143 @@ In the example above, to keep a session open with the same server, the client wo
|
|||||||
curl -H Host:example.com -b "lvl1=default-whoami1-80; lvl2=http://10.42.0.6:80" http://localhost:8000/foo
|
curl -H Host:example.com -b "lvl1=default-whoami1-80; lvl2=http://10.42.0.6:80" http://localhost:8000/foo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Highest Random Weight
|
||||||
|
|
||||||
|
The HRW (Highest Random Weight) load balancer uses consistent hashing to ensure that requests from the same client IP are always routed to the same service. Unlike weighted round-robin which distributes requests based on weights, HRW provides consistent routing based on the client's remote address.
|
||||||
|
|
||||||
|
This is particularly useful for maintaining session affinity without requiring sticky cookies, as clients will consistently reach the same backend service based on their IP address.
|
||||||
|
|
||||||
|
### Configuration Example
|
||||||
|
|
||||||
|
```yaml tab="IngressRoute"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test-hrw
|
||||||
|
namespace: apps
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- websecure
|
||||||
|
routes:
|
||||||
|
- match: Host(`example.com`) && PathPrefix(`/app`)
|
||||||
|
kind: Rule
|
||||||
|
services:
|
||||||
|
# Set an HRW TraefikService
|
||||||
|
- name: hrw1
|
||||||
|
namespace: apps
|
||||||
|
kind: TraefikService
|
||||||
|
tls:
|
||||||
|
secretName: supersecret
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="TraefikService HRW"
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: TraefikService
|
||||||
|
metadata:
|
||||||
|
name: hrw1
|
||||||
|
namespace: apps
|
||||||
|
|
||||||
|
spec:
|
||||||
|
highestRandomWeight:
|
||||||
|
services:
|
||||||
|
# Kubernetes Service with weight 10
|
||||||
|
- name: svc1
|
||||||
|
namespace: apps
|
||||||
|
port: 80
|
||||||
|
weight: 10
|
||||||
|
# Kubernetes Service with weight 20
|
||||||
|
- name: svc2
|
||||||
|
namespace: apps
|
||||||
|
port: 80
|
||||||
|
weight: 20
|
||||||
|
# Another TraefikService
|
||||||
|
- name: wrr1
|
||||||
|
namespace: apps
|
||||||
|
kind: TraefikService
|
||||||
|
weight: 15
|
||||||
|
```
|
||||||
|
|
||||||
|
```yaml tab="Kubernetes Services"
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: svc1
|
||||||
|
namespace: apps
|
||||||
|
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
selector:
|
||||||
|
app: traefiklabs
|
||||||
|
task: app1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: svc2
|
||||||
|
namespace: apps
|
||||||
|
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
selector:
|
||||||
|
app: traefiklabs
|
||||||
|
task: app2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Options
|
||||||
|
|
||||||
|
| Field | Description | Default | Required |
|
||||||
|
|:---------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------------------------------------------------------------------|:---------|
|
||||||
|
| <a id="hrw-services" href="#hrw-services" title="#hrw-services">`services`</a> | List of any combination of TraefikService and [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). Each service must have a weight assigned. | | Yes |
|
||||||
|
| <a id="hrw-servicesm-kind" href="#hrw-servicesm-kind" title="#hrw-servicesm-kind">`services[m].`<br />`kind`</a> | Kind of the service targeted.<br />Two values allowed:<br />- **Service**: Kubernetes Service<br /> - **TraefikService**: Traefik Service. | "" | No |
|
||||||
|
| <a id="hrw-servicesm-name" href="#hrw-servicesm-name" title="#hrw-servicesm-name">`services[m].`<br />`name`</a> | Service name.<br />The character `@` is not authorized. | "" | Yes |
|
||||||
|
| <a id="hrw-servicesm-namespace" href="#hrw-servicesm-namespace" title="#hrw-servicesm-namespace">`services[m].`<br />`namespace`</a> | Service namespace. | "" | No |
|
||||||
|
| <a id="hrw-servicesm-port" href="#hrw-servicesm-port" title="#hrw-servicesm-port">`services[m].`<br />`port`</a> | Service port (number or port name).<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||||
|
| <a id="hrw-servicesm-weight" href="#hrw-servicesm-weight" title="#hrw-servicesm-weight">`services[m].`<br />`weight`</a> | Service weight used in the HRW algorithm. Higher weights increase the probability of selection for a given client IP. | 1 | No |
|
||||||
|
| <a id="hrw-servicesm-responseForwarding-flushInterval" href="#hrw-servicesm-responseForwarding-flushInterval" title="#hrw-servicesm-responseForwarding-flushInterval">`services[m].`<br />`responseForwarding.`<br />`flushInterval`</a> | Interval, in milliseconds, in between flushes to the client while copying the response body.<br />A negative value means to flush immediately after each write to the client.<br />This configuration is ignored when a response is a streaming response; for such responses, writes are flushed to the client immediately.<br />Evaluated only if the kind is **Service**. | 100ms | No |
|
||||||
|
| <a id="hrw-servicesm-scheme" href="#hrw-servicesm-scheme" title="#hrw-servicesm-scheme">`services[m].`<br />`scheme`</a> | Scheme to use for the request to the upstream Kubernetes Service.<br />Evaluated only if the kind is **Service**. | "http"<br />"https" if `port` is 443 or contains the string *https*. | No |
|
||||||
|
| <a id="hrw-servicesm-serversTransport" href="#hrw-servicesm-serversTransport" title="#hrw-servicesm-serversTransport">`services[m].`<br />`serversTransport`</a> | Name of ServersTransport resource to use to configure the transport between Traefik and your servers.<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||||
|
| <a id="hrw-servicesm-passHostHeader" href="#hrw-servicesm-passHostHeader" title="#hrw-servicesm-passHostHeader">`services[m].`<br />`passHostHeader`</a> | Forward client Host header to server.<br />Evaluated only if the kind is **Service**. | true | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-scheme" href="#hrw-servicesm-healthCheck-scheme" title="#hrw-servicesm-healthCheck-scheme">`services[m].`<br />`healthCheck.scheme`</a> | Server URL scheme for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "" | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-mode" href="#hrw-servicesm-healthCheck-mode" title="#hrw-servicesm-healthCheck-mode">`services[m].`<br />`healthCheck.mode`</a> | Health check mode.<br /> If defined to grpc, will use the gRPC health check protocol to probe the server.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "http" | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-path" href="#hrw-servicesm-healthCheck-path" title="#hrw-servicesm-healthCheck-path">`services[m].`<br />`healthCheck.path`</a> | Server URL path for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "" | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-interval" href="#hrw-servicesm-healthCheck-interval" title="#hrw-servicesm-healthCheck-interval">`services[m].`<br />`healthCheck.interval`</a> | Frequency of the health check calls for healthy targets.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "100ms" | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-unhealthyInterval" href="#hrw-servicesm-healthCheck-unhealthyInterval" title="#hrw-servicesm-healthCheck-unhealthyInterval">`services[m].`<br />`healthCheck.unhealthyInterval`</a> | Frequency of the health check calls for unhealthy targets.<br />When not defined, it defaults to the `interval` value.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "100ms" | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-method" href="#hrw-servicesm-healthCheck-method" title="#hrw-servicesm-healthCheck-method">`services[m].`<br />`healthCheck.method`</a> | HTTP method for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "GET" | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-status" href="#hrw-servicesm-healthCheck-status" title="#hrw-servicesm-healthCheck-status">`services[m].`<br />`healthCheck.status`</a> | Expected HTTP status code of the response to the health check request.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName.<br />If not set, expect a status between 200 and 399.<br />Evaluated only if the kind is **Service**. | | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-port" href="#hrw-servicesm-healthCheck-port" title="#hrw-servicesm-healthCheck-port">`services[m].`<br />`healthCheck.port`</a> | URL port for the health check endpoint.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-timeout" href="#hrw-servicesm-healthCheck-timeout" title="#hrw-servicesm-healthCheck-timeout">`services[m].`<br />`healthCheck.timeout`</a> | Maximum duration to wait before considering the server unhealthy.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "5s" | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-hostname" href="#hrw-servicesm-healthCheck-hostname" title="#hrw-servicesm-healthCheck-hostname">`services[m].`<br />`healthCheck.hostname`</a> | Value in the Host header of the health check request.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | "" | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-followRedirect" href="#hrw-servicesm-healthCheck-followRedirect" title="#hrw-servicesm-healthCheck-followRedirect">`services[m].`<br />`healthCheck.`<br />`followRedirect`</a> | Follow the redirections during the healtchcheck.<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | true | No |
|
||||||
|
| <a id="hrw-servicesm-healthCheck-headers" href="#hrw-servicesm-healthCheck-headers" title="#hrw-servicesm-healthCheck-headers">`services[m].`<br />`healthCheck.headers`</a> | Map of header to send to the health check endpoint<br />Evaluated only if the kind is **Service**.<br />Only for [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type `ExternalName`. | | No |
|
||||||
|
| <a id="hrw-servicesm-sticky-cookie-name" href="#hrw-servicesm-sticky-cookie-name" title="#hrw-servicesm-sticky-cookie-name">`services[m].`<br />`sticky.`<br />`cookie.name`</a> | Name of the cookie used for the stickiness.<br />Evaluated only if the kind is **Service**. | Abbreviation of a sha1<br />(ex: `_1d52e`). | No |
|
||||||
|
| <a id="hrw-servicesm-sticky-cookie-httpOnly" href="#hrw-servicesm-sticky-cookie-httpOnly" title="#hrw-servicesm-sticky-cookie-httpOnly">`services[m].`<br />`sticky.`<br />`cookie.httpOnly`</a> | Allow the cookie can be accessed by client-side APIs, such as JavaScript.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||||
|
| <a id="hrw-servicesm-sticky-cookie-secure" href="#hrw-servicesm-sticky-cookie-secure" title="#hrw-servicesm-sticky-cookie-secure">`services[m].`<br />`sticky.`<br />`cookie.secure`</a> | Allow the cookie can only be transmitted over an encrypted connection (i.e. HTTPS).<br />Evaluated only if the kind is **Service**. | false | No |
|
||||||
|
| <a id="hrw-servicesm-sticky-cookie-sameSite" href="#hrw-servicesm-sticky-cookie-sameSite" title="#hrw-servicesm-sticky-cookie-sameSite">`services[m].`<br />`sticky.`<br />`cookie.sameSite`</a> | [SameSite](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite) policy.<br />Allowed values:<br />-`none`<br />-`lax`<br />`strict`<br />Evaluated only if the kind is **Service**. | "" | No |
|
||||||
|
| <a id="hrw-servicesm-sticky-cookie-maxAge" href="#hrw-servicesm-sticky-cookie-maxAge" title="#hrw-servicesm-sticky-cookie-maxAge">`services[m].`<br />`sticky.`<br />`cookie.maxAge`</a> | Number of seconds until the cookie expires.<br />Negative number, the cookie expires immediately.<br />0, the cookie never expires.<br />Evaluated only if the kind is **Service**. | 0 | No |
|
||||||
|
| <a id="hrw-servicesm-strategy" href="#hrw-servicesm-strategy" title="#hrw-servicesm-strategy">`services[m].`<br />`strategy`</a> | Load balancing strategy between the servers.<br />RoundRobin is the only supported value yet.<br />Evaluated only if the kind is **Service**. | "RoundRobin" | No |
|
||||||
|
| <a id="hrw-servicesm-nativeLB" href="#hrw-servicesm-nativeLB" title="#hrw-servicesm-nativeLB">`services[m].`<br />`nativeLB`</a> | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||||
|
| <a id="hrw-servicesm-nodePortLB" href="#hrw-servicesm-nodePortLB" title="#hrw-servicesm-nodePortLB">`services[m].`<br />`nodePortLB`</a> | Use the nodePort IP address when the service type is NodePort.<br />It allows services to be reachable when Traefik runs externally from the Kubernetes cluster but within the same network of the nodes.<br />Evaluated only if the kind is **Service**. | false | No |
|
||||||
|
|
||||||
|
### How HRW Works
|
||||||
|
|
||||||
|
The Highest Random Weight algorithm combines consistent hashing with weighted load balancing:
|
||||||
|
|
||||||
|
1. **Consistent Hashing**: For each incoming request, the client's remote address is hashed to ensure consistent routing.
|
||||||
|
2. **Weighted Selection**: Each service is assigned a random value based on both the hash of the client IP and the service's weight.
|
||||||
|
3. **Highest Selection**: The service with the highest calculated value receives the request.
|
||||||
|
|
||||||
|
This approach provides several benefits:
|
||||||
|
|
||||||
|
- **Session Affinity**: Clients consistently reach the same backend service
|
||||||
|
- **Weighted Distribution**: Services with higher weights are more likely to be selected
|
||||||
|
- **No State Required**: Unlike sticky cookies, no client-side or server-side state is needed
|
||||||
|
- **Fault Tolerance**: If a service becomes unavailable, requests are redistributed consistently among remaining services
|
||||||
|
|
||||||
## Mirroring
|
## Mirroring
|
||||||
|
|
||||||
The mirroring is able to mirror requests sent to a service to other services.
|
The mirroring is able to mirror requests sent to a service to other services.
|
||||||
|
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:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -1292,11 +1293,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -2791,6 +2793,243 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
description: TraefikServiceSpec defines the desired state of a TraefikService.
|
description: TraefikServiceSpec defines the desired state of a TraefikService.
|
||||||
properties:
|
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:
|
mirroring:
|
||||||
description: Mirroring defines the Mirroring service configuration.
|
description: Mirroring defines the Mirroring service configuration.
|
||||||
properties:
|
properties:
|
||||||
@ -3100,11 +3339,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -3246,11 +3486,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
@ -3479,11 +3720,12 @@ spec:
|
|||||||
strategy:
|
strategy:
|
||||||
description: |-
|
description: |-
|
||||||
Strategy defines the load balancing strategy between the servers.
|
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.
|
RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
enum:
|
enum:
|
||||||
- wrr
|
- wrr
|
||||||
- p2c
|
- p2c
|
||||||
|
- hrw
|
||||||
- RoundRobin
|
- RoundRobin
|
||||||
type: string
|
type: string
|
||||||
weight:
|
weight:
|
||||||
|
@ -28,6 +28,23 @@ spec:
|
|||||||
- name: whoami
|
- name: whoami
|
||||||
port: 80
|
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
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
kind: IngressRoute
|
||||||
@ -47,6 +64,22 @@ spec:
|
|||||||
---
|
---
|
||||||
apiVersion: traefik.io/v1alpha1
|
apiVersion: traefik.io/v1alpha1
|
||||||
kind: IngressRoute
|
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:
|
metadata:
|
||||||
name: api.route
|
name: api.route
|
||||||
namespace: default
|
namespace: default
|
||||||
|
@ -1217,6 +1217,74 @@ func (s *SimpleSuite) TestMirrorCanceled() {
|
|||||||
assert.Equal(s.T(), int32(0), val2)
|
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() {
|
func (s *SimpleSuite) TestSecureAPI() {
|
||||||
s.createComposeProject("base")
|
s.createComposeProject("base")
|
||||||
|
|
||||||
|
36
integration/testdata/rawdata-crd.json
vendored
36
integration/testdata/rawdata-crd.json
vendored
@ -78,6 +78,24 @@
|
|||||||
"web"
|
"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": {
|
"default-testst-route-60ad45fcb5fc1f5f3629@kubernetescrd": {
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
"web"
|
"web"
|
||||||
@ -157,6 +175,24 @@
|
|||||||
"dashboard@internal": {
|
"dashboard@internal": {
|
||||||
"status": "enabled"
|
"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": {
|
"default-mirror1@kubernetescrd": {
|
||||||
"mirroring": {
|
"mirroring": {
|
||||||
"service": "default-whoami-80",
|
"service": "default-whoami-80",
|
||||||
|
@ -259,7 +259,7 @@ const (
|
|||||||
BalancerStrategyWRR BalancerStrategy = "wrr"
|
BalancerStrategyWRR BalancerStrategy = "wrr"
|
||||||
// BalancerStrategyP2C is the power of two choices strategy.
|
// BalancerStrategyP2C is the power of two choices strategy.
|
||||||
BalancerStrategyP2C BalancerStrategy = "p2c"
|
BalancerStrategyP2C BalancerStrategy = "p2c"
|
||||||
// BalancerStrategyHRW is the power of two choices strategy.
|
// BalancerStrategyHRW is the highest random weight strategy.
|
||||||
BalancerStrategyHRW BalancerStrategy = "hrw"
|
BalancerStrategyHRW BalancerStrategy = "hrw"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
---
|
||||||
|
kind: EndpointSlice
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: whoami1-abc
|
||||||
|
namespace: default
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: whoami1
|
||||||
|
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
port: 8080
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- 10.10.0.1
|
||||||
|
- 10.10.0.2
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: whoami1
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
port: 8080
|
||||||
|
selector:
|
||||||
|
app: traefiklabs
|
||||||
|
task: whoami1
|
||||||
|
|
||||||
|
---
|
||||||
|
kind: EndpointSlice
|
||||||
|
apiVersion: discovery.k8s.io/v1
|
||||||
|
metadata:
|
||||||
|
name: whoami2-abc
|
||||||
|
namespace: default
|
||||||
|
labels:
|
||||||
|
kubernetes.io/service-name: whoami2
|
||||||
|
|
||||||
|
addressType: IPv4
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
port: 8080
|
||||||
|
endpoints:
|
||||||
|
- addresses:
|
||||||
|
- 10.10.0.3
|
||||||
|
- 10.10.0.4
|
||||||
|
conditions:
|
||||||
|
ready: true
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: whoami2
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- name: web
|
||||||
|
port: 8080
|
||||||
|
selector:
|
||||||
|
app: traefiklabs
|
||||||
|
task: whoami2
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: TraefikService
|
||||||
|
metadata:
|
||||||
|
name: hrw1
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
highestRandomWeight:
|
||||||
|
services:
|
||||||
|
- name: whoami1
|
||||||
|
kind: Service
|
||||||
|
port: 8080
|
||||||
|
weight: 10
|
||||||
|
- name: whoami2
|
||||||
|
kind: Service
|
||||||
|
port: 8080
|
||||||
|
weight: 20
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: traefik.io/v1alpha1
|
||||||
|
kind: IngressRoute
|
||||||
|
metadata:
|
||||||
|
name: test.route
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
spec:
|
||||||
|
entryPoints:
|
||||||
|
- web
|
||||||
|
|
||||||
|
routes:
|
||||||
|
- match: Host(`foo.com`) && PathPrefix(`/foo`)
|
||||||
|
kind: Rule
|
||||||
|
priority: 12
|
||||||
|
services:
|
||||||
|
- name: hrw1
|
||||||
|
kind: TraefikService
|
@ -216,13 +216,17 @@ type configBuilder struct {
|
|||||||
func (c configBuilder) buildTraefikService(ctx context.Context, tService *traefikv1alpha1.TraefikService, conf map[string]*dynamic.Service) error {
|
func (c configBuilder) buildTraefikService(ctx context.Context, tService *traefikv1alpha1.TraefikService, conf map[string]*dynamic.Service) error {
|
||||||
id := provider.Normalize(makeID(tService.Namespace, tService.Name))
|
id := provider.Normalize(makeID(tService.Namespace, tService.Name))
|
||||||
|
|
||||||
if tService.Spec.Weighted != nil {
|
switch {
|
||||||
|
case tService.Spec.Weighted != nil:
|
||||||
return c.buildServicesLB(ctx, tService.Namespace, tService.Spec, id, conf)
|
return c.buildServicesLB(ctx, tService.Namespace, tService.Spec, id, conf)
|
||||||
} else if tService.Spec.Mirroring != nil {
|
case tService.Spec.Mirroring != nil:
|
||||||
return c.buildMirroring(ctx, tService, id, conf)
|
return c.buildMirroring(ctx, tService, id, conf)
|
||||||
}
|
case tService.Spec.HighestRandomWeight != nil:
|
||||||
|
return c.buildHRW(ctx, tService, id, conf)
|
||||||
|
default:
|
||||||
|
|
||||||
return errors.New("unspecified service type")
|
return errors.New("unspecified service type")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildServicesLB creates the configuration for the load-balancer of services named id, and defined in tService.
|
// buildServicesLB creates the configuration for the load-balancer of services named id, and defined in tService.
|
||||||
@ -329,7 +333,7 @@ func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.Load
|
|||||||
// TODO: remove this when the fake client apply default values.
|
// TODO: remove this when the fake client apply default values.
|
||||||
if svc.Strategy != "" {
|
if svc.Strategy != "" {
|
||||||
switch svc.Strategy {
|
switch svc.Strategy {
|
||||||
case dynamic.BalancerStrategyWRR, dynamic.BalancerStrategyP2C:
|
case dynamic.BalancerStrategyWRR, dynamic.BalancerStrategyP2C, dynamic.BalancerStrategyHRW:
|
||||||
lb.Strategy = svc.Strategy
|
lb.Strategy = svc.Strategy
|
||||||
|
|
||||||
// Here we are just logging a warning as the default value is already applied.
|
// Here we are just logging a warning as the default value is already applied.
|
||||||
@ -644,6 +648,38 @@ func (c configBuilder) nameAndService(ctx context.Context, parentNamespace strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c configBuilder) buildHRW(ctx context.Context, tService *traefikv1alpha1.TraefikService, id string, conf map[string]*dynamic.Service) error {
|
||||||
|
var hrwServices []dynamic.HRWService
|
||||||
|
for _, hrwService := range tService.Spec.HighestRandomWeight.Services {
|
||||||
|
hrwServiceName, k8sService, err := c.nameAndService(ctx, tService.Namespace, hrwService.LoadBalancerSpec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if k8sService != nil {
|
||||||
|
conf[hrwServiceName] = k8sService
|
||||||
|
}
|
||||||
|
|
||||||
|
weight := hrwService.Weight
|
||||||
|
if weight == nil {
|
||||||
|
weight = func(i int) *int { return &i }(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
hrwServices = append(hrwServices, dynamic.HRWService{
|
||||||
|
Name: hrwServiceName,
|
||||||
|
Weight: weight,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
conf[id] = &dynamic.Service{
|
||||||
|
HighestRandomWeight: &dynamic.HighestRandomWeight{
|
||||||
|
Services: hrwServices,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func splitSvcNameProvider(name string) (string, string) {
|
func splitSvcNameProvider(name string) (string, string) {
|
||||||
parts := strings.Split(name, providerNamespaceSeparator)
|
parts := strings.Split(name, providerNamespaceSeparator)
|
||||||
|
|
||||||
|
@ -3150,6 +3150,79 @@ func TestLoadIngressRoutes(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
desc: "one kube services in a highest random weight",
|
||||||
|
paths: []string{"with_highest_random_weight.yml"},
|
||||||
|
expected: &dynamic.Configuration{
|
||||||
|
UDP: &dynamic.UDPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.UDPRouter{},
|
||||||
|
Services: map[string]*dynamic.UDPService{},
|
||||||
|
},
|
||||||
|
TLS: &dynamic.TLSConfiguration{},
|
||||||
|
TCP: &dynamic.TCPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.TCPRouter{},
|
||||||
|
Middlewares: map[string]*dynamic.TCPMiddleware{},
|
||||||
|
Services: map[string]*dynamic.TCPService{},
|
||||||
|
ServersTransports: map[string]*dynamic.TCPServersTransport{},
|
||||||
|
},
|
||||||
|
HTTP: &dynamic.HTTPConfiguration{
|
||||||
|
Routers: map[string]*dynamic.Router{
|
||||||
|
"default-test-route-77c62dfe9517144aeeaa": {
|
||||||
|
EntryPoints: []string{"web"},
|
||||||
|
Service: "default-hrw1",
|
||||||
|
Rule: "Host(`foo.com`) && PathPrefix(`/foo`)",
|
||||||
|
Priority: 12,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Middlewares: map[string]*dynamic.Middleware{},
|
||||||
|
Services: map[string]*dynamic.Service{
|
||||||
|
"default-hrw1": {
|
||||||
|
HighestRandomWeight: &dynamic.HighestRandomWeight{
|
||||||
|
Services: []dynamic.HRWService{
|
||||||
|
{Name: "default-whoami1-8080", Weight: pointer(10)},
|
||||||
|
{Name: "default-whoami2-8080", Weight: pointer(20)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"default-whoami1-8080": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Strategy: dynamic.BalancerStrategyWRR,
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.1:8080",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.2:8080",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: pointer(true),
|
||||||
|
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||||
|
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"default-whoami2-8080": {
|
||||||
|
LoadBalancer: &dynamic.ServersLoadBalancer{
|
||||||
|
Strategy: dynamic.BalancerStrategyWRR,
|
||||||
|
Servers: []dynamic.Server{
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.3:8080",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
URL: "http://10.10.0.4:8080",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PassHostHeader: pointer(true),
|
||||||
|
ResponseForwarding: &dynamic.ResponseForwarding{
|
||||||
|
FlushInterval: ptypes.Duration(100 * time.Millisecond),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ServersTransports: map[string]*dynamic.ServersTransport{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
desc: "One ingress Route with two different services, with weights",
|
desc: "One ingress Route with two different services, with weights",
|
||||||
paths: []string{"services.yml", "with_two_services_weight.yml"},
|
paths: []string{"services.yml", "with_two_services_weight.yml"},
|
||||||
|
@ -114,10 +114,10 @@ type LoadBalancerSpec struct {
|
|||||||
// It defaults to https when Kubernetes Service port is 443, http otherwise.
|
// It defaults to https when Kubernetes Service port is 443, http otherwise.
|
||||||
Scheme string `json:"scheme,omitempty"`
|
Scheme string `json:"scheme,omitempty"`
|
||||||
// Strategy defines the load balancing strategy between the servers.
|
// 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.
|
// RoundRobin value is deprecated and supported for backward compatibility.
|
||||||
// TODO: when the deprecated RoundRobin value will be removed, set the default value to wrr.
|
// TODO: when the deprecated RoundRobin value will be removed, set the default value to wrr.
|
||||||
// +kubebuilder:validation:Enum=wrr;p2c;RoundRobin
|
// +kubebuilder:validation:Enum=wrr;p2c;hrw;RoundRobin
|
||||||
Strategy dynamic.BalancerStrategy `json:"strategy,omitempty"`
|
Strategy dynamic.BalancerStrategy `json:"strategy,omitempty"`
|
||||||
// PassHostHeader defines whether the client Host header is forwarded to the upstream Kubernetes Service.
|
// PassHostHeader defines whether the client Host header is forwarded to the upstream Kubernetes Service.
|
||||||
// By default, passHostHeader is true.
|
// By default, passHostHeader is true.
|
||||||
|
@ -44,6 +44,8 @@ type TraefikServiceSpec struct {
|
|||||||
Weighted *WeightedRoundRobin `json:"weighted,omitempty"`
|
Weighted *WeightedRoundRobin `json:"weighted,omitempty"`
|
||||||
// Mirroring defines the Mirroring service configuration.
|
// Mirroring defines the Mirroring service configuration.
|
||||||
Mirroring *Mirroring `json:"mirroring,omitempty"`
|
Mirroring *Mirroring `json:"mirroring,omitempty"`
|
||||||
|
// HighestRandomWeight defines the highest random weight service configuration.
|
||||||
|
HighestRandomWeight *HighestRandomWeight `json:"highestRandomWeight,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
@ -86,3 +88,12 @@ type WeightedRoundRobin struct {
|
|||||||
// More info: https://doc.traefik.io/traefik/v3.5/routing/providers/kubernetes-crd/#stickiness-and-load-balancing
|
// More info: https://doc.traefik.io/traefik/v3.5/routing/providers/kubernetes-crd/#stickiness-and-load-balancing
|
||||||
Sticky *dynamic.Sticky `json:"sticky,omitempty"`
|
Sticky *dynamic.Sticky `json:"sticky,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
||||||
|
// HighestRandomWeight holds the highest random weight configuration.
|
||||||
|
// More info: https://doc.traefik.io/traefik/v3.5/routing/services/#highest-random-configuration
|
||||||
|
type HighestRandomWeight struct {
|
||||||
|
// Services defines the list of Kubernetes Service and/or TraefikService to load-balance, with weight.
|
||||||
|
Services []Service `json:"services,omitempty"`
|
||||||
|
}
|
||||||
|
@ -349,6 +349,29 @@ func (in *ForwardingTimeouts) DeepCopy() *ForwardingTimeouts {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
|
func (in *HighestRandomWeight) DeepCopyInto(out *HighestRandomWeight) {
|
||||||
|
*out = *in
|
||||||
|
if in.Services != nil {
|
||||||
|
in, out := &in.Services, &out.Services
|
||||||
|
*out = make([]Service, len(*in))
|
||||||
|
for i := range *in {
|
||||||
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HighestRandomWeight.
|
||||||
|
func (in *HighestRandomWeight) DeepCopy() *HighestRandomWeight {
|
||||||
|
if in == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := new(HighestRandomWeight)
|
||||||
|
in.DeepCopyInto(out)
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||||
func (in *IngressRoute) DeepCopyInto(out *IngressRoute) {
|
func (in *IngressRoute) DeepCopyInto(out *IngressRoute) {
|
||||||
*out = *in
|
*out = *in
|
||||||
@ -2028,6 +2051,11 @@ func (in *TraefikServiceSpec) DeepCopyInto(out *TraefikServiceSpec) {
|
|||||||
*out = new(Mirroring)
|
*out = new(Mirroring)
|
||||||
(*in).DeepCopyInto(*out)
|
(*in).DeepCopyInto(*out)
|
||||||
}
|
}
|
||||||
|
if in.HighestRandomWeight != nil {
|
||||||
|
in, out := &in.HighestRandomWeight, &out.HighestRandomWeight
|
||||||
|
*out = new(HighestRandomWeight)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user