Skip to content

Commit 08ec940

Browse files
committed
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 <[email protected]>
1 parent 7e28ed2 commit 08ec940

File tree

5 files changed

+64
-4
lines changed

5 files changed

+64
-4
lines changed

docs/pod-metrics.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| ---------- | ----------- | ----------- | ----------------------- | ----------- | ------ | ------ |
55
| kube_pod_annotations | Gauge | Kubernetes annotations converted to Prometheus labels | | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `annotation_POD_ANNOTATION`=&lt;POD_ANNOTATION&gt; <br> `uid`=&lt;pod-uid&gt; | EXPERIMENTAL | -
66
| kube_pod_info | Gauge | Information about pod | | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `host_ip`=&lt;host-ip&gt; <br> `pod_ip`=&lt;pod-ip&gt; <br> `node`=&lt;node-name&gt;<br> `created_by_kind`=&lt;created_by_kind&gt;<br> `created_by_name`=&lt;created_by_name&gt;<br> `uid`=&lt;pod-uid&gt;<br> `priority_class`=&lt;priority_class&gt;<br> `host_network`=&lt;host_network&gt;| STABLE | - |
7+
| kube_pod_ips | Gauge | Pod IP addresses | | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `ip`=&lt;pod-ip-address&gt; <br> `ip_family`=&lt;4 OR 6&gt; <br> `uid`=&lt;pod-uid&gt; | EXPERIMENTAL | - |
78
| kube_pod_start_time | Gauge | Start time in unix timestamp for a pod | seconds | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `uid`=&lt;pod-uid&gt; | STABLE | - |
89
| kube_pod_completion_time | Gauge | Completion time in unix timestamp for a pod | seconds | `pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `uid`=&lt;pod-uid&gt; | STABLE | - |
910
| kube_pod_owner | Gauge | Information about the Pod's owner | |`pod`=&lt;pod-name&gt; <br> `namespace`=&lt;pod-namespace&gt; <br> `owner_kind`=&lt;owner kind&gt; <br> `owner_name`=&lt;owner name&gt; <br> `owner_is_controller`=&lt;whether owner is controller&gt; <br> `uid`=&lt;pod-uid&gt; | STABLE | - |

go.mod

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ require (
2222
k8s.io/client-go v0.24.1
2323
k8s.io/klog/v2 v2.60.1
2424
k8s.io/sample-controller v0.24.1
25+
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
2526
)
2627

2728
require (
@@ -80,10 +81,21 @@ require (
8081
gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
8182
gopkg.in/inf.v0 v0.9.1 // indirect
8283
gopkg.in/yaml.v2 v2.4.0 // indirect
84+
<<<<<<< HEAD
8385
gopkg.in/yaml.v3 v3.0.0 // indirect
8486
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
8587
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
8688
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
89+
||||||| parent of 2b4874e5 (Add kube_pod_ips gauge to pod metrics)
90+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
91+
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
92+
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
93+
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
94+
=======
95+
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
96+
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect
97+
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
98+
>>>>>>> 2b4874e5 (Add kube_pod_ips gauge to pod metrics)
8799
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
88100
sigs.k8s.io/yaml v1.3.0 // indirect
89101
)

internal/store/pod.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package store
1818

1919
import (
2020
"context"
21+
"k8s.io/utils/net"
2122
"strconv"
2223

2324
"k8s.io/kube-state-metrics/v2/pkg/constant"
@@ -55,6 +56,7 @@ func podMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generat
5556
createPodCreatedFamilyGenerator(),
5657
createPodDeletionTimestampFamilyGenerator(),
5758
createPodInfoFamilyGenerator(),
59+
createPodIPFamilyGenerator(),
5860
createPodInitContainerInfoFamilyGenerator(),
5961
createPodInitContainerResourceLimitsFamilyGenerator(),
6062
createPodInitContainerResourceRequestsFamilyGenerator(),
@@ -580,6 +582,37 @@ func createPodInfoFamilyGenerator() generator.FamilyGenerator {
580582
)
581583
}
582584

585+
func createPodIPFamilyGenerator() generator.FamilyGenerator {
586+
return *generator.NewFamilyGenerator(
587+
"kube_pod_ips",
588+
"Pod IP addresses",
589+
metric.Gauge,
590+
"",
591+
wrapPodFunc(func(p *v1.Pod) *metric.Family {
592+
ms := make([]*metric.Metric, len(p.Status.PodIPs))
593+
labelKeys := []string{"ip", "ip_family"}
594+
595+
for i, ip := range p.Status.PodIPs {
596+
netIP := net.ParseIPSloppy(ip.IP)
597+
var ipFamily net.IPFamily
598+
if net.IsIPv4(netIP) {
599+
ipFamily = net.IPv4
600+
} else {
601+
ipFamily = net.IPv6
602+
}
603+
ms[i] = &metric.Metric{
604+
LabelKeys: labelKeys,
605+
LabelValues: []string{ip.IP, string(ipFamily)},
606+
Value: 1,
607+
}
608+
}
609+
610+
return &metric.Family{
611+
Metrics: ms,
612+
}
613+
}))
614+
}
615+
583616
func createPodInitContainerInfoFamilyGenerator() generator.FamilyGenerator {
584617
return *generator.NewFamilyGenerator(
585618
"kube_pod_init_container_info",

internal/store/pod_test.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -987,8 +987,16 @@ func TestPodStore(t *testing.T) {
987987
},
988988
},
989989
Status: v1.PodStatus{
990-
HostIP: "1.1.1.1",
991-
PodIP: "1.2.3.4",
990+
HostIP: "1.1.1.1",
991+
PodIP: "1.2.3.4",
992+
PodIPs: []v1.PodIP{
993+
{
994+
"1.2.3.4",
995+
},
996+
{
997+
"fc00:1234:5678:90ab:cdef:cafe:f00d:d00d",
998+
},
999+
},
9921000
StartTime: &metav1StartTime,
9931001
},
9941002
},
@@ -997,19 +1005,23 @@ func TestPodStore(t *testing.T) {
9971005
# HELP kube_pod_completion_time Completion time in unix timestamp for a pod.
9981006
# HELP kube_pod_created Unix creation timestamp
9991007
# HELP kube_pod_info Information about pod.
1008+
# HELP kube_pod_ips Pod IP addresses
10001009
# HELP kube_pod_owner Information about the Pod's owner.
10011010
# HELP kube_pod_start_time Start time in unix timestamp for a pod.
10021011
# TYPE kube_pod_completion_time gauge
10031012
# TYPE kube_pod_created gauge
10041013
# TYPE kube_pod_info gauge
1014+
# TYPE kube_pod_ips gauge
10051015
# TYPE kube_pod_owner gauge
10061016
# TYPE kube_pod_start_time gauge
10071017
kube_pod_created{namespace="ns1",pod="pod1",uid="abc-123-xxx"} 1.5e+09
10081018
kube_pod_info{created_by_kind="<none>",created_by_name="<none>",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
1019+
kube_pod_ips{namespace="ns1",pod="pod1",uid="abc-123-xxx",ip="1.2.3.4",ip_family="4"} 1
1020+
kube_pod_ips{namespace="ns1",pod="pod1",uid="abc-123-xxx",ip="fc00:1234:5678:90ab:cdef:cafe:f00d:d00d",ip_family="6"} 1
10091021
kube_pod_start_time{namespace="ns1",pod="pod1",uid="abc-123-xxx"} 1.501569018e+09
10101022
kube_pod_owner{namespace="ns1",owner_is_controller="<none>",owner_kind="<none>",owner_name="<none>",pod="pod1",uid="abc-123-xxx"} 1
10111023
`,
1012-
MetricNames: []string{"kube_pod_created", "kube_pod_info", "kube_pod_start_time", "kube_pod_completion_time", "kube_pod_owner"},
1024+
MetricNames: []string{"kube_pod_created", "kube_pod_info", "kube_pod_ips", "kube_pod_start_time", "kube_pod_completion_time", "kube_pod_owner"},
10131025
},
10141026
{
10151027
Obj: &v1.Pod{
@@ -2006,7 +2018,7 @@ func BenchmarkPodStore(b *testing.B) {
20062018
},
20072019
}
20082020

2009-
expectedFamilies := 44
2021+
expectedFamilies := 45
20102022
for n := 0; n < b.N; n++ {
20112023
families := f(pod)
20122024
if len(families) != expectedFamilies {

pkg/app/server_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ func TestFullScrapeCycle(t *testing.T) {
218218
# HELP kube_pod_init_container_status_terminated_reason Describes the reason the init container is currently in terminated state.
219219
# HELP kube_pod_init_container_status_waiting Describes whether the init container is currently in waiting state.
220220
# HELP kube_pod_init_container_status_waiting_reason Describes the reason the init container is currently in waiting state.
221+
# HELP kube_pod_ips Pod IP addresses
221222
# HELP kube_pod_labels Kubernetes labels converted to Prometheus labels.
222223
# HELP kube_pod_overhead_cpu_cores The pod overhead in regards to cpu cores associated with running a pod.
223224
# 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) {
261262
# TYPE kube_pod_init_container_status_terminated_reason gauge
262263
# TYPE kube_pod_init_container_status_waiting gauge
263264
# TYPE kube_pod_init_container_status_waiting_reason gauge
265+
# TYPE kube_pod_ips gauge
264266
# TYPE kube_pod_labels gauge
265267
# TYPE kube_pod_overhead_cpu_cores gauge
266268
# TYPE kube_pod_overhead_memory_bytes gauge

0 commit comments

Comments
 (0)