Amazon EKS — StatefulSets on EKS

2 minute read

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

  1. Use gp3 StorageClass for cost-effective EBS volumes (see Storage)
  2. Configure PodDisruptionBudgets — StatefulSets are sensitive to disruptions
  3. Back up your data — EBS snapshots via Velero or the CSI snapshot controller
  4. Use headless Services for stable per-pod DNS names
  5. Set podManagementPolicy: Parallel if ordering doesn’t matter (faster scaling)
  6. Consider managed databases for critical production workloads (RDS, Aurora, DynamoDB)

Updated: