- Introduction to Stateful Applications Stateful applications maintain data and rely on stable network identities. Examples include databases, message queues, and distributed file systems. Kubernetes provides StatefulSets to manage these applications efficiently.
Why StatefulSets?
- Stable Pod Identity: Each Pod gets a unique name and network identity.
- Stable Storage: PersistentVolumeClaims (PVCs) ensure data persists even if Pods are deleted.
- Ordered Deployment and Scaling: Pods are created, updated, and terminated in a specific order.
- Graceful Node Failures: Supports failover and recovery of stateful applications.
Key Features of StatefulSets
- Pod Identity Management: Each Pod gets a predictable hostname (e.g.,
pod-0,pod-1). - Persistent Storage: Ensures that data remains intact across Pod restarts.
- Rolling Updates: Updates Pods sequentially to minimize disruptions.
- Service Integration: Works with a Headless Service to provide stable DNS records.
Step-by-Step Implementation
Step 1: StatefulSet Basics
Create a Headless Service
A Headless Service ensures stable DNS entries for Pods in the StatefulSet.
- Create a YAML file (
headless-service.yaml):
apiVersion: v1
kind: Service
metadata:
name: stateful-app
spec:
clusterIP: None
selector:
app: stateful-app
2. Apply the Service:
kubectl apply -f headless-service.yaml
3. Verify the Service:
kubectl get svc
Deploy a StatefulSet
- Create a StatefulSet YAML (
statefulset.yaml):
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: stateful-app
spec:
serviceName: stateful-app
replicas: 3
selector:
matchLabels:
app: stateful-app
template:
metadata:
labels:
app: stateful-app
spec:
containers:
- name: app
image: busybox
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
volumeMounts:
- name: data
mountPath: /usr/share/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
2. Deploy the StatefulSet:
kubectl apply -f statefulset.yaml
3. Verify StatefulSet Pods:
kubectl get pods -l app=stateful-app
4. Inspect the PersistentVolumeClaims:
kubectl get pvc
Step 2: Accessing StatefulSet Pods
Each Pod in the StatefulSet gets a unique DNS name.
- Pod DNS Format:
<statefulset-name>-<ordinal>.<service-name>
Example:
stateful-app-0.stateful-app
2. Ping Other Pods: Exec into a Pod and ping another Pod:
kubectl exec -it stateful-app-0 -- ping stateful-app-1.stateful-app
Step 3: Scaling a StatefulSet
Scale Up
Increase the replicas in the StatefulSet:
kubectl scale statefulset stateful-app --replicas=5\
Verify the new Pods
kubectl get pods
Scale Down
Reduce the replicas in the StatefulSet:
kubectl scale statefulset stateful-app --replicas=2
Notice that the highest numbered Pods are deleted first.
Step 4: Rolling Updates for StatefulSets
- Update the image in the StatefulSet YAML:
containers:
- name: app
image: busybox:latest
2. Apply the changes:
kubectl apply -f statefulset.yaml
3. Monitor the update:
kubectl rollout status statefulset stateful-app
Step 5: Troubleshooting StatefulSets
1. Check Pod Logs:
kubectl logs stateful-app-0
2. Describe Pods:
kubectl describe pod stateful-app-0
3. Debug DNS Issues:
kubectl exec -it stateful-app-0 -- nslookup stateful-app-1.stateful-app
4. Recover PVCs: If a Pod is deleted, ensure the PVC is bound to the replacement Pod.
Best Practices for StatefulSets
- Use ReadWriteOnce Volumes: For applications that need dedicated storage.
- Enable PodDisruptionBudgets (PDBs): Protect against voluntary disruptions.
- Design for Failover: Test how the application handles Pod failures.
- Monitor Performance: Use tools like Prometheus and Grafana.
- Avoid Overprovisioning: Match PVC requests to storage needs.
Production Example: Deploying a Stateful Database
Scenario
Deploy a MySQL database using StatefulSets.
1. Create a Headless Service for MySQL:
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
clusterIP: None
selector:
app: mysql
2. Create a MySQL StatefulSet:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "rootpassword"
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 5Gi
3. Apply and Test:
kubectl apply -f mysql-statefulset.yaml
Verify Pods:
kubectl get pods -l app=mysql
Test MySQL connection:
kubectl exec -it mysql-0 -- mysql -u root -p
Conclusion
In this chapter, you learned:
- How to use StatefulSets for managing stateful workloads.
- How to scale and update StatefulSets.
- Best practices for deploying stateful applications in Kubernetes.