Skip to content

Commit f369828

Browse files
MarkSRobinsonmruegdgrisonnet
authored
feat: Add support for endpoint topology routing hints (#2090)
* Add support for endpoint topology routing hints Fix goimports Fix gocritic issue * Update docs/endpointslice-metrics.md Co-authored-by: Manuel Rüger <[email protected]> * Update internal/store/endpointslice.go Co-authored-by: Manuel Rüger <[email protected]> * Update Dockerfile * Update Dockerfile * Update endpointslice_test.go * Redesign metric * Update endpointslice.go Remove unneeded label * Update endpointslice.go * Update endpointslice-metrics.md * Fix test * Remove hostname * Update docs/endpointslice-metrics.md --------- Co-authored-by: Manuel Rüger <[email protected]> Co-authored-by: Damien Grisonnet <[email protected]>
1 parent dbd4568 commit f369828

File tree

3 files changed

+82
-1
lines changed

3 files changed

+82
-1
lines changed

docs/endpointslice-metrics.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@
66
| kube_endpointslice_info | Gauge | | `endpointslice`=&lt;endpointslice-name&gt; <br> `namespace`=&lt;endpointslice-namespace&gt; | EXPERIMENTAL |
77
| kube_endpointslice_ports | Gauge | | `endpointslice`=&lt;endpointslice-name&gt; <br> `namespace`=&lt;endpointslice-namespace&gt; <br> `port_name`=&lt;endpointslice-port-name&gt; <br> `port_protocol`=&lt;endpointslice-port-protocol&gt; <br> `port_number`=&lt;endpointslice-port-number&gt; | EXPERIMENTAL |
88
| kube_endpointslice_endpoints | Gauge | | `endpointslice`=&lt;endpointslice-name&gt; <br> `namespace`=&lt;endpointslice-namespace&gt; <br> `ready`=&lt;endpointslice-ready&gt; <br> `serving`=&lt;endpointslice-serving&gt; <br> `terminating`=&lt;endpointslice-terminating&gt; <br> `hostname`=&lt;endpointslice-hostname&gt; <br> `targetref_kind`=&lt;endpointslice-targetref-kind&gt; <br> `targetref_name`=&lt;endpointslice-targetref-name&gt; <br> `targetref_namespace`=&lt;endpointslice-targetref-namespace&gt; <br> `nodename`=&lt;endpointslice-nodename&gt; <br> `endpoint_zone`=&lt;endpointslice-zone&gt; | EXPERIMENTAL |
9+
| kube_endpointslice_endpoints_hints | Gauge | Each line is a hint applied to an endpoint-slice | `endpointslice`=&lt;endpointslice-name&gt; <br> `namespace`=&lt;endpointslice-namespace&gt; <br> `address`=&lt;endpointslice-address[0]&gt; <br> `for_zone`=&lt;endpointslice-hint&gt; | EXPERIMENTAL |
910
| kube_endpointslice_labels | Gauge | Kubernetes labels converted to Prometheus labels controlled via [--metric-labels-allowlist](./cli-arguments.md) | `endpointslice`=&lt;endpointslice-name&gt; <br> `namespace`=&lt;endpointslice-namespace&gt; <br> `label_ENDPOINTSLICE_LABEL`=&lt;ENDPOINTSLICE_LABEL&gt; | EXPERIMENTAL |
1011
| kube_endpointslice_created | Gauge | | `endpointslice`=&lt;endpointslice-name&gt; <br> `namespace`=&lt;endpointslice-namespace&gt; | EXPERIMENTAL |

internal/store/endpointslice.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,44 @@ func endpointSliceMetricFamilies(allowAnnotationsList, allowLabelsList []string)
7474
}
7575
}),
7676
),
77+
*generator.NewFamilyGeneratorWithStability(
78+
"kube_endpointslice_endpoints_hints",
79+
"Topology routing hints attached to endpoints",
80+
metric.Gauge,
81+
basemetrics.ALPHA,
82+
"",
83+
wrapEndpointSliceFunc(func(e *discoveryv1.EndpointSlice) *metric.Family {
84+
m := []*metric.Metric{}
85+
for _, ep := range e.Endpoints {
86+
// Hint is populated when the endpoint is configured to be zone aware and preferentially route requests to its local zone.
87+
// If there is no hint, skip this metric
88+
if ep.Hints != nil && len(ep.Hints.ForZones) > 0 {
89+
var (
90+
labelKeys,
91+
labelValues []string
92+
)
93+
94+
// Per Docs.
95+
// This must contain at least one address but no more than
96+
// 100. These are all assumed to be fungible and clients may choose to only
97+
// use the first element. Refer to: https://issue.k8s.io/106267
98+
labelKeys = append(labelKeys, "address")
99+
labelValues = append(labelValues, ep.Addresses[0])
100+
101+
for _, zone := range ep.Hints.ForZones {
102+
m = append(m, &metric.Metric{
103+
LabelKeys: append(labelKeys, "for_zone"),
104+
LabelValues: append(labelValues, zone.Name),
105+
Value: 1,
106+
})
107+
}
108+
}
109+
}
110+
return &metric.Family{
111+
Metrics: m,
112+
}
113+
}),
114+
),
77115
*generator.NewFamilyGeneratorWithStability(
78116
"kube_endpointslice_endpoints",
79117
"Endpoints attached to the endpointslice.",
@@ -134,9 +172,11 @@ func endpointSliceMetricFamilies(allowAnnotationsList, allowLabelsList []string)
134172
for _, address := range ep.Addresses {
135173
newlabelValues := make([]string, len(labelValues))
136174
copy(newlabelValues, labelValues)
175+
newlabelValues = append(newlabelValues, address)
176+
137177
m = append(m, &metric.Metric{
138178
LabelKeys: labelKeys,
139-
LabelValues: append(newlabelValues, address),
179+
LabelValues: newlabelValues,
140180
Value: 1,
141181
})
142182
}

internal/store/endpointslice_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ func TestEndpointSliceStore(t *testing.T) {
113113
},
114114
Want: `
115115
# HELP kube_endpointslice_endpoints Endpoints attached to the endpointslice.
116+
# HELP kube_endpointslice_endpoints_hints Topology routing hints attached to endpoints
116117
# TYPE kube_endpointslice_endpoints gauge
118+
# TYPE kube_endpointslice_endpoints_hints gauge
117119
kube_endpointslice_endpoints{address="10.0.0.1",endpoint_nodename="node",endpoint_zone="west",endpointslice="test_endpointslice-endpoints",hostname="host",ready="true",terminating="false"} 1
118120
kube_endpointslice_endpoints{address="192.168.1.10",endpoint_nodename="node",endpoint_zone="west",endpointslice="test_endpointslice-endpoints",hostname="host",ready="true",terminating="false"} 1
119121
`,
@@ -122,6 +124,44 @@ func TestEndpointSliceStore(t *testing.T) {
122124
"kube_endpointslice_endpoints",
123125
},
124126
},
127+
{
128+
Obj: &discoveryv1.EndpointSlice{
129+
ObjectMeta: metav1.ObjectMeta{
130+
Name: "test_endpointslice-endpoints",
131+
},
132+
AddressType: "IPv4",
133+
Endpoints: []discoveryv1.Endpoint{
134+
{
135+
NodeName: &nodename,
136+
Conditions: discoveryv1.EndpointConditions{
137+
Ready: &ready,
138+
Terminating: &terminating,
139+
},
140+
Hostname: &hostname,
141+
Zone: &zone,
142+
Addresses: addresses,
143+
Hints: &discoveryv1.EndpointHints{
144+
ForZones: []discoveryv1.ForZone{
145+
{Name: "zone1"},
146+
},
147+
},
148+
},
149+
},
150+
},
151+
Want: `
152+
# HELP kube_endpointslice_endpoints Endpoints attached to the endpointslice.
153+
# HELP kube_endpointslice_endpoints_hints Topology routing hints attached to endpoints
154+
# TYPE kube_endpointslice_endpoints gauge
155+
# TYPE kube_endpointslice_endpoints_hints gauge
156+
kube_endpointslice_endpoints_hints{address="10.0.0.1",endpointslice="test_endpointslice-endpoints",for_zone="zone1"} 1
157+
kube_endpointslice_endpoints{address="10.0.0.1",endpoint_nodename="node",endpoint_zone="west",endpointslice="test_endpointslice-endpoints",hostname="host",ready="true",terminating="false"} 1
158+
kube_endpointslice_endpoints{address="192.168.1.10",endpoint_nodename="node",endpoint_zone="west",endpointslice="test_endpointslice-endpoints",hostname="host",ready="true",terminating="false"} 1
159+
`,
160+
161+
MetricNames: []string{
162+
"kube_endpointslice_endpoints",
163+
},
164+
},
125165
{
126166
AllowAnnotationsList: []string{
127167
"foo",

0 commit comments

Comments
 (0)