Skip to content

Commit 229befd

Browse files
committed
*: add webhooks client config service metrics
In order to better identify, prioritize, and debug webhook latency issues it is important to have a metric that would point to the resource it is responsible for. However, it is not possible to have that dimension in the metrics exposed by Kubernetes because of the unbound cardinality that such a label would have. The name of the webhook could be an alternative since it usually contains some information about the resource that the webhook targets, however this is not very practical to use in multi-tenants environments. A solution for these kind of platform is to tie a specific webhook to a namespace in order to be able to know which tenant manages it and take actions depending on that. This is achieveable by leveraging the client config information of webhooks configured via WebhookConfiguration resources since Services are namespaced objects. With these new metrics, users will be able to split the alerting severity of webhook latency / rejection rate per namespace on top of being able to do it based on the webhook name. This is key in environment where administrators don't have control over the webhooks installed by the various tenants. Signed-off-by: Damien Grisonnet <[email protected]>
1 parent 31d6e8f commit 229befd

6 files changed

+118
-0
lines changed

docs/mutatingwebhookconfiguration-metrics.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
| kube_mutatingwebhookconfiguration_info | Gauge | `mutatingwebhookconfiguration`=&lt;mutatingwebhookconfiguration-name&gt; <br> `namespace`=&lt;mutatingwebhookconfiguration-namespace&gt; | EXPERIMENTAL |
66
| kube_mutatingwebhookconfiguration_created | Gauge | `mutatingwebhookconfiguration`=&lt;mutatingwebhookconfiguration-name&gt; <br> `namespace`=&lt;mutatingwebhookconfiguration-namespace&gt; | EXPERIMENTAL |
77
| kube_mutatingwebhookconfiguration_metadata_resource_version | Gauge | `mutatingwebhookconfiguration`=&lt;mutatingwebhookconfiguration-name&gt; <br> `namespace`=&lt;mutatingwebhookconfiguration-namespace&gt; | EXPERIMENTAL |
8+
| kube_mutatingwebhookconfiguration_webhook_clientconfig_service | Gauge | `mutatingwebhookconfiguration`=&lt;mutatingwebhookconfiguration-name&gt; <br> `namespace`=&lt;mutatingwebhookconfiguration-namespace&gt; <br> `webhook_name`=&lt;webhook-name&gt; <br> `service_name`=&lt;webhook-service-name&gt; <br> `service_namespace`=&lt;webhook-service-namespace&gt;| EXPERIMENTAL |

docs/validatingwebhookconfiguration-metrics.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
| kube_validatingwebhookconfiguration_info | Gauge | `validatingwebhookconfiguration`=&lt;validatingwebhookconfiguration-name&gt; <br> `namespace`=&lt;validatingwebhookconfiguration-namespace&gt; | EXPERIMENTAL |
66
| kube_validatingwebhookconfiguration_created | Gauge | `validatingwebhookconfiguration`=&lt;validatingwebhookconfiguration-name&gt; <br> `namespace`=&lt;validatingwebhookconfiguration-namespace&gt; | EXPERIMENTAL |
77
| kube_validatingwebhookconfiguration_metadata_resource_version | Gauge | `validatingwebhookconfiguration`=&lt;validatingwebhookconfiguration-name&gt; <br> `namespace`=&lt;validatingwebhookconfiguration-namespace&gt; | EXPERIMENTAL |
8+
| kube_validatingwebhookconfiguration_webhook_clientconfig_service | Gauge | `validatingwebhookconfiguration`=&lt;validatingwebhookconfiguration-name&gt; <br> `namespace`=&lt;validatingwebhookconfiguration-namespace&gt; <br> `webhook_name`=&lt;webhook-name&gt; <br> `service_name`=&lt;webhook-service-name&gt; <br> `service_namespace`=&lt;webhook-service-namespace&gt;| EXPERIMENTAL |

internal/store/mutatingwebhookconfiguration.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,32 @@ var (
8282
}
8383
}),
8484
),
85+
*generator.NewFamilyGeneratorWithStability(
86+
"kube_mutatingwebhookconfiguration_webhook_clientconfig_service",
87+
"Service used by the apiserver to connect to a mutating webhook.",
88+
metric.Gauge,
89+
basemetrics.ALPHA,
90+
"",
91+
wrapMutatingWebhookConfigurationFunc(func(mwc *admissionregistrationv1.MutatingWebhookConfiguration) *metric.Family {
92+
ms := []*metric.Metric{}
93+
for _, webhook := range mwc.Webhooks {
94+
var serviceName, serviceNamespace string
95+
if webhook.ClientConfig.Service != nil {
96+
serviceName = webhook.ClientConfig.Service.Name
97+
serviceNamespace = webhook.ClientConfig.Service.Namespace
98+
}
99+
100+
ms = append(ms, &metric.Metric{
101+
LabelKeys: []string{"webhook_name", "service_name", "service_namespace"},
102+
LabelValues: []string{webhook.Name, serviceName, serviceNamespace},
103+
Value: 1,
104+
})
105+
}
106+
return &metric.Family{
107+
Metrics: ms,
108+
}
109+
}),
110+
),
85111
}
86112
)
87113

internal/store/mutatingwebhookconfiguration_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
func TestMutatingWebhookConfigurationStore(t *testing.T) {
2929
startTime := 1501569018
3030
metav1StartTime := metav1.Unix(int64(startTime), 0)
31+
externalURL := "example.com"
3132

3233
cases := []generateMetricsTestCase{
3334
{
@@ -69,6 +70,37 @@ func TestMutatingWebhookConfigurationStore(t *testing.T) {
6970
`,
7071
MetricNames: []string{"kube_mutatingwebhookconfiguration_created", "kube_mutatingwebhookconfiguration_info", "kube_mutatingwebhookconfiguration_metadata_resource_version"},
7172
},
73+
{
74+
Obj: &admissionregistrationv1.MutatingWebhookConfiguration{
75+
ObjectMeta: metav1.ObjectMeta{
76+
Name: "mutatingwebhookconfiguration3",
77+
Namespace: "ns3",
78+
CreationTimestamp: metav1StartTime,
79+
ResourceVersion: "abcdef",
80+
},
81+
Webhooks: []admissionregistrationv1.MutatingWebhook{
82+
{
83+
Name: "webhook_with_service",
84+
ClientConfig: admissionregistrationv1.WebhookClientConfig{
85+
Service: &admissionregistrationv1.ServiceReference{Name: "svc", Namespace: "ns"},
86+
},
87+
},
88+
{
89+
Name: "webhook_with_external_url",
90+
ClientConfig: admissionregistrationv1.WebhookClientConfig{
91+
URL: &externalURL,
92+
},
93+
},
94+
},
95+
},
96+
Want: `
97+
# HELP kube_mutatingwebhookconfiguration_webhook_clientconfig_service Service used by the apiserver to connect to a mutating webhook.
98+
# TYPE kube_mutatingwebhookconfiguration_webhook_clientconfig_service gauge
99+
kube_mutatingwebhookconfiguration_webhook_clientconfig_service{webhook_name="webhook_with_external_url",namespace="ns3",service_name="",service_namespace="",mutatingwebhookconfiguration="mutatingwebhookconfiguration3"} 1
100+
kube_mutatingwebhookconfiguration_webhook_clientconfig_service{webhook_name="webhook_with_service",namespace="ns3",service_name="svc",service_namespace="ns",mutatingwebhookconfiguration="mutatingwebhookconfiguration3"} 1
101+
`,
102+
MetricNames: []string{"kube_mutatingwebhookconfiguration_webhook_clientconfig_service"},
103+
},
72104
}
73105
for i, c := range cases {
74106
c.Func = generator.ComposeMetricGenFuncs(mutatingWebhookConfigurationMetricFamilies)

internal/store/validatingwebhookconfiguration.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,32 @@ var (
8282
}
8383
}),
8484
),
85+
*generator.NewFamilyGeneratorWithStability(
86+
"kube_validatingwebhookconfiguration_webhook_clientconfig_service",
87+
"Service used by the apiserver to connect to a validating webhook.",
88+
metric.Gauge,
89+
basemetrics.ALPHA,
90+
"",
91+
wrapValidatingWebhookConfigurationFunc(func(vwc *admissionregistrationv1.ValidatingWebhookConfiguration) *metric.Family {
92+
ms := []*metric.Metric{}
93+
for _, webhook := range vwc.Webhooks {
94+
var serviceName, serviceNamespace string
95+
if webhook.ClientConfig.Service != nil {
96+
serviceName = webhook.ClientConfig.Service.Name
97+
serviceNamespace = webhook.ClientConfig.Service.Namespace
98+
}
99+
100+
ms = append(ms, &metric.Metric{
101+
LabelKeys: []string{"webhook_name", "service_name", "service_namespace"},
102+
LabelValues: []string{webhook.Name, serviceName, serviceNamespace},
103+
Value: 1,
104+
})
105+
}
106+
return &metric.Family{
107+
Metrics: ms,
108+
}
109+
}),
110+
),
85111
}
86112
)
87113

internal/store/validatingwebhookconfiguration_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
func TestValidatingWebhookConfigurationStore(t *testing.T) {
2929
startTime := 1501569018
3030
metav1StartTime := metav1.Unix(int64(startTime), 0)
31+
externalURL := "example.com"
3132

3233
cases := []generateMetricsTestCase{
3334
{
@@ -69,6 +70,37 @@ func TestValidatingWebhookConfigurationStore(t *testing.T) {
6970
`,
7071
MetricNames: []string{"kube_validatingwebhookconfiguration_created", "kube_validatingwebhookconfiguration_info", "kube_validatingwebhookconfiguration_metadata_resource_version"},
7172
},
73+
{
74+
Obj: &admissionregistrationv1.ValidatingWebhookConfiguration{
75+
ObjectMeta: metav1.ObjectMeta{
76+
Name: "validatingwebhookconfiguration3",
77+
Namespace: "ns3",
78+
CreationTimestamp: metav1StartTime,
79+
ResourceVersion: "abcdef",
80+
},
81+
Webhooks: []admissionregistrationv1.ValidatingWebhook{
82+
{
83+
Name: "webhook_with_service",
84+
ClientConfig: admissionregistrationv1.WebhookClientConfig{
85+
Service: &admissionregistrationv1.ServiceReference{Name: "svc", Namespace: "ns"},
86+
},
87+
},
88+
{
89+
Name: "webhook_with_external_url",
90+
ClientConfig: admissionregistrationv1.WebhookClientConfig{
91+
URL: &externalURL,
92+
},
93+
},
94+
},
95+
},
96+
Want: `
97+
# HELP kube_validatingwebhookconfiguration_webhook_clientconfig_service Service used by the apiserver to connect to a validating webhook.
98+
# TYPE kube_validatingwebhookconfiguration_webhook_clientconfig_service gauge
99+
kube_validatingwebhookconfiguration_webhook_clientconfig_service{webhook_name="webhook_with_external_url",namespace="ns3",service_name="",service_namespace="",validatingwebhookconfiguration="validatingwebhookconfiguration3"} 1
100+
kube_validatingwebhookconfiguration_webhook_clientconfig_service{webhook_name="webhook_with_service",namespace="ns3",service_name="svc",service_namespace="ns",validatingwebhookconfiguration="validatingwebhookconfiguration3"} 1
101+
`,
102+
MetricNames: []string{"kube_validatingwebhookconfiguration_webhook_clientconfig_service"},
103+
},
72104
}
73105
for i, c := range cases {
74106
c.Func = generator.ComposeMetricGenFuncs(validatingWebhookConfigurationMetricFamilies)

0 commit comments

Comments
 (0)