[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.
This commit is contained in:
Timo Reimann 2017-05-15 23:16:35 +02:00
parent b392023c37
commit 9967494996
3 changed files with 72 additions and 19 deletions

View file

@ -252,28 +252,25 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
} }
if !exists { if !exists {
log.Errorf("Endpoints not found for %s/%s", service.ObjectMeta.Namespace, service.ObjectMeta.Name) log.Warnf("Endpoints not found for %s/%s", service.ObjectMeta.Namespace, service.ObjectMeta.Name)
continue break
} }
if len(endpoints.Subsets) == 0 { 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) log.Warnf("Endpoints not available for %s/%s", service.ObjectMeta.Namespace, service.ObjectMeta.Name)
templateObjects.Backends[r.Host+pa.Path].Servers[string(service.UID)] = types.Server{ break
URL: protocol + "://" + service.Spec.ClusterIP + ":" + strconv.Itoa(int(port.Port)), }
Weight: 1,
} for _, subset := range endpoints.Subsets {
} else { for _, address := range subset.Addresses {
for _, subset := range endpoints.Subsets { url := protocol + "://" + address.IP + ":" + strconv.Itoa(endpointPortNumber(port, subset.Ports))
for _, address := range subset.Addresses { name := url
url := protocol + "://" + address.IP + ":" + strconv.Itoa(endpointPortNumber(port, subset.Ports)) if address.TargetRef != nil && address.TargetRef.Name != "" {
name := url name = address.TargetRef.Name
if address.TargetRef != nil && address.TargetRef.Name != "" { }
name = address.TargetRef.Name templateObjects.Backends[r.Host+pa.Path].Servers[name] = types.Server{
} URL: url,
templateObjects.Backends[r.Host+pa.Path].Servers[name] = types.Server{ Weight: 1,
URL: url,
Weight: 1,
}
} }
} }
} }

View file

@ -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{ 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{}) watchChan := make(chan interface{})
@ -2016,6 +2054,14 @@ func TestMissingResources(t *testing.T) {
Sticky: false, Sticky: false,
}, },
}, },
"missing_endpoint_subsets": {
Servers: map[string]types.Server{},
CircuitBreaker: nil,
LoadBalancer: &types.LoadBalancer{
Method: "wrr",
Sticky: false,
},
},
}, },
Frontends: map[string]*types.Frontend{ Frontends: map[string]*types.Frontend{
"fully_working": { "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",
},
},
},
}, },
} }

View file

@ -1,4 +1,5 @@
[backends]{{range $backendName, $backend := .Backends}} [backends]{{range $backendName, $backend := .Backends}}
[backends."{{$backendName}}"]
{{if $backend.CircuitBreaker}} {{if $backend.CircuitBreaker}}
[backends."{{$backendName}}".circuitbreaker] [backends."{{$backendName}}".circuitbreaker]
expression = "{{$backend.CircuitBreaker.Expression}}" expression = "{{$backend.CircuitBreaker.Expression}}"