Introducing Topology Mode Annotation, Deprecating Topology Hints

Annotation

As part of this change, kube-proxy accepts any value for either
annotation that is not "disabled".

Change-Id: Idfc26eb4cc97ff062649dc52ed29823a64fc59a4
This commit is contained in:
Rob Scott 2023-03-13 06:21:32 +00:00
parent 16bc942a6b
commit e23af041f5
No known key found for this signature in database
10 changed files with 116 additions and 32 deletions

View File

@ -122,8 +122,24 @@ const (
// This annotation is beta-level and is only honored when PodDeletionCost feature is enabled.
PodDeletionCost = "controller.kubernetes.io/pod-deletion-cost"
// AnnotationTopologyAwareHints can be used to enable or disable Topology
// Aware Hints for a Service. This may be set to "Auto" or "Disabled". Any
// other value is treated as "Disabled".
AnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints"
// DeprecatedAnnotationTopologyAwareHints can be used to enable or disable
// Topology Aware Hints for a Service. This may be set to "Auto" or
// "Disabled". Any other value is treated as "Disabled". This annotation has
// been deprecated in favor of the `service.kubernetes.io/topology-mode`
// annotation which also allows "Auto" and "Disabled", but is not limited to
// those (it's open ended to provide room for experimentation while we
// pursue configuration for topology via specification). When both
// `service.kubernetes.io/topology-aware-hints` and
// `service.kubernetes.io/topology-mode` annotations are set, the value of
// `service.kubernetes.io/topology-aware-hints` has precedence.
DeprecatedAnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints"
// AnnotationTopologyMode can be used to enable or disable Topology Aware
// Routing for a Service. Well known values are "Auto" and "Disabled".
// Implementations may choose to develop new topology approaches, exposing
// them with domain-prefixed values. For example, "example.com/lowest-rtt"
// could be a valid implementation-specific value for this annotation. These
// heuristics will often populate topology hints on EndpointSlices, but that
// is not a requirement.
AnnotationTopologyMode = "service.kubernetes.io/topology-mode"
)

View File

@ -1843,7 +1843,7 @@ func TestReconcileTopology(t *testing.T) {
service := svc.DeepCopy()
service.Annotations = map[string]string{
corev1.AnnotationTopologyAwareHints: tc.hintsAnnotation,
corev1.DeprecatedAnnotationTopologyAwareHints: tc.hintsAnnotation,
}
r.reconcile(service, tc.pods, tc.existingSlices, time.Now())

View File

@ -378,12 +378,17 @@ func unchangedSlices(existingSlices, slicesToUpdate, slicesToDelete []*discovery
return unchangedSlices
}
// hintsEnabled returns true if the provided annotations include a
// v1.AnnotationTopologyAwareHints key with a value set to "Auto" or "auto".
// hintsEnabled returns true if the provided annotations include either
// v1.AnnotationTopologyMode or v1.DeprecatedAnnotationTopologyAwareHints key
// with a value set to "Auto" or "auto". When both are set,
// v1.DeprecatedAnnotationTopologyAwareHints has precedence.
func hintsEnabled(annotations map[string]string) bool {
val, ok := annotations[v1.AnnotationTopologyAwareHints]
val, ok := annotations[v1.DeprecatedAnnotationTopologyAwareHints]
if !ok {
return false
val, ok = annotations[v1.AnnotationTopologyMode]
if !ok {
return false
}
}
return val == "Auto" || val == "auto"
}

View File

@ -1149,24 +1149,72 @@ func Test_hintsEnabled(t *testing.T) {
annotations: map[string]string{"topology-hints": "enabled"},
expectEnabled: false,
}, {
name: "annotation == enabled",
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "enabled"},
name: "hints annotation == enabled",
annotations: map[string]string{v1.DeprecatedAnnotationTopologyAwareHints: "enabled"},
expectEnabled: false,
}, {
name: "annotation == aUto",
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "aUto"},
name: "hints annotation == aUto",
annotations: map[string]string{v1.DeprecatedAnnotationTopologyAwareHints: "aUto"},
expectEnabled: false,
}, {
name: "annotation == auto",
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "auto"},
name: "hints annotation == auto",
annotations: map[string]string{v1.DeprecatedAnnotationTopologyAwareHints: "auto"},
expectEnabled: true,
}, {
name: "annotation == Auto",
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "Auto"},
name: "hints annotation == Auto",
annotations: map[string]string{v1.DeprecatedAnnotationTopologyAwareHints: "Auto"},
expectEnabled: true,
}, {
name: "annotation == disabled",
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "disabled"},
name: "hints annotation == disabled",
annotations: map[string]string{v1.DeprecatedAnnotationTopologyAwareHints: "disabled"},
expectEnabled: false,
}, {
name: "mode annotation == enabled",
annotations: map[string]string{v1.AnnotationTopologyMode: "enabled"},
expectEnabled: false,
}, {
name: "mode annotation == aUto",
annotations: map[string]string{v1.AnnotationTopologyMode: "aUto"},
expectEnabled: false,
}, {
name: "mode annotation == auto",
annotations: map[string]string{v1.AnnotationTopologyMode: "auto"},
expectEnabled: true,
}, {
name: "mode annotation == Auto",
annotations: map[string]string{v1.AnnotationTopologyMode: "Auto"},
expectEnabled: true,
}, {
name: "mode annotation == disabled",
annotations: map[string]string{v1.AnnotationTopologyMode: "disabled"},
expectEnabled: false,
}, {
name: "mode annotation == enabled",
annotations: map[string]string{v1.AnnotationTopologyMode: "enabled"},
expectEnabled: false,
}, {
name: "mode annotation == aUto",
annotations: map[string]string{v1.AnnotationTopologyMode: "aUto"},
expectEnabled: false,
}, {
name: "mode annotation == auto",
annotations: map[string]string{v1.AnnotationTopologyMode: "auto"},
expectEnabled: true,
}, {
name: "mode annotation == Auto",
annotations: map[string]string{v1.AnnotationTopologyMode: "Auto"},
expectEnabled: true,
}, {
name: "mode annotation == disabled",
annotations: map[string]string{v1.AnnotationTopologyMode: "disabled"},
expectEnabled: false,
}, {
name: "mode annotation == disabled, hints annotation == auto",
annotations: map[string]string{v1.AnnotationTopologyMode: "disabled", v1.DeprecatedAnnotationTopologyAwareHints: "auto"},
expectEnabled: true,
}, {
name: "mode annotation == auto, hints annotation == disabled",
annotations: map[string]string{v1.AnnotationTopologyMode: "auto", v1.DeprecatedAnnotationTopologyAwareHints: "disabled"},
expectEnabled: false,
}}
for _, tc := range testCases {

View File

@ -176,7 +176,13 @@ func (sct *ServiceChangeTracker) newBaseServiceInfo(port *v1.ServicePort, servic
externalPolicyLocal: externalPolicyLocal,
internalPolicyLocal: internalPolicyLocal,
internalTrafficPolicy: service.Spec.InternalTrafficPolicy,
hintsAnnotation: service.Annotations[v1.AnnotationTopologyAwareHints],
}
// v1.DeprecatedAnnotationTopologyAwareHints has precedence over v1.AnnotationTopologyMode.
var ok bool
info.hintsAnnotation, ok = service.Annotations[v1.DeprecatedAnnotationTopologyAwareHints]
if !ok {
info.hintsAnnotation, _ = service.Annotations[v1.AnnotationTopologyMode]
}
loadBalancerSourceRanges := make([]string, len(service.Spec.LoadBalancerSourceRanges))

View File

@ -148,11 +148,9 @@ func canUseTopology(endpoints []Endpoint, svcInfo ServicePort, nodeLabels map[st
if !utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareHints) {
return false
}
// Any non-empty and non-disabled values for the hints annotation are acceptable.
hintsAnnotation := svcInfo.HintsAnnotation()
if hintsAnnotation != "Auto" && hintsAnnotation != "auto" {
if hintsAnnotation != "" && hintsAnnotation != "Disabled" && hintsAnnotation != "disabled" {
klog.InfoS("Skipping topology aware endpoint filtering since Service has unexpected value", "annotationTopologyAwareHints", v1.AnnotationTopologyAwareHints, "hints", hintsAnnotation)
}
if hintsAnnotation == "" || hintsAnnotation == "disabled" || hintsAnnotation == "Disabled" {
return false
}

View File

@ -105,7 +105,7 @@ func TestCategorizeEndpoints(t *testing.T) {
localEndpoints: nil,
}, {
name: "hints, hints annotation == aUto (wrong capitalization), hints ignored",
name: "hints, hints annotation == aUto (wrong capitalization), hints no longer ignored",
hintsEnabled: true,
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
serviceInfo: &BaseServicePortInfo{hintsAnnotation: "aUto"},
@ -115,7 +115,7 @@ func TestCategorizeEndpoints(t *testing.T) {
&BaseEndpointInfo{Endpoint: "10.1.2.5:80", ZoneHints: sets.NewString("zone-c"), Ready: true},
&BaseEndpointInfo{Endpoint: "10.1.2.6:80", ZoneHints: sets.NewString("zone-a"), Ready: true},
},
clusterEndpoints: sets.NewString("10.1.2.3:80", "10.1.2.4:80", "10.1.2.5:80", "10.1.2.6:80"),
clusterEndpoints: sets.NewString("10.1.2.3:80", "10.1.2.6:80"),
localEndpoints: nil,
}, {
name: "hints, hints annotation empty, hints ignored",

View File

@ -89,7 +89,7 @@ type ServicePort interface {
InternalPolicyLocal() bool
// InternalTrafficPolicy returns service InternalTrafficPolicy
InternalTrafficPolicy() *v1.ServiceInternalTrafficPolicy
// HintsAnnotation returns the value of the v1.AnnotationTopologyAwareHints annotation.
// HintsAnnotation returns the value of the v1.DeprecatedAnnotationTopologyAwareHints annotation.
HintsAnnotation() string
// ExternallyAccessible returns true if the service port is reachable via something
// other than ClusterIP (NodePort/ExternalIP/LoadBalancer)

View File

@ -144,8 +144,19 @@ const (
// This annotation is beta-level and is only honored when PodDeletionCost feature is enabled.
PodDeletionCost = "controller.kubernetes.io/pod-deletion-cost"
// AnnotationTopologyAwareHints can be used to enable or disable Topology
// Aware Hints for a Service. This may be set to "Auto" or "Disabled". Any
// other value is treated as "Disabled".
AnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints"
// DeprecatedAnnotationTopologyAwareHints can be used to enable or disable
// Topology Aware Hints for a Service. This may be set to "Auto" or
// "Disabled". Any other value is treated as "Disabled". This annotation has
// been deprecated in favor of the "service.kubernetes.io/topology-mode"
// annotation.
DeprecatedAnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints"
// AnnotationTopologyMode can be used to enable or disable Topology Aware
// Routing for a Service. Well known values are "Auto" and "Disabled".
// Implementations may choose to develop new topology approaches, exposing
// them with domain-prefixed values. For example, "example.com/lowest-rtt"
// could be a valid implementation-specific value for this annotation. These
// heuristics will often populate topology hints on EndpointSlices, but that
// is not a requirement.
AnnotationTopologyMode = "service.kubernetes.io/topology-mode"
)

View File

@ -65,7 +65,7 @@ var _ = common.SIGDescribe("[Feature:Topology Hints]", func() {
ObjectMeta: metav1.ObjectMeta{
Name: "topology-hints",
Annotations: map[string]string{
v1.AnnotationTopologyAwareHints: "Auto",
v1.AnnotationTopologyMode: "Auto",
},
},
Spec: v1.ServiceSpec{