[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 {
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,
}
}
}

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{
{
@ -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",
},
},
},
},
}

View file

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