1
0
Fork 0

Native Kubernetes service load-balancing at the provider level

This commit is contained in:
Prajith 2024-04-29 15:50:04 +05:30 committed by GitHub
parent 73e5dbbfe5
commit 8d2a2ff08f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
23 changed files with 642 additions and 50 deletions

View file

@ -45,7 +45,7 @@ type ServiceIng struct {
ServersTransport string `json:"serversTransport,omitempty"`
PassHostHeader *bool `json:"passHostHeader"`
Sticky *dynamic.Sticky `json:"sticky,omitempty" label:"allowEmpty"`
NativeLB bool `json:"nativeLB,omitempty"`
NativeLB *bool `json:"nativeLB,omitempty"`
}
// SetDefaults sets the default values.

View file

@ -125,7 +125,7 @@ func Test_parseServiceConfig(t *testing.T) {
ServersScheme: "protocol",
ServersTransport: "foobar@file",
PassHostHeader: Bool(true),
NativeLB: true,
NativeLB: Bool(true),
},
},
},

View file

@ -0,0 +1,30 @@
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: global-native-lb
namespace: default
spec:
rules:
- host: traefik.tchouk
http:
paths:
- path: /bar
backend:
service:
name: service1
port:
number: 8080
pathType: Prefix
---
kind: Service
apiVersion: v1
metadata:
name: service1
namespace: default
spec:
ports:
- port: 8080
clusterIP: 10.0.0.1
type: ClusterIP
externalName: traefik.wtf

View file

@ -52,6 +52,7 @@ type Provider struct {
AllowEmptyServices bool `description:"Allow creation of services without endpoints." json:"allowEmptyServices,omitempty" toml:"allowEmptyServices,omitempty" yaml:"allowEmptyServices,omitempty" export:"true"`
AllowExternalNameServices bool `description:"Allow ExternalName services." json:"allowExternalNameServices,omitempty" toml:"allowExternalNameServices,omitempty" yaml:"allowExternalNameServices,omitempty" export:"true"`
DisableIngressClassLookup bool `description:"Disables the lookup of IngressClasses." json:"disableIngressClassLookup,omitempty" toml:"disableIngressClassLookup,omitempty" yaml:"disableIngressClassLookup,omitempty" export:"true"`
NativeLBByDefault bool `description:"Defines whether to use Native Kubernetes load-balancing mode by default." json:"nativeLBByDefault,omitempty" toml:"nativeLBByDefault,omitempty" yaml:"nativeLBByDefault,omitempty" export:"true"`
lastConfiguration safe.Safe
@ -571,6 +572,8 @@ func (p *Provider) loadService(client Client, namespace string, backend netv1.In
return nil, err
}
nativeLB := p.NativeLBByDefault
if svcConfig != nil && svcConfig.Service != nil {
svc.LoadBalancer.Sticky = svcConfig.Service.Sticky
@ -582,19 +585,8 @@ func (p *Provider) loadService(client Client, namespace string, backend netv1.In
svc.LoadBalancer.ServersTransport = svcConfig.Service.ServersTransport
}
if svcConfig.Service.NativeLB {
address, err := getNativeServiceAddress(*service, portSpec)
if err != nil {
return nil, fmt.Errorf("getting native Kubernetes Service address: %w", err)
}
protocol := getProtocol(portSpec, portSpec.Name, svcConfig)
svc.LoadBalancer.Servers = []dynamic.Server{
{URL: fmt.Sprintf("%s://%s", protocol, address)},
}
return svc, nil
if svcConfig.Service.NativeLB != nil {
nativeLB = *svcConfig.Service.NativeLB
}
}
@ -609,6 +601,20 @@ func (p *Provider) loadService(client Client, namespace string, backend netv1.In
return svc, nil
}
if nativeLB {
address, err := getNativeServiceAddress(*service, portSpec)
if err != nil {
return nil, fmt.Errorf("getting native Kubernetes Service address: %w", err)
}
protocol := getProtocol(portSpec, portSpec.Name, svcConfig)
svc.LoadBalancer.Servers = []dynamic.Server{
{URL: fmt.Sprintf("%s://%s", protocol, address)},
}
return svc, nil
}
endpoints, endpointsExists, endpointsErr := client.GetEndpoints(namespace, backend.Service.Name)
if endpointsErr != nil {
return nil, endpointsErr

View file

@ -1864,3 +1864,84 @@ func TestGetCertificates(t *testing.T) {
})
}
}
func TestLoadConfigurationFromIngressesWithNativeLBByDefault(t *testing.T) {
testCases := []struct {
desc string
ingressClass string
expected *dynamic.Configuration
}{
{
desc: "Ingress with native service lb",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"testing-traefik-tchouk-bar": {
Rule: "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
Service: "testing-service1-8080",
},
},
Services: map[string]*dynamic.Service{
"testing-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.0.0.1:8080",
},
},
},
},
},
},
},
},
{
desc: "Ingress with native lb by default",
expected: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{},
HTTP: &dynamic.HTTPConfiguration{
Middlewares: map[string]*dynamic.Middleware{},
Routers: map[string]*dynamic.Router{
"default-global-native-lb-traefik-tchouk-bar": {
Rule: "Host(`traefik.tchouk`) && PathPrefix(`/bar`)",
Service: "default-service1-8080",
},
},
Services: map[string]*dynamic.Service{
"default-service1-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
ResponseForwarding: &dynamic.ResponseForwarding{FlushInterval: dynamic.DefaultFlushInterval},
PassHostHeader: Bool(true),
Servers: []dynamic.Server{
{
URL: "http://10.0.0.1:8080",
},
},
},
},
},
},
},
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
clientMock := newClientMock(generateTestFilename(test.desc))
p := Provider{
IngressClass: test.ingressClass,
NativeLBByDefault: true,
}
conf := p.loadConfigurationFromIngresses(context.Background(), clientMock)
assert.Equal(t, test.expected, conf)
})
}
}