Review the StatefulSet headless Service association

Configure a headless Service for the StatefulSet’s stable network identities.

Description

A StatefulSet references a headless Service through spec.service_name to provide stable network names for its pods. Configure cluster_ip = "None" on a Service in the same namespace, with a selector matching the actual pod labels.

Referring to an ordinary Service or an incorrect selector can prevent the expected per-pod DNS names and peer discovery from working.

Potential impact

  • Peers may be unreachable through stable pod DNS names.
  • Unreliable discovery during restarts or scaling can complicate recovery of stateful applications.

Remediation

  • Point the StatefulSet’s service_name to a headless Service in the same namespace and set the Service’s cluster_ip to "None".
  • Verify the Service selector against actual pod labels, ports and DNS responses. Create the Service separately.

Examples

These excerpts show the Service association only; the required pod template, Service ports and other settings are omitted. The before excerpt omits cluster_ip for ordinary ClusterIP allocation, while the after excerpt selects a headless Service.

Before

hcl
resource "kubernetes_service" "example" {
  metadata {
    name      = "prometheus"
    namespace = "monitoring"
  }

  spec {
    selector = {
      app = "prometheus"
    }
  }
}

resource "kubernetes_stateful_set" "example" {
  metadata {
    name      = "prometheus"
    namespace = "monitoring"
  }

  spec {
    service_name = "prometheus"

    selector {
      match_labels = {
        app = "prometheus"
      }
    }
  }
}

After

hcl
resource "kubernetes_service" "example" {
  metadata {
    name      = "prometheus"
    namespace = "monitoring"
  }

  spec {
    cluster_ip = "None"

    selector = {
      app = "prometheus"
    }
  }
}

resource "kubernetes_stateful_set" "example" {
  metadata {
    name      = "prometheus"
    namespace = "monitoring"
  }

  spec {
    service_name = "prometheus"

    selector {
      match_labels = {
        app = "prometheus"
      }
    }
  }
}

Explanation:

  • Before: The StatefulSet references an ordinary ClusterIP Service, not a headless Service.
  • After: cluster_ip is set to None. The omitted pod template must also carry labels matching the selector.

References