Adding support for TopologyAwareHints to kube-proxy

This commit is contained in:
Rob Scott
2021-03-05 12:06:07 -08:00
parent 1dcf09c1bf
commit f07be06a19
12 changed files with 545 additions and 133 deletions

View File

@@ -19,11 +19,80 @@ package proxy
import (
v1 "k8s.io/api/core/v1"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog/v2"
"k8s.io/kubernetes/pkg/features"
)
// FilterTopologyEndpoint returns the appropriate endpoints based on the cluster
// topology.
// FilterEndpoints filters endpoints based on Service configuration, node
// labels, and enabled feature gates. This is primarily used to enable topology
// aware routing.
func FilterEndpoints(endpoints []Endpoint, svcInfo ServicePort, nodeLabels map[string]string) []Endpoint {
if svcInfo.NodeLocalExternal() || !utilfeature.DefaultFeatureGate.Enabled(features.EndpointSliceProxying) {
return endpoints
}
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceTopology) {
return deprecatedTopologyFilter(nodeLabels, svcInfo.TopologyKeys(), endpoints)
}
if utilfeature.DefaultFeatureGate.Enabled(features.ServiceInternalTrafficPolicy) && svcInfo.NodeLocalInternal() {
return filterEndpointsInternalTrafficPolicy(svcInfo.InternalTrafficPolicy(), endpoints)
}
if utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints) {
return filterEndpointsWithHints(endpoints, svcInfo.HintsAnnotation(), nodeLabels)
}
return endpoints
}
// filterEndpointsWithHints provides filtering based on the hints included in
// EndpointSlices. If any of the following are true, the full list of endpoints
// will be returned without any filtering:
// * The AnnotationTopologyAwareHints annotation is not set to "auto" for this
// Service.
// * No zone is specified in node labels.
// * No endpoints for this Service have a hint pointing to the zone this
// instance of kube-proxy is running in.
// * One or more endpoints for this Service do not have hints specified.
func filterEndpointsWithHints(endpoints []Endpoint, hintsAnnotation string, nodeLabels map[string]string) []Endpoint {
if hintsAnnotation != "auto" {
if hintsAnnotation != "" && hintsAnnotation != "disabled" {
klog.Warningf("Skipping topology aware endpoint filtering since Service has unexpected value for %s annotation: %s", v1.AnnotationTopologyAwareHints, hintsAnnotation)
}
return endpoints
}
zone, ok := nodeLabels[v1.LabelTopologyZone]
if !ok || zone == "" {
klog.Warningf("Skipping topology aware endpoint filtering since node is missing %s label", v1.LabelTopologyZone)
return endpoints
}
filteredEndpoints := []Endpoint{}
for _, endpoint := range endpoints {
if endpoint.GetZoneHints().Len() == 0 {
klog.Warningf("Skipping topology aware endpoint filtering since one or more endpoints is missing a zone hint")
return endpoints
}
if endpoint.GetZoneHints().Has(zone) {
filteredEndpoints = append(filteredEndpoints, endpoint)
}
}
if len(filteredEndpoints) > 0 {
klog.Warningf("Skipping topology aware endpoint filtering since no hints were provided for zone %s", zone)
return filteredEndpoints
}
return endpoints
}
// deprecatedTopologyFilter returns the appropriate endpoints based on the
// cluster topology. This will be removed in an upcoming release along with the
// ServiceTopology feature gate.
//
// This uses the current node's labels, which contain topology information, and
// the required topologyKeys to find appropriate endpoints. If both the endpoint's
// topology and the current node have matching values for topologyKeys[0], the
@@ -40,7 +109,7 @@ import (
//
// If topologyKeys is not specified or empty, no topology constraints will be
// applied and this will return all endpoints.
func FilterTopologyEndpoint(nodeLabels map[string]string, topologyKeys []string, endpoints []Endpoint) []Endpoint {
func deprecatedTopologyFilter(nodeLabels map[string]string, topologyKeys []string, endpoints []Endpoint) []Endpoint {
// Do not filter endpoints if service has no topology keys.
if len(topologyKeys) == 0 {
return endpoints
@@ -81,13 +150,13 @@ func FilterTopologyEndpoint(nodeLabels map[string]string, topologyKeys []string,
return filteredEndpoints
}
// FilterLocalEndpoint returns the node local endpoints based on configured
// InternalTrafficPolicy.
// filterEndpointsInternalTrafficPolicy returns the node local endpoints based
// on configured InternalTrafficPolicy.
//
// If ServiceInternalTrafficPolicy feature gate is off, returns the original
// endpoints slice.
// EndpointSlice.
// Otherwise, if InternalTrafficPolicy is Local, only return the node local endpoints.
func FilterLocalEndpoint(internalTrafficPolicy *v1.ServiceInternalTrafficPolicyType, endpoints []Endpoint) []Endpoint {
func filterEndpointsInternalTrafficPolicy(internalTrafficPolicy *v1.ServiceInternalTrafficPolicyType, endpoints []Endpoint) []Endpoint {
if !utilfeature.DefaultFeatureGate.Enabled(features.ServiceInternalTrafficPolicy) {
return endpoints
}