Kubernetes StatefulSets for stateful workloads
# Headless Service for stable DNS
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: production
labels:
app: postgres
spec:
clusterIP: None
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
---
# StatefulSet for PostgreSQL
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: production
spec:
serviceName: postgres
replicas: 3
podManagementPolicy: OrderedReady
selector:
matchLabels:
app: postgres
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0
template:
metadata:
labels:
app: postgres
spec:
terminationGracePeriodSeconds: 120
securityContext:
runAsUser: 999
fsGroup: 999
initContainers:
- name: init-permissions
image: busybox:1.36
command:
- sh
- -c
- |
chown -R 999:999 /var/lib/postgresql/data
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
containers:
- name: postgres
image: postgres:16-alpine
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_DB
value: myapp
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
# Replication config for replicas
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: "2"
memory: 4Gi
readinessProbe:
exec:
command:
- pg_isready
- -U
- postgres
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 5
livenessProbe:
exec:
command:
- pg_isready
- -U
- postgres
initialDelaySeconds: 30
periodSeconds: 30
timeoutSeconds: 5
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
- name: postgres-config
mountPath: /etc/postgresql/conf.d
volumes:
- name: postgres-config
configMap:
name: postgres-config
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: gp3
resources:
requests:
storage: 50Gi
---
# ConfigMap for PostgreSQL tuning
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
namespace: production
data:
custom.conf: |
max_connections = 200
shared_buffers = 1GB
effective_cache_size = 3GB
work_mem = 16MB
maintenance_work_mem = 256MB
wal_buffers = 16MB
checkpoint_completion_target = 0.9
random_page_cost = 1.1
log_min_duration_statement = 1000
log_statement = 'ddl'
---
# StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
encrypted: "true"
iops: "3000"
throughput: "125"
reclaimPolicy: Retain
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
StatefulSets manage stateful applications requiring stable identities and persistent storage. Unlike Deployments, StatefulSets provide ordered Pod creation (pod-0, pod-1, pod-2) and stable network identifiers. Each Pod gets a predictable hostname via a headless Service. volumeClaimTemplates create a unique PersistentVolumeClaim for each replica. Pods maintain their identity across rescheduling—pod-0 always reattaches to the same volume. Ordered deployment and scaling ensure pod-0 starts before pod-1. podManagementPolicy: Parallel allows simultaneous startup when ordering is unnecessary. StatefulSets are essential for databases, message queues, and distributed systems like Kafka, Elasticsearch, and ZooKeeper. Update strategies support RollingUpdate with partition for canary rollouts.