From 08ec940c2888aa04475873a5928880cd64d6719c Mon Sep 17 00:00:00 2001 From: Braxton Schafer Date: Mon, 23 May 2022 12:24:18 -0500 Subject: [PATCH] Add kube_pod_ips gauge to pod metrics Add experimental kube_pod_ips metric to show all IPs on a pod. This is useful for dual-stack clusters where pods will have at least one IPv4 and one IPv6 address. Current kube_pod_info metric only shows the single IP exposed by .status.podIP. Signed-off-by: Braxton Schafer --- docs/pod-metrics.md | 1 + go.mod | 12 ++++++++++++ internal/store/pod.go | 33 +++++++++++++++++++++++++++++++++ internal/store/pod_test.go | 20 ++++++++++++++++---- pkg/app/server_test.go | 2 ++ 5 files changed, 64 insertions(+), 4 deletions(-) diff --git a/docs/pod-metrics.md b/docs/pod-metrics.md index 7c7742cc..15937db6 100644 --- a/docs/pod-metrics.md +++ b/docs/pod-metrics.md @@ -4,6 +4,7 @@ | ---------- | ----------- | ----------- | ----------------------- | ----------- | ------ | ------ | | kube_pod_annotations | Gauge | Kubernetes annotations converted to Prometheus labels | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`annotation_POD_ANNOTATION`=<POD_ANNOTATION>
`uid`=<pod-uid> | EXPERIMENTAL | - | kube_pod_info | Gauge | Information about pod | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`host_ip`=<host-ip>
`pod_ip`=<pod-ip>
`node`=<node-name>
`created_by_kind`=<created_by_kind>
`created_by_name`=<created_by_name>
`uid`=<pod-uid>
`priority_class`=<priority_class>
`host_network`=<host_network>| STABLE | - | +| kube_pod_ips | Gauge | Pod IP addresses | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`ip`=<pod-ip-address>
`ip_family`=<4 OR 6>
`uid`=<pod-uid> | EXPERIMENTAL | - | | kube_pod_start_time | Gauge | Start time in unix timestamp for a pod | seconds | `pod`=<pod-name>
`namespace`=<pod-namespace>
`uid`=<pod-uid> | STABLE | - | | kube_pod_completion_time | Gauge | Completion time in unix timestamp for a pod | seconds | `pod`=<pod-name>
`namespace`=<pod-namespace>
`uid`=<pod-uid> | STABLE | - | | kube_pod_owner | Gauge | Information about the Pod's owner | |`pod`=<pod-name>
`namespace`=<pod-namespace>
`owner_kind`=<owner kind>
`owner_name`=<owner name>
`owner_is_controller`=<whether owner is controller>
`uid`=<pod-uid> | STABLE | - | diff --git a/go.mod b/go.mod index 5dc98f6f..16df88aa 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( k8s.io/client-go v0.24.1 k8s.io/klog/v2 v2.60.1 k8s.io/sample-controller v0.24.1 + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 ) require ( @@ -80,10 +81,21 @@ require ( gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect +<<<<<<< HEAD gopkg.in/yaml.v3 v3.0.0 // indirect k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect +||||||| parent of 2b4874e5 (Add kube_pod_ips gauge to pod metrics) + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect + sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect +======= + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect + sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect +>>>>>>> 2b4874e5 (Add kube_pod_ips gauge to pod metrics) sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) diff --git a/internal/store/pod.go b/internal/store/pod.go index ec4c0135..9857d455 100644 --- a/internal/store/pod.go +++ b/internal/store/pod.go @@ -18,6 +18,7 @@ package store import ( "context" + "k8s.io/utils/net" "strconv" "k8s.io/kube-state-metrics/v2/pkg/constant" @@ -55,6 +56,7 @@ func podMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generat createPodCreatedFamilyGenerator(), createPodDeletionTimestampFamilyGenerator(), createPodInfoFamilyGenerator(), + createPodIPFamilyGenerator(), createPodInitContainerInfoFamilyGenerator(), createPodInitContainerResourceLimitsFamilyGenerator(), createPodInitContainerResourceRequestsFamilyGenerator(), @@ -580,6 +582,37 @@ func createPodInfoFamilyGenerator() generator.FamilyGenerator { ) } +func createPodIPFamilyGenerator() generator.FamilyGenerator { + return *generator.NewFamilyGenerator( + "kube_pod_ips", + "Pod IP addresses", + metric.Gauge, + "", + wrapPodFunc(func(p *v1.Pod) *metric.Family { + ms := make([]*metric.Metric, len(p.Status.PodIPs)) + labelKeys := []string{"ip", "ip_family"} + + for i, ip := range p.Status.PodIPs { + netIP := net.ParseIPSloppy(ip.IP) + var ipFamily net.IPFamily + if net.IsIPv4(netIP) { + ipFamily = net.IPv4 + } else { + ipFamily = net.IPv6 + } + ms[i] = &metric.Metric{ + LabelKeys: labelKeys, + LabelValues: []string{ip.IP, string(ipFamily)}, + Value: 1, + } + } + + return &metric.Family{ + Metrics: ms, + } + })) +} + func createPodInitContainerInfoFamilyGenerator() generator.FamilyGenerator { return *generator.NewFamilyGenerator( "kube_pod_init_container_info", diff --git a/internal/store/pod_test.go b/internal/store/pod_test.go index 3708cbb2..55cc4197 100644 --- a/internal/store/pod_test.go +++ b/internal/store/pod_test.go @@ -987,8 +987,16 @@ func TestPodStore(t *testing.T) { }, }, Status: v1.PodStatus{ - HostIP: "1.1.1.1", - PodIP: "1.2.3.4", + HostIP: "1.1.1.1", + PodIP: "1.2.3.4", + PodIPs: []v1.PodIP{ + { + "1.2.3.4", + }, + { + "fc00:1234:5678:90ab:cdef:cafe:f00d:d00d", + }, + }, StartTime: &metav1StartTime, }, }, @@ -997,19 +1005,23 @@ func TestPodStore(t *testing.T) { # HELP kube_pod_completion_time Completion time in unix timestamp for a pod. # HELP kube_pod_created Unix creation timestamp # HELP kube_pod_info Information about pod. + # HELP kube_pod_ips Pod IP addresses # HELP kube_pod_owner Information about the Pod's owner. # HELP kube_pod_start_time Start time in unix timestamp for a pod. # TYPE kube_pod_completion_time gauge # TYPE kube_pod_created gauge # TYPE kube_pod_info gauge + # TYPE kube_pod_ips gauge # TYPE kube_pod_owner gauge # TYPE kube_pod_start_time gauge kube_pod_created{namespace="ns1",pod="pod1",uid="abc-123-xxx"} 1.5e+09 kube_pod_info{created_by_kind="",created_by_name="",host_ip="1.1.1.1",namespace="ns1",node="node1",pod="pod1",pod_ip="1.2.3.4",uid="abc-123-xxx",priority_class="system-node-critical",host_network="true"} 1 + kube_pod_ips{namespace="ns1",pod="pod1",uid="abc-123-xxx",ip="1.2.3.4",ip_family="4"} 1 + kube_pod_ips{namespace="ns1",pod="pod1",uid="abc-123-xxx",ip="fc00:1234:5678:90ab:cdef:cafe:f00d:d00d",ip_family="6"} 1 kube_pod_start_time{namespace="ns1",pod="pod1",uid="abc-123-xxx"} 1.501569018e+09 kube_pod_owner{namespace="ns1",owner_is_controller="",owner_kind="",owner_name="",pod="pod1",uid="abc-123-xxx"} 1 `, - MetricNames: []string{"kube_pod_created", "kube_pod_info", "kube_pod_start_time", "kube_pod_completion_time", "kube_pod_owner"}, + MetricNames: []string{"kube_pod_created", "kube_pod_info", "kube_pod_ips", "kube_pod_start_time", "kube_pod_completion_time", "kube_pod_owner"}, }, { Obj: &v1.Pod{ @@ -2006,7 +2018,7 @@ func BenchmarkPodStore(b *testing.B) { }, } - expectedFamilies := 44 + expectedFamilies := 45 for n := 0; n < b.N; n++ { families := f(pod) if len(families) != expectedFamilies { diff --git a/pkg/app/server_test.go b/pkg/app/server_test.go index defd2ff8..2bf2550b 100644 --- a/pkg/app/server_test.go +++ b/pkg/app/server_test.go @@ -218,6 +218,7 @@ func TestFullScrapeCycle(t *testing.T) { # HELP kube_pod_init_container_status_terminated_reason Describes the reason the init container is currently in terminated state. # HELP kube_pod_init_container_status_waiting Describes whether the init container is currently in waiting state. # HELP kube_pod_init_container_status_waiting_reason Describes the reason the init container is currently in waiting state. +# HELP kube_pod_ips Pod IP addresses # HELP kube_pod_labels Kubernetes labels converted to Prometheus labels. # HELP kube_pod_overhead_cpu_cores The pod overhead in regards to cpu cores associated with running a pod. # HELP kube_pod_overhead_memory_bytes The pod overhead in regards to memory associated with running a pod. @@ -261,6 +262,7 @@ func TestFullScrapeCycle(t *testing.T) { # TYPE kube_pod_init_container_status_terminated_reason gauge # TYPE kube_pod_init_container_status_waiting gauge # TYPE kube_pod_init_container_status_waiting_reason gauge +# TYPE kube_pod_ips gauge # TYPE kube_pod_labels gauge # TYPE kube_pod_overhead_cpu_cores gauge # TYPE kube_pod_overhead_memory_bytes gauge