Running Stateful Applications on Kubernetes
- 1 day ago
- 3 min read

Kubernetes has become the go-to platform for deploying and scaling stateless applications. But when it comes to stateful workloads — databases, message queues, and storage-dependent systems — things get more complex. These applications need stable identities, persistent storage, and careful lifecycle management.
In this post, we’ll explore the challenges of running stateful applications in Kubernetes, and the solutions available through features like StatefulSets, Persistent Volumes (PVs), and Operators.
The Challenges of Running Stateful Applications
While Kubernetes offers powerful orchestration capabilities, stateful workloads introduce unique issues:
1 - Stable Network Identity
Databases like PostgreSQL or message brokers like RabbitMQ often require stable hostnames for clustering and replication.
2 - Persistent Storage
Pods in Kubernetes are ephemeral. Stateful apps need their data to persist across pod restarts and node failures.
3 - Ordered, Graceful Lifecycle
Stateful systems often depend on the order in which instances are started or shut down (e.g., leader/follower replication) and require graceful shutdown to avoid data corruption.
4 - Configuration Complexity
Managing complex configurations such as replication factors, backup policies, or sharding strategies can become operational overhead.
Kubernetes to the Rescue: Key Constructs
To solve these challenges, Kubernetes provides a few important primitives:
1 - StatefulSets
StatefulSets are Kubernetes controllers designed for managing stateful applications. They differ from Deployments in several important ways:
Feature | Deployment | StatefulSet |
Pod Identity | Ephemeral | Stable (pod-0, pod-1...) |
Storage | Shared / ephemeral | Stable + per-pod PVC |
Startup Order | Unordered | Ordered |
Scaling | Simple | Requires ordered coordination |
Each pod in a StatefulSet gets a stable DNS name (<podname>.<service>.namespace.svc.cluster.local) and a persistent volume claim (PVC) that sticks with it, even if it’s rescheduled.
Use cases:
Databases: PostgreSQL, MySQL, MongoDB
Message queues: Kafka, RabbitMQ
Storage clusters: Cassandra, Elasticsearch
Example:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
spec:
serviceName: "postgres"
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15
volumeMounts:
- name: pgdata
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: pgdata
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
2 - Persistent Volumes and Persistent Volume Claims
Persistent Volumes (PVs) are pieces of storage in the cluster provisioned by an admin or dynamically created using a StorageClass.
PVCs are how users request storage.
When used with StatefulSets, each pod gets its own PVC.
Kubernetes ensures the PVC is reattached to the correct pod, even if rescheduled on a different node.
Common backends:
AWS EBS / EFS
GCP Persistent Disks
Azure Disk
Ceph, Longhorn, OpenEBS (for on-prem)
Example of dynamic provisioning:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pgdata
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: standard
3 - Operators
Operators extend Kubernetes by automating the operational tasks for complex stateful applications. They are essentially custom controllers that manage CRDs (Custom Resource Definitions).
What Operators do:
Manage application lifecycle
Automate backups, upgrades, and failover
Configure clustering, replication, sharding
Ensure desired state
Examples of popular Operators:
Application | Operator |
PostgreSQL | |
MongoDB | |
Kafka | |
Redis |
Benefits:
Reduce manual intervention
Enforce best practices
Enable GitOps workflows with CRDs
Real-World Example: Running a Highly Available PostgreSQL Cluster
Here’s how you might set up a HA PostgreSQL cluster on Kubernetes:
Install a PostgreSQL Operator:
kubectl apply -f https://github.com/CrunchyData/postgres-operator-examples/
Create a PostgreSQL Cluster CR:
apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
name: hippo
spec:
instances:
- replicas: 3
backups:
pgbackrest:
repos:
- name: repo1
volume:
volumeClaimSpec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
patroni:
dynamicConfiguration:
synchronous_mode: true
Access the Cluster via a service:
kubectl get svc hippo-pgbouncer
Best Practices
Choose the right storage class: Make sure it supports ReadWriteOnce or ReadWriteMany depending on the workload.
Use PodDisruptionBudgets: To avoid accidental downtime during upgrades or node drains.
Backup strategies: Use volume snapshots, or leverage Operators that support pgBackRest or similar tools.
Monitor and alert: Prometheus + Grafana stack is great for DB metrics and alerting.
Avoid anti-patterns:
Don’t use Deployments for stateful apps.
Avoid sharing PVCs across pods unless explicitly supported.
Conclusion
Running stateful applications on Kubernetes is no longer a fringe idea — it’s a production reality. While it introduces complexities, Kubernetes provides a rich ecosystem of primitives and tooling to handle it reliably.
At Ananta Cloud, we help teams simplify the deployment and management of critical stateful workloads on Kubernetes. Whether you’re running databases, data lakes, or streaming systems, our platform provides the reliability, automation, and observability you need.
📢 Need help with stateful workloads on Kubernetes?
Reach out to us at hello@anantacloud.com or visit www.anantacloud.com to learn how we can help.
Comments