Skip to content
Open
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; | BETA |
| 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; | BETA |
| 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; | BETA |
| 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; | BETA |

## 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.BETA,
Copy link
Contributor

@CatherineF-dev CatherineF-dev Oct 8, 2025

Choose a reason for hiding this comment

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

STABLE

We don't have BETA stage in KSM now.

KSM's STABLE is k8s's BETA, which means we can add labels.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks @CatherineF-dev for reviewing
Got it, is it a recent change in KSM?

I have addressed your comments and reverted to STABLE b763076

"",
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.BETA,

"",
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.BETA,
"",
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.BETA,
"",
wrapStatefulSetFunc(func(s *v1.StatefulSet) *metric.Family {
ms := []*metric.Metric{}
Expand Down
Loading