Amazon EKS — StatefulSets on EKS
StatefulSets provide stable identities, persistent storage, and ordered deployment for stateful workloads like databases, message queues, and caches.
StatefulSet Fundamentals
| Feature | Deployment | StatefulSet |
|---|---|---|
| Pod names | Random (web-api-abc123) | Ordered (db-0, db-1, db-2) |
| Storage | Shared or none | Per-pod PersistentVolumeClaim |
| Network identity | Via Service | Headless Service + stable DNS |
| Scaling | Parallel | Ordered (one at a time) |
| Deletion | Parallel | Reverse order |
EBS-Backed StatefulSet
Most common pattern on EKS — each pod gets its own EBS volume:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: production
spec:
serviceName: postgres-headless
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: pg-credentials
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
memory: "2Gi"
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: gp3
resources:
requests:
storage: 50Gi
---
apiVersion: v1
kind: Service
metadata:
name: postgres-headless
namespace: production
spec:
type: ClusterIP
clusterIP: None
selector:
app: postgres
ports:
- port: 5432
Stable DNS Names
Each pod gets a predictable DNS entry:
postgres-0.postgres-headless.production.svc.cluster.local
postgres-1.postgres-headless.production.svc.cluster.local
postgres-2.postgres-headless.production.svc.cluster.local
EFS for Shared Stateful Storage
When multiple pods need to read/write the same data, use EFS (ReadWriteMany):
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-data
namespace: production
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 100Gi
Mount in a StatefulSet or Deployment:
volumes:
- name: shared
persistentVolumeClaim:
claimName: shared-data
See EFS CSI Driver for setup.
EBS Limitations for StatefulSets
| Limitation | Impact |
|---|---|
| Single AZ | EBS volumes are AZ-bound; pod must reschedule in the same AZ |
| Single attach | Only one node can mount an EBS volume at a time (ReadWriteOnce) |
| Resize | Supported, but takes time and can’t exceed once every 6 hours |
To mitigate the AZ issue, use topologySpreadConstraints:
spec:
template:
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: postgres
Should You Run Databases on EKS?
| Scenario | Recommendation |
|---|---|
| Dev/test databases | Yes — StatefulSets on EKS with EBS |
| Small production databases | Maybe — if your team can manage backups and failover |
| Critical production databases | Use RDS, Aurora, or DynamoDB — managed services handle replication, backups, and failover |
| Redis/Memcached cache | ElastiCache is usually better, but EKS-native is fine for non-critical use |
Rule of thumb: Run databases on EKS if you need portability or have a strong Kubernetes operations team. Use managed AWS services if you want less operational burden.
Best Practices
- Use
gp3StorageClass for cost-effective EBS volumes (see Storage) - Configure PodDisruptionBudgets — StatefulSets are sensitive to disruptions
- Back up your data — EBS snapshots via Velero or the CSI snapshot controller
- Use headless Services for stable per-pod DNS names
- Set
podManagementPolicy: Parallelif ordering doesn’t matter (faster scaling) - Consider managed databases for critical production workloads (RDS, Aurora, DynamoDB)