Skip to main content

Lab 7.1 - StatefulSet for Database

Lab Objectives​

By the end of this lab, you will be able to:

  • Deploy a database (MySQL) with a StatefulSet.
  • Configure persistent storage for a database.
  • Understand the importance of startup order for databases.
  • Configure a headless Service for discovery.
  • Test database data persistence.

Estimated Duration​

60-75 minutes

Prerequisites​

  • kubectl installed and configured.
  • Functional local Kubernetes cluster (minikube or kind).
  • Knowledge of StatefulSets (Chapter 7.1).

Part 1: Preparing the StorageClass​

Create a StorageClass for database storage:

# storageclass-mysql.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: mysql-storage
provisioner: k8s.io/minikube-hostpath # For minikube
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete

Apply the StorageClass:

kubectl apply -f storageclass-mysql.yaml

Part 2: Creating the Secret for MySQL​

Create a Secret to store the MySQL root password:

# mysql-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
data:
mysql-root-password: cGFzc3dvcmQxMjM= # "password123" in base64
mysql-password: cGFzc3dvcmQxMjM= # "password123" in base64

Apply the Secret:

kubectl apply -f mysql-secret.yaml

Part 3: Creating the Headless Service​

A StatefulSet requires a headless Service for DNS discovery:

# mysql-service.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
labels:
app: mysql
spec:
ports:
- port: 3306
name: mysql
clusterIP: None # Headless service
selector:
app: mysql

Apply the Service:

kubectl apply -f mysql-service.yaml

Part 4: Creating the MySQL StatefulSet​

Create the StatefulSet for MySQL with persistent storage:

# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql # Name of the headless Service
replicas: 1 # For this lab, a single MySQL instance
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
initContainers:
- name: init-mysql
image: busybox:1.35
command:
- sh
- -c
- |
# Create the data directory if needed
if [ ! -d /var/lib/mysql/mysql ]; then
echo "Initializing MySQL data directory"
fi
volumeMounts:
- name: data
mountPath: /var/lib/mysql
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: mysql-root-password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: data
mountPath: /var/lib/mysql
resources:
requests:
cpu: 500m
memory: 512Mi
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: mysql-storage
resources:
requests:
storage: 1Gi

Apply the StatefulSet:

kubectl apply -f mysql-statefulset.yaml

Part 5: Verifying the Deployment​

Step 5.1: Verify the Pod​

Wait for the Pod to be Running:

kubectl get pods -l app=mysql

Check the logs to ensure MySQL starts correctly:

kubectl logs mysql-0

Step 5.2: Verify the PVC​

Check that the PVC was created:

kubectl get pvc

You should see a PVC named data-mysql-0.


Part 6: Testing the Database​

Step 6.1: Create a Database and a Table​

Connect to MySQL and create a test database:

kubectl exec -it mysql-0 -- mysql -uroot -ppassword123 -e "CREATE DATABASE testdb;"
kubectl exec -it mysql-0 -- mysql -uroot -ppassword123 -e "USE testdb; CREATE TABLE users (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50));"
kubectl exec -it mysql-0 -- mysql -uroot -ppassword123 -e "USE testdb; INSERT INTO users (name) VALUES ('Alice'), ('Bob'), ('Charlie');"

Step 6.2: Verify the Data​

Check that the data was inserted:

kubectl exec -it mysql-0 -- mysql -uroot -ppassword123 -e "USE testdb; SELECT * FROM users;"

Part 7: Testing Persistence​

Step 7.1: Delete the Pod​

Delete the Pod to test persistence:

kubectl delete pod mysql-0

The StatefulSet will automatically recreate the Pod with the same name.

Wait for the new Pod to be Running:

kubectl get pods -l app=mysql

Wait a few seconds for MySQL to fully restart:

kubectl logs mysql-0 -f

Press Ctrl+C once MySQL is ready.

Step 7.2: Verify Data Persistence​

Check that the data is still present:

kubectl exec -it mysql-0 -- mysql -uroot -ppassword123 -e "USE testdb; SELECT * FROM users;"

You should see the three users (Alice, Bob, Charlie), proving that the data persisted!


Part 8: Cleanup​

Delete the created resources:

kubectl delete statefulset mysql
kubectl delete service mysql
kubectl delete secret mysql-secret
kubectl delete pvc data-mysql-0
kubectl delete -f storageclass-mysql.yaml

Lab Summary​

In this lab, you deployed a MySQL database with a StatefulSet. You learned how to configure persistent storage for a database, use Secrets for passwords, and test data persistence during restarts. StatefulSets are ideal for stateful applications like databases.


Next Steps​

The next lab will show you how to use DaemonSets to deploy agents on all nodes.

Lab 7.2: DaemonSet for Monitoring


Lab created: December 2024