From 9967494996d47b7ab88a2d7783e5c0bb9a5a5261 Mon Sep 17 00:00:00 2001 From: Timo Reimann Date: Mon, 15 May 2017 23:16:35 +0200 Subject: [PATCH] [k8s] Ignore Ingresses with empty Endpoint subsets. We previously fell back to using ClusterIPs. However, the approach can lead to all kinds of problems since Ingresses rely on being able to talk to Endpoints directly. For instance, it can break stickiness and retries. --- provider/kubernetes/kubernetes.go | 35 ++++++++-------- provider/kubernetes/kubernetes_test.go | 55 ++++++++++++++++++++++++++ templates/kubernetes.tmpl | 1 + 3 files changed, 72 insertions(+), 19 deletions(-) diff --git a/provider/kubernetes/kubernetes.go b/provider/kubernetes/kubernetes.go index 1d81c736a..6af976536 100644 --- a/provider/kubernetes/kubernetes.go +++ b/provider/kubernetes/kubernetes.go @@ -252,28 +252,25 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error) } if !exists { - log.Errorf("Endpoints not found for %s/%s", service.ObjectMeta.Namespace, service.ObjectMeta.Name) - continue + log.Warnf("Endpoints not found for %s/%s", service.ObjectMeta.Namespace, service.ObjectMeta.Name) + break } if len(endpoints.Subsets) == 0 { - log.Warnf("Service endpoints not found for %s/%s, falling back to Service ClusterIP", service.ObjectMeta.Namespace, service.ObjectMeta.Name) - templateObjects.Backends[r.Host+pa.Path].Servers[string(service.UID)] = types.Server{ - URL: protocol + "://" + service.Spec.ClusterIP + ":" + strconv.Itoa(int(port.Port)), - Weight: 1, - } - } else { - for _, subset := range endpoints.Subsets { - for _, address := range subset.Addresses { - url := protocol + "://" + address.IP + ":" + strconv.Itoa(endpointPortNumber(port, subset.Ports)) - name := url - if address.TargetRef != nil && address.TargetRef.Name != "" { - name = address.TargetRef.Name - } - templateObjects.Backends[r.Host+pa.Path].Servers[name] = types.Server{ - URL: url, - Weight: 1, - } + log.Warnf("Endpoints not available for %s/%s", service.ObjectMeta.Namespace, service.ObjectMeta.Name) + break + } + + for _, subset := range endpoints.Subsets { + for _, address := range subset.Addresses { + url := protocol + "://" + address.IP + ":" + strconv.Itoa(endpointPortNumber(port, subset.Ports)) + name := url + if address.TargetRef != nil && address.TargetRef.Name != "" { + name = address.TargetRef.Name + } + templateObjects.Backends[r.Host+pa.Path].Servers[name] = types.Server{ + URL: url, + Weight: 1, } } } diff --git a/provider/kubernetes/kubernetes_test.go b/provider/kubernetes/kubernetes_test.go index 02ffa5405..1fda8af55 100644 --- a/provider/kubernetes/kubernetes_test.go +++ b/provider/kubernetes/kubernetes_test.go @@ -1913,6 +1913,21 @@ func TestMissingResources(t *testing.T) { }, }, }, + { + Host: "missing_endpoint_subsets", + IngressRuleValue: v1beta1.IngressRuleValue{ + HTTP: &v1beta1.HTTPIngressRuleValue{ + Paths: []v1beta1.HTTPIngressPath{ + { + Backend: v1beta1.IngressBackend{ + ServiceName: "missing_endpoint_subsets_service", + ServicePort: intstr.FromInt(80), + }, + }, + }, + }, + }, + }, }, }, }} @@ -1947,6 +1962,21 @@ func TestMissingResources(t *testing.T) { }, }, }, + { + ObjectMeta: v1.ObjectMeta{ + Name: "missing_endpoint_subsets_service", + UID: "4", + Namespace: "testing", + }, + Spec: v1.ServiceSpec{ + ClusterIP: "10.0.0.4", + Ports: []v1.ServicePort{ + { + Port: 80, + }, + }, + }, + }, } endpoints := []*v1.Endpoints{ { @@ -1970,6 +2000,14 @@ func TestMissingResources(t *testing.T) { }, }, }, + { + ObjectMeta: v1.ObjectMeta{ + Name: "missing_endpoint_subsets_service", + UID: "4", + Namespace: "testing", + }, + Subsets: []v1.EndpointSubset{}, + }, } watchChan := make(chan interface{}) @@ -2016,6 +2054,14 @@ func TestMissingResources(t *testing.T) { Sticky: false, }, }, + "missing_endpoint_subsets": { + Servers: map[string]types.Server{}, + CircuitBreaker: nil, + LoadBalancer: &types.LoadBalancer{ + Method: "wrr", + Sticky: false, + }, + }, }, Frontends: map[string]*types.Frontend{ "fully_working": { @@ -2036,6 +2082,15 @@ func TestMissingResources(t *testing.T) { }, }, }, + "missing_endpoint_subsets": { + Backend: "missing_endpoint_subsets", + PassHostHeader: true, + Routes: map[string]types.Route{ + "missing_endpoint_subsets": { + Rule: "Host:missing_endpoint_subsets", + }, + }, + }, }, } diff --git a/templates/kubernetes.tmpl b/templates/kubernetes.tmpl index d11a34b61..c0d9a7657 100644 --- a/templates/kubernetes.tmpl +++ b/templates/kubernetes.tmpl @@ -1,4 +1,5 @@ [backends]{{range $backendName, $backend := .Backends}} + [backends."{{$backendName}}"] {{if $backend.CircuitBreaker}} [backends."{{$backendName}}".circuitbreaker] expression = "{{$backend.CircuitBreaker.Expression}}"