mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-21 02:41:25 +00:00
Merge pull request #100728 from robscott/topology-auto
Updating Topology Aware Hints to support "Auto" value for annotation
This commit is contained in:
commit
1cedfef5c6
@ -126,7 +126,7 @@ const (
|
|||||||
PodDeletionCost = "controller.kubernetes.io/pod-deletion-cost"
|
PodDeletionCost = "controller.kubernetes.io/pod-deletion-cost"
|
||||||
|
|
||||||
// AnnotationTopologyAwareHints can be used to enable or disable Topology
|
// AnnotationTopologyAwareHints can be used to enable or disable Topology
|
||||||
// Aware Hints for a Service. This may be set to "auto" or "disabled". Any
|
// Aware Hints for a Service. This may be set to "Auto" or "Disabled". Any
|
||||||
// other value is treated as "disabled".
|
// other value is treated as "Disabled".
|
||||||
AnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints"
|
AnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints"
|
||||||
)
|
)
|
||||||
|
@ -102,7 +102,7 @@ var (
|
|||||||
Name: "endpointslices_changed_per_sync",
|
Name: "endpointslices_changed_per_sync",
|
||||||
Help: "Number of EndpointSlices changed on each Service sync",
|
Help: "Number of EndpointSlices changed on each Service sync",
|
||||||
},
|
},
|
||||||
[]string{"topology"}, // either "auto" or "disabled"
|
[]string{"topology"}, // either "Auto" or "Disabled"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EndpointSliceSyncs tracks the number of sync operations the controller
|
// EndpointSliceSyncs tracks the number of sync operations the controller
|
||||||
|
@ -330,9 +330,9 @@ func (r *reconciler) finalize(
|
|||||||
metrics.EndpointSliceChanges.WithLabelValues("delete").Inc()
|
metrics.EndpointSliceChanges.WithLabelValues("delete").Inc()
|
||||||
}
|
}
|
||||||
|
|
||||||
topologyLabel := "disabled"
|
topologyLabel := "Disabled"
|
||||||
if r.topologyCache != nil && hintsEnabled(service.Annotations) {
|
if r.topologyCache != nil && hintsEnabled(service.Annotations) {
|
||||||
topologyLabel = "auto"
|
topologyLabel = "Auto"
|
||||||
}
|
}
|
||||||
|
|
||||||
numSlicesChanged := len(slicesToCreate) + len(slicesToUpdate) + len(slicesToDelete)
|
numSlicesChanged := len(slicesToCreate) + len(slicesToUpdate) + len(slicesToDelete)
|
||||||
|
@ -1460,9 +1460,9 @@ func TestReconcileTopology(t *testing.T) {
|
|||||||
slicesChangedPerSyncTopology: 0,
|
slicesChangedPerSyncTopology: 0,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
name: "topology enabled, hintsAnnotation==auto, more slices and endpoints",
|
name: "topology enabled, hintsAnnotation==Auto, more slices and endpoints",
|
||||||
topologyCacheEnabled: true,
|
topologyCacheEnabled: true,
|
||||||
hintsAnnotation: "auto",
|
hintsAnnotation: "Auto",
|
||||||
existingSlices: []*discovery.EndpointSlice{slicesByName["zone-a-c"], slicesByName["zone-a-b"]},
|
existingSlices: []*discovery.EndpointSlice{slicesByName["zone-a-c"], slicesByName["zone-a-b"]},
|
||||||
pods: append(slicePods["zone-a-c"], slicePods["zone-a-b"]...),
|
pods: append(slicePods["zone-a-c"], slicePods["zone-a-b"]...),
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
@ -1784,13 +1784,13 @@ func expectMetrics(t *testing.T, em expectedMetrics) {
|
|||||||
t.Errorf("Expected endpointSliceChangesDeleted to be %d, got %v", em.numDeleted, actualDeleted)
|
t.Errorf("Expected endpointSliceChangesDeleted to be %d, got %v", em.numDeleted, actualDeleted)
|
||||||
}
|
}
|
||||||
|
|
||||||
actualSlicesChangedPerSync, err := testutil.GetHistogramMetricValue(metrics.EndpointSlicesChangedPerSync.WithLabelValues("disabled"))
|
actualSlicesChangedPerSync, err := testutil.GetHistogramMetricValue(metrics.EndpointSlicesChangedPerSync.WithLabelValues("Disabled"))
|
||||||
handleErr(t, err, "slicesChangedPerSync")
|
handleErr(t, err, "slicesChangedPerSync")
|
||||||
if actualSlicesChangedPerSync != float64(em.slicesChangedPerSync) {
|
if actualSlicesChangedPerSync != float64(em.slicesChangedPerSync) {
|
||||||
t.Errorf("Expected slicesChangedPerSync to be %d, got %v", em.slicesChangedPerSync, actualSlicesChangedPerSync)
|
t.Errorf("Expected slicesChangedPerSync to be %d, got %v", em.slicesChangedPerSync, actualSlicesChangedPerSync)
|
||||||
}
|
}
|
||||||
|
|
||||||
actualSlicesChangedPerSyncTopology, err := testutil.GetHistogramMetricValue(metrics.EndpointSlicesChangedPerSync.WithLabelValues("auto"))
|
actualSlicesChangedPerSyncTopology, err := testutil.GetHistogramMetricValue(metrics.EndpointSlicesChangedPerSync.WithLabelValues("Auto"))
|
||||||
handleErr(t, err, "slicesChangedPerSyncTopology")
|
handleErr(t, err, "slicesChangedPerSyncTopology")
|
||||||
if actualSlicesChangedPerSyncTopology != float64(em.slicesChangedPerSyncTopology) {
|
if actualSlicesChangedPerSyncTopology != float64(em.slicesChangedPerSyncTopology) {
|
||||||
t.Errorf("Expected slicesChangedPerSyncTopology to be %d, got %v", em.slicesChangedPerSyncTopology, actualSlicesChangedPerSyncTopology)
|
t.Errorf("Expected slicesChangedPerSyncTopology to be %d, got %v", em.slicesChangedPerSyncTopology, actualSlicesChangedPerSyncTopology)
|
||||||
@ -1825,8 +1825,8 @@ func setupMetrics() {
|
|||||||
metrics.EndpointSliceChanges.Delete(map[string]string{"operation": "create"})
|
metrics.EndpointSliceChanges.Delete(map[string]string{"operation": "create"})
|
||||||
metrics.EndpointSliceChanges.Delete(map[string]string{"operation": "update"})
|
metrics.EndpointSliceChanges.Delete(map[string]string{"operation": "update"})
|
||||||
metrics.EndpointSliceChanges.Delete(map[string]string{"operation": "delete"})
|
metrics.EndpointSliceChanges.Delete(map[string]string{"operation": "delete"})
|
||||||
metrics.EndpointSlicesChangedPerSync.Delete(map[string]string{"topology": "disabled"})
|
metrics.EndpointSlicesChangedPerSync.Delete(map[string]string{"topology": "Disabled"})
|
||||||
metrics.EndpointSlicesChangedPerSync.Delete(map[string]string{"topology": "auto"})
|
metrics.EndpointSlicesChangedPerSync.Delete(map[string]string{"topology": "Auto"})
|
||||||
metrics.EndpointSliceSyncs.Delete(map[string]string{"result": "success"})
|
metrics.EndpointSliceSyncs.Delete(map[string]string{"result": "success"})
|
||||||
metrics.EndpointSliceSyncs.Delete(map[string]string{"result": "error"})
|
metrics.EndpointSliceSyncs.Delete(map[string]string{"result": "error"})
|
||||||
}
|
}
|
||||||
|
@ -386,11 +386,11 @@ func unchangedSlices(existingSlices, slicesToUpdate, slicesToDelete []*discovery
|
|||||||
}
|
}
|
||||||
|
|
||||||
// hintsEnabled returns true if the provided annotations include a
|
// hintsEnabled returns true if the provided annotations include a
|
||||||
// corev1.AnnotationTopologyAwareHints key with a value set to "auto".
|
// corev1.AnnotationTopologyAwareHints key with a value set to "Auto" or "auto".
|
||||||
func hintsEnabled(annotations map[string]string) bool {
|
func hintsEnabled(annotations map[string]string) bool {
|
||||||
val, ok := annotations[corev1.AnnotationTopologyAwareHints]
|
val, ok := annotations[corev1.AnnotationTopologyAwareHints]
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return val == "auto"
|
return val == "Auto" || val == "auto"
|
||||||
}
|
}
|
||||||
|
@ -1165,3 +1165,46 @@ func TestSupportedServiceAddressType(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_hintsEnabled(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
annotations map[string]string
|
||||||
|
expectEnabled bool
|
||||||
|
}{{
|
||||||
|
name: "empty annotations",
|
||||||
|
expectEnabled: false,
|
||||||
|
}, {
|
||||||
|
name: "different annotations",
|
||||||
|
annotations: map[string]string{"topology-hints": "enabled"},
|
||||||
|
expectEnabled: false,
|
||||||
|
}, {
|
||||||
|
name: "annotation == enabled",
|
||||||
|
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "enabled"},
|
||||||
|
expectEnabled: false,
|
||||||
|
}, {
|
||||||
|
name: "annotation == aUto",
|
||||||
|
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "aUto"},
|
||||||
|
expectEnabled: false,
|
||||||
|
}, {
|
||||||
|
name: "annotation == auto",
|
||||||
|
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "auto"},
|
||||||
|
expectEnabled: true,
|
||||||
|
}, {
|
||||||
|
name: "annotation == Auto",
|
||||||
|
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "Auto"},
|
||||||
|
expectEnabled: true,
|
||||||
|
}, {
|
||||||
|
name: "annotation == disabled",
|
||||||
|
annotations: map[string]string{v1.AnnotationTopologyAwareHints: "disabled"},
|
||||||
|
expectEnabled: false,
|
||||||
|
}}
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
actualEnabled := hintsEnabled(tc.annotations)
|
||||||
|
if actualEnabled != tc.expectEnabled {
|
||||||
|
t.Errorf("Expected %t, got %t", tc.expectEnabled, actualEnabled)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -49,15 +49,15 @@ func FilterEndpoints(endpoints []Endpoint, svcInfo ServicePort, nodeLabels map[s
|
|||||||
// filterEndpointsWithHints provides filtering based on the hints included in
|
// filterEndpointsWithHints provides filtering based on the hints included in
|
||||||
// EndpointSlices. If any of the following are true, the full list of endpoints
|
// EndpointSlices. If any of the following are true, the full list of endpoints
|
||||||
// will be returned without any filtering:
|
// will be returned without any filtering:
|
||||||
// * The AnnotationTopologyAwareHints annotation is not set to "auto" for this
|
// * The AnnotationTopologyAwareHints annotation is not set to "Auto" for this
|
||||||
// Service.
|
// Service.
|
||||||
// * No zone is specified in node labels.
|
// * No zone is specified in node labels.
|
||||||
// * No endpoints for this Service have a hint pointing to the zone this
|
// * No endpoints for this Service have a hint pointing to the zone this
|
||||||
// instance of kube-proxy is running in.
|
// instance of kube-proxy is running in.
|
||||||
// * One or more endpoints for this Service do not have hints specified.
|
// * One or more endpoints for this Service do not have hints specified.
|
||||||
func filterEndpointsWithHints(endpoints []Endpoint, hintsAnnotation string, nodeLabels map[string]string) []Endpoint {
|
func filterEndpointsWithHints(endpoints []Endpoint, hintsAnnotation string, nodeLabels map[string]string) []Endpoint {
|
||||||
if hintsAnnotation != "auto" {
|
if hintsAnnotation != "Auto" && hintsAnnotation != "auto" {
|
||||||
if hintsAnnotation != "" && hintsAnnotation != "disabled" {
|
if hintsAnnotation != "" && hintsAnnotation != "Disabled" && hintsAnnotation != "disabled" {
|
||||||
klog.Warningf("Skipping topology aware endpoint filtering since Service has unexpected value for %s annotation: %s", v1.AnnotationTopologyAwareHints, hintsAnnotation)
|
klog.Warningf("Skipping topology aware endpoint filtering since Service has unexpected value for %s annotation: %s", v1.AnnotationTopologyAwareHints, hintsAnnotation)
|
||||||
}
|
}
|
||||||
return endpoints
|
return endpoints
|
||||||
|
@ -77,11 +77,11 @@ func TestFilterEndpoints(t *testing.T) {
|
|||||||
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
name: "hints + eps proxying enabled, hints annotation == Auto (wrong capitalization), hints ignored",
|
name: "hints + eps proxying enabled, hints annotation == aUto (wrong capitalization), hints ignored",
|
||||||
hintsEnabled: true,
|
hintsEnabled: true,
|
||||||
epsProxyingEnabled: true,
|
epsProxyingEnabled: true,
|
||||||
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
|
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
|
||||||
serviceInfo: &BaseServiceInfo{nodeLocalExternal: false, hintsAnnotation: "Auto"},
|
serviceInfo: &BaseServiceInfo{nodeLocalExternal: false, hintsAnnotation: "aUto"},
|
||||||
endpoints: []endpoint{
|
endpoints: []endpoint{
|
||||||
{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")},
|
{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")},
|
||||||
{ip: "10.1.2.4", zoneHints: sets.NewString("zone-b")},
|
{ip: "10.1.2.4", zoneHints: sets.NewString("zone-b")},
|
||||||
@ -234,7 +234,7 @@ func Test_filterEndpointsWithHints(t *testing.T) {
|
|||||||
endpoints: []endpoint{{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")}},
|
endpoints: []endpoint{{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")}},
|
||||||
expectedEndpoints: []endpoint{{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")}},
|
expectedEndpoints: []endpoint{{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")}},
|
||||||
}, {
|
}, {
|
||||||
name: "normal endpoint filtering",
|
name: "normal endpoint filtering, auto annotation",
|
||||||
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
|
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
|
||||||
hintsAnnotation: "auto",
|
hintsAnnotation: "auto",
|
||||||
endpoints: []endpoint{
|
endpoints: []endpoint{
|
||||||
@ -247,6 +247,20 @@ func Test_filterEndpointsWithHints(t *testing.T) {
|
|||||||
{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")},
|
{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")},
|
||||||
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
name: "normal endpoint filtering, Auto annotation",
|
||||||
|
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
|
||||||
|
hintsAnnotation: "Auto",
|
||||||
|
endpoints: []endpoint{
|
||||||
|
{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")},
|
||||||
|
{ip: "10.1.2.4", zoneHints: sets.NewString("zone-b")},
|
||||||
|
{ip: "10.1.2.5", zoneHints: sets.NewString("zone-c")},
|
||||||
|
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
||||||
|
},
|
||||||
|
expectedEndpoints: []endpoint{
|
||||||
|
{ip: "10.1.2.3", zoneHints: sets.NewString("zone-a")},
|
||||||
|
{ip: "10.1.2.6", zoneHints: sets.NewString("zone-a")},
|
||||||
|
},
|
||||||
}, {
|
}, {
|
||||||
name: "hintsAnnotation empty, no filtering applied",
|
name: "hintsAnnotation empty, no filtering applied",
|
||||||
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
|
nodeLabels: map[string]string{v1.LabelTopologyZone: "zone-a"},
|
||||||
|
@ -148,7 +148,7 @@ const (
|
|||||||
PodDeletionCost = "controller.kubernetes.io/pod-deletion-cost"
|
PodDeletionCost = "controller.kubernetes.io/pod-deletion-cost"
|
||||||
|
|
||||||
// AnnotationTopologyAwareHints can be used to enable or disable Topology
|
// AnnotationTopologyAwareHints can be used to enable or disable Topology
|
||||||
// Aware Hints for a Service. This may be set to "auto" or "disabled". Any
|
// Aware Hints for a Service. This may be set to "Auto" or "Disabled". Any
|
||||||
// other value is treated as "disabled".
|
// other value is treated as "Disabled".
|
||||||
AnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints"
|
AnnotationTopologyAwareHints = "service.kubernetes.io/topology-aware-hints"
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user