From 24d9aada1171d8f2cca163c37fdb797b69002731 Mon Sep 17 00:00:00 2001 From: bprashanth Date: Wed, 8 Feb 2017 13:54:27 -0800 Subject: [PATCH] Set balancing mode --- controllers/gce/backends/backends.go | 77 +++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/controllers/gce/backends/backends.go b/controllers/gce/backends/backends.go index 18686b968..3f2e9ca35 100644 --- a/controllers/gce/backends/backends.go +++ b/controllers/gce/backends/backends.go @@ -20,6 +20,7 @@ import ( "fmt" "net/http" "strconv" + "strings" "time" "k8s.io/kubernetes/pkg/util/sets" @@ -32,6 +33,41 @@ import ( "k8s.io/ingress/controllers/gce/utils" ) +// BalancingMode represents the loadbalancing configuration of an individual +// Backend in a BackendService. This is *effectively* a cluster wide setting +// since you can't mix modes across Backends pointing to the same IG, and you +// can't have a single node in more than 1 loadbalanced IG. +type BalancingMode string + +const ( + // Rate balances incoming requests based on observed RPS. + // As of this writing, it's the only balancing mode supported by GCE's + // internal LB. This setting doesn't make sense for Kubernets clusters + // because requests can get proxied between instance groups in different + // zones by kube-proxy without GCE even knowing it. Setting equal RPS on + // all IGs should achieve roughly equal distribution of requests. + Rate BalancingMode = "RATE" + // Utilization balances incoming requests based on observed utilization. + // This mode is only useful if you want to divert traffic away from IGs + // running other compute intensive workloads. Utilization statistics are + // aggregated per instances, not per container, and requests can get proxied + // between instance groups in different zones by kube-proxy without GCE even + // knowing about it. + Utilization BalancingMode = "UTILIZATION" + // Connections balances incoming requests based on a connection counter. + // This setting currently doesn't make sense for Kubernetes clusters, + // because we use NodePort Services as HTTP LB backends, so GCE's connection + // counters don't accurately represent connections per container. + Connections BalancingMode = "CONNECTION" +) + +// maxRPS is the RPS setting for all Backends with BalancingMode RATE. The exact +// value doesn't matter, as long as it's the same for all Backends. Requests +// received by GCLB above this RPS are NOT dropped, GCLB continues to distribute +// them across IGs. +// TODO: Should this be math.MaxInt64? +const maxRPS = 1 + // Backends implements BackendPool. type Backends struct { cloud BackendServices @@ -116,20 +152,35 @@ func (b *Backends) create(igs []*compute.InstanceGroup, namedPort *compute.Named if err != nil { return nil, err } - // Create a new backend - backend := &compute.BackendService{ - Name: name, - Protocol: "HTTP", - Backends: getBackendsForIGs(igs), - // Api expects one, means little to kubernetes. - HealthChecks: []string{hc.SelfLink}, - Port: namedPort.Port, - PortName: namedPort.Name, + errs := []string{} + for _, bm := range []BalancingMode{Rate, Utilization} { + backends := getBackendsForIGs(igs) + for _, b := range backends { + switch bm { + case Rate: + b.MaxRate = maxRPS + default: + // TODO: Set utilization and connection limits when we accept them + // as valid fields. + } + b.BalancingMode = string(bm) + } + // Create a new backend + backend := &compute.BackendService{ + Name: name, + Protocol: "HTTP", + Backends: backends, + HealthChecks: []string{hc.SelfLink}, + Port: namedPort.Port, + PortName: namedPort.Name, + } + if err := b.cloud.CreateBackendService(backend); err != nil { + glog.Infof("Error creating backend service with balancing mode %v", bm) + errs = append(errs, fmt.Sprintf("%v", err)) + } + return b.Get(namedPort.Port) } - if err := b.cloud.CreateBackendService(backend); err != nil { - return nil, err - } - return b.Get(namedPort.Port) + return nil, fmt.Errorf("%v", strings.Join(errs, "\n")) } // Add will get or create a Backend for the given port.