Skip to content
107 changes: 103 additions & 4 deletions docs/metrics/workload/statefulset-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,118 @@

| Metric name | Metric type | Description | Labels/tags | Status |
| ------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
| kube_statefulset_annotations | Gauge | Kubernetes annotations converted to Prometheus labels controlled via [--metric-annotations-allowlist](../../developer/cli-arguments.md) | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; <br> `annotation_STATEFULSET_ANNOTATION`=&lt;STATEFULSET_ANNOTATION&gt; | EXPERIMENTAL |
| kube_statefulset_annotations | Gauge | Kubernetes annotations converted to Prometheus labels controlled via [--metric-annotations-allowlist](../../developer/cli-arguments.md) | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; <br> `annotation_STATEFULSET_ANNOTATION`=&lt;STATEFULSET_ANNOTATION&gt; | STABLE |
| kube_statefulset_status_replicas | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_status_replicas_current | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_status_replicas_ready | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_status_replicas_available | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | EXPERIMENTAL |
| kube_statefulset_status_replicas_available | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_status_replicas_updated | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_status_observed_generation | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_replicas | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_ordinals_start | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_metadata_generation | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_persistentvolumeclaim_retention_policy | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; <br> `when_deleted`=&lt;statefulset-when-deleted-pvc-policy&gt; <br> `when_scaled`=&lt;statefulset-when-scaled-pvc-policy&gt; | EXPERIMENTAL |
| kube_statefulset_persistentvolumeclaim_retention_policy | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; <br> `when_deleted`=&lt;statefulset-when-deleted-pvc-policy&gt; <br> `when_scaled`=&lt;statefulset-when-scaled-pvc-policy&gt; | STABLE |
| kube_statefulset_created | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |
| kube_statefulset_labels | Gauge | Kubernetes labels converted to Prometheus labels controlled via [--metric-labels-allowlist](../../developer/cli-arguments.md) | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; <br> `label_STATEFULSET_LABEL`=&lt;STATEFULSET_LABEL&gt; | STABLE |
| kube_statefulset_status_current_revision | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; <br> `revision`=&lt;statefulset-current-revision&gt; | STABLE |
| kube_statefulset_status_update_revision | Gauge | | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; <br> `revision`=&lt;statefulset-update-revision&gt; | STABLE |
| kube_statefulset_deletion_timestamp | Gauge | Unix deletion timestamp | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | EXPERIMENTAL |
| kube_statefulset_deletion_timestamp | Gauge | Unix deletion timestamp | `statefulset`=&lt;statefulset-name&gt; <br> `namespace`=&lt;statefulset-namespace&gt; | STABLE |

## Common PromQL Queries

### StatefulSet Health Monitoring

Copy link
Member

@nmn3m nmn3m Oct 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that you added some PromQL troubleshooting query examples under the metric definition. From my understanding, this file (docs/metrics/workload/statefulset-metrics.md) is meant to document the metrics themselves (type, labels, stability), not usage or example queries.

I think you should remove them.
Thanks.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! Thank you for the feedback.
I added the PromQL examples because I noticed the Pod metrics documentation (docs/metrics/workload/pod-metrics.md) includes similar usage examples and queries, and the main README mentions welcoming "sample usages" contributions.
I was trying to follow that same pattern for consistency. Please add your thoughts.
I'm happy to adjust based on what works best for the project!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yasicar, You are right, thanks for mentioning that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nmn3m Thanks
This is my first contribution to kube-state-metrics, and I'd really appreciate your help completing this review.

**Check StatefulSet rollout status:**

```promql
# Percentage of updated replicas
(kube_statefulset_status_replicas_updated / kube_statefulset_replicas) * 100
```

**Monitor unavailable replicas:**

```promql
# Number of unavailable replicas
kube_statefulset_replicas - kube_statefulset_status_replicas_available
```

### Troubleshooting Queries

**Find StatefulSets with outdated replicas:**

```promql
# StatefulSets with replicas not yet updated
kube_statefulset_status_replicas_current != kube_statefulset_status_replicas_updated
```

**StatefulSets stuck during rollout:**

```promql
# StatefulSets where observed generation is behind metadata generation
kube_statefulset_status_observed_generation < kube_statefulset_metadata_generation
```

**StatefulSets with scaling issues:**

```promql
# StatefulSets where current replicas don't match desired
kube_statefulset_status_replicas_current != kube_statefulset_replicas
```

## Major Alerting Rules

### Critical Alerts

**StatefulSet is completely down:**

```yaml
- alert: StatefulSetDown
expr: kube_statefulset_status_replicas_available == 0 and kube_statefulset_replicas > 0
for: 5m
labels:
severity: critical
annotations:
summary: "StatefulSet {{ $labels.statefulset }} is completely down"
description: "StatefulSet {{ $labels.statefulset }} in namespace {{ $labels.namespace }} has no available replicas despite having {{ $labels.replicas }} desired replicas."
```

**StatefulSet rollout stuck:**

```yaml
- alert: StatefulSetRolloutStuck
expr: kube_statefulset_status_observed_generation < kube_statefulset_metadata_generation
for: 15m
labels:
severity: critical
annotations:
summary: "StatefulSet {{ $labels.statefulset }} rollout is stuck"
description: "StatefulSet {{ $labels.statefulset }} in namespace {{ $labels.namespace }} has been stuck rolling out for more than 15 minutes."
```

### Warning Alerts

**StatefulSet has unavailable replicas:**

```yaml
- alert: StatefulSetReplicasUnavailable
expr: (kube_statefulset_replicas - kube_statefulset_status_replicas_available) > 0
for: 5m
labels:
severity: warning
annotations:
summary: "StatefulSet {{ $labels.statefulset }} has unavailable replicas"
description: "StatefulSet {{ $labels.statefulset }} in namespace {{ $labels.namespace }} has {{ $value }} unavailable replicas."
```

**StatefulSet replica count mismatch:**

```yaml
- alert: StatefulSetReplicasMismatch
expr: kube_statefulset_status_replicas_current != kube_statefulset_replicas
for: 10m
labels:
severity: warning
annotations:
summary: "StatefulSet {{ $labels.statefulset }} replica count mismatch"
description: "StatefulSet {{ $labels.statefulset }} in namespace {{ $labels.namespace }} has {{ $labels.status_replicas_current }} current replicas but {{ $labels.replicas }} are desired."
```
8 changes: 4 additions & 4 deletions internal/store/statefulset.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func statefulSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) [
"kube_statefulset_status_replicas_available",
"The number of available replicas per StatefulSet.",
metric.Gauge,
basemetrics.ALPHA,
basemetrics.STABLE,
Copy link
Member

@nmn3m nmn3m Oct 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This metric will need to be in BETA for a quite time then we can promote it to STABLE,
you can read this as I have the same situation before, #2749 (comment)

Copy link
Author

@yasicar yasicar Oct 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nmn3m
Sure Thanks
I have addressed your comment and updated the entire PR to promote these metrics to BETA instead of STABLE.
d843208

"",
wrapStatefulSetFunc(func(s *v1.StatefulSet) *metric.Family {
return &metric.Family{
Expand Down Expand Up @@ -218,7 +218,7 @@ func statefulSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) [
"kube_statefulset_persistentvolumeclaim_retention_policy",
"Count of retention policy for StatefulSet template PVCs",
metric.Gauge,
basemetrics.ALPHA,
basemetrics.STABLE,

"",
wrapStatefulSetFunc(func(s *v1.StatefulSet) *metric.Family {
Expand All @@ -245,7 +245,7 @@ func statefulSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) [
descStatefulSetAnnotationsName,
descStatefulSetAnnotationsHelp,
metric.Gauge,
basemetrics.ALPHA,
basemetrics.STABLE,
"",
wrapStatefulSetFunc(func(s *v1.StatefulSet) *metric.Family {
if len(allowAnnotationsList) == 0 {
Expand Down Expand Up @@ -325,7 +325,7 @@ func statefulSetMetricFamilies(allowAnnotationsList, allowLabelsList []string) [
"kube_statefulset_deletion_timestamp",
"Unix deletion timestamp",
metric.Gauge,
basemetrics.ALPHA,
basemetrics.STABLE,
"",
wrapStatefulSetFunc(func(s *v1.StatefulSet) *metric.Family {
ms := []*metric.Metric{}
Expand Down
Loading