diff --git a/docs/pod-metrics.md b/docs/pod-metrics.md
index 627ae4f90c..74c0bf2d94 100644
--- a/docs/pod-metrics.md
+++ b/docs/pod-metrics.md
@@ -11,6 +11,7 @@
| kube_pod_labels | Gauge | Kubernetes labels converted to Prometheus labels | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`label_POD_LABEL`=<POD_LABEL>
`uid`=<pod-uid> | STABLE | - |
| kube_pod_nodeselectors| Gauge | Describes the Pod nodeSelectors | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`nodeselector_NODE_SELECTOR`=<NODE_SELECTOR>
`uid`=<pod-uid> | EXPERIMENTAL | Opt-in |
| kube_pod_status_phase | Gauge | The pods current phase | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`phase`=<Pending\|Running\|Succeeded\|Failed\|Unknown>
`uid`=<pod-uid> | STABLE | - |
+| kube_pod_status_qos_class | Gauge | The pods current qosClass | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`qos_class`=<BestEffort\|Burstable\|Guaranteed>
`uid`=<pod-uid> | EXPERIMENTAL | - |
| kube_pod_status_ready | Gauge | Describes whether the pod is ready to serve requests | | `pod`=<pod-name>
`namespace`=<pod-namespace>
`condition`=<true\|false\|unknown>
`uid`=<pod-uid> | STABLE | - |
| kube_pod_status_scheduled | Gauge | Describes the status of the scheduling process for the pod | |`pod`=<pod-name>
`namespace`=<pod-namespace>
`condition`=<true\|false\|unknown>
`uid`=<pod-uid> | STABLE | - |
| kube_pod_container_info | Gauge | Information about a container in a pod | | `container`=<container-name>
`pod`=<pod-name>
`namespace`=<pod-namespace>
`image`=<image-name>
`image_id`=<image-id>
`image_spec`=<image-spec>
`container_id`=<containerid>
`uid`=<pod-uid> | STABLE | - |
diff --git a/internal/store/pod.go b/internal/store/pod.go
index f9bfdd21f2..9d7fbc4f3d 100644
--- a/internal/store/pod.go
+++ b/internal/store/pod.go
@@ -82,6 +82,7 @@ func podMetricFamilies(allowAnnotationsList, allowLabelsList []string) []generat
createPodSpecVolumesPersistentVolumeClaimsReadonlyFamilyGenerator(),
createPodStartTimeFamilyGenerator(),
createPodStatusPhaseFamilyGenerator(),
+ createPodStatusQosClassFamilyGenerator(),
createPodStatusReadyFamilyGenerator(),
createPodStatusReasonFamilyGenerator(),
createPodStatusScheduledFamilyGenerator(),
@@ -1317,6 +1318,48 @@ func createPodStatusPhaseFamilyGenerator() generator.FamilyGenerator {
)
}
+func createPodStatusQosClassFamilyGenerator() generator.FamilyGenerator {
+ return *generator.NewFamilyGeneratorWithStability(
+ "kube_pod_status_qos_class",
+ "The pods current qosClass.",
+ metric.Gauge,
+ basemetrics.ALPHA,
+ "",
+ wrapPodFunc(func(p *v1.Pod) *metric.Family {
+ class := p.Status.QOSClass
+ if class == "" {
+ return &metric.Family{
+ Metrics: []*metric.Metric{},
+ }
+ }
+
+ qosClasses := []struct {
+ v bool
+ n string
+ }{
+ {class == v1.PodQOSBestEffort, string(v1.PodQOSBestEffort)},
+ {class == v1.PodQOSBurstable, string(v1.PodQOSBurstable)},
+ {class == v1.PodQOSGuaranteed, string(v1.PodQOSGuaranteed)},
+ }
+
+ ms := make([]*metric.Metric, len(qosClasses))
+
+ for i, p := range qosClasses {
+ ms[i] = &metric.Metric{
+
+ LabelKeys: []string{"qos_class"},
+ LabelValues: []string{p.n},
+ Value: boolFloat64(p.v),
+ }
+ }
+
+ return &metric.Family{
+ Metrics: ms,
+ }
+ }),
+ )
+}
+
func createPodStatusReadyFamilyGenerator() generator.FamilyGenerator {
return *generator.NewFamilyGeneratorWithStability(
"kube_pod_status_ready",
diff --git a/internal/store/pod_test.go b/internal/store/pod_test.go
index fb118f2d1c..1f42d0b7c4 100644
--- a/internal/store/pod_test.go
+++ b/internal/store/pod_test.go
@@ -1294,6 +1294,26 @@ func TestPodStore(t *testing.T) {
`,
MetricNames: []string{"kube_pod_status_phase", "kube_pod_status_reason"},
},
+ {
+ Obj: &v1.Pod{
+ ObjectMeta: metav1.ObjectMeta{
+ Name: "pod1",
+ Namespace: "ns1",
+ UID: "uid1",
+ },
+ Status: v1.PodStatus{
+ QOSClass: v1.PodQOSBestEffort,
+ },
+ },
+ Want: `
+ # HELP kube_pod_status_qos_class The pods current qosClass.
+ # TYPE kube_pod_status_qos_class gauge
+ kube_pod_status_qos_class{namespace="ns1",qos_class="BestEffort",pod="pod1",uid="uid1"} 1
+ kube_pod_status_qos_class{namespace="ns1",qos_class="Burstable",pod="pod1",uid="uid1"} 0
+ kube_pod_status_qos_class{namespace="ns1",qos_class="Guaranteed",pod="pod1",uid="uid1"} 0
+`,
+ MetricNames: []string{"kube_pod_status_qos_class"},
+ },
{
Obj: &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
@@ -2079,7 +2099,7 @@ func BenchmarkPodStore(b *testing.B) {
},
}
- expectedFamilies := 47
+ expectedFamilies := 48
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 659b84bf24..aefeef891a 100644
--- a/pkg/app/server_test.go
+++ b/pkg/app/server_test.go
@@ -238,6 +238,7 @@ func TestFullScrapeCycle(t *testing.T) {
# HELP kube_pod_spec_volumes_persistentvolumeclaims_info [STABLE] Information about persistentvolumeclaim volumes in a pod.
# HELP kube_pod_spec_volumes_persistentvolumeclaims_readonly [STABLE] Describes whether a persistentvolumeclaim is mounted read only.
# HELP kube_pod_start_time [STABLE] Start time in unix timestamp for a pod.
+# HELP kube_pod_status_qos_class The pods current qosClass.
# HELP kube_pod_status_phase [STABLE] The pods current phase.
# HELP kube_pod_status_ready [STABLE] Describes whether the pod is ready to serve requests.
# HELP kube_pod_status_reason The pod status reasons
@@ -285,6 +286,7 @@ func TestFullScrapeCycle(t *testing.T) {
# TYPE kube_pod_spec_volumes_persistentvolumeclaims_readonly gauge
# TYPE kube_pod_start_time gauge
# TYPE kube_pod_status_phase gauge
+# TYPE kube_pod_status_qos_class gauge
# TYPE kube_pod_status_ready gauge
# TYPE kube_pod_status_reason gauge
# TYPE kube_pod_status_scheduled gauge