PART 1 — StatefulSet + Headless Service + Persistent Storage

Source: Dev.to | Jan 12, 2026 (UTC)

Goal: Deploy a stateful MySQL cluster correctly in Kubernetes and understand every moving part.

LAB PREREQUISITES (DO NOT SKIP)

You need one working Kubernetes cluster:

  • Minikube

Verify:

kubectl get nodes

Enter fullscreen mode

Exit fullscreen mode

You must see Ready.

STEP 0 — WHAT WE ARE BUILDING (VISUAL FIRST)

Final architecture

STEP 1 — CREATE A NAMESPACE (CLEAN ISOLATION)

kubectl create namespace mysql-lab kubectl config set-context --current --namespace=mysql-lab

Enter fullscreen mode

Exit fullscreen mode

Verify:

kubectl get ns

Enter fullscreen mode

Exit fullscreen mode

STEP 2 — HEADLESS SERVICE (MOST IMPORTANT FILE)

File: mysql-headless.yaml

apiVersion: v1 kind: Service metadata: name: mysql-headless spec: clusterIP: None selector: app: mysql ports: - port: 3306 name: mysql

Enter fullscreen mode

Exit fullscreen mode

Apply:

kubectl apply -f mysql-headless.yaml

Enter fullscreen mode

Exit fullscreen mode

Verify:

kubectl get svc

Enter fullscreen mode

Exit fullscreen mode

You must see:

mysql-headless ClusterIP None

Enter fullscreen mode

Exit fullscreen mode

🔍 WHAT THIS DOES (VISUAL)

⚠️ Alone this is NOT ENOUGH — identity still missing

STEP 3 — STATEFULSET (THE CORE)

File: mysql-statefulset.yaml

apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: mysql-headless replicas: 3 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 env: - name: MYSQL_ROOT_PASSWORD value: rootpass ports: - containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 1Gi

Enter fullscreen mode

Exit fullscreen mode

Apply:

kubectl apply -f mysql-statefulset.yaml

Enter fullscreen mode

Exit fullscreen mode

STEP 4 — WATCH POD CREATION (ORDER MATTERS)

kubectl get pods -w

Enter fullscreen mode

Exit fullscreen mode

You will see:

mysql-0 → Running mysql-1 → Running mysql-2 → Running

Enter fullscreen mode

Exit fullscreen mode

🔍 IMPORTANT

STEP 5 — VERIFY STABLE POD NAMES

kubectl get pods

Enter fullscreen mode

Exit fullscreen mode

Expected:

mysql-0 mysql-1 mysql-2

Enter fullscreen mode

Exit fullscreen mode

Restart one pod:

kubectl delete pod mysql-1

Enter fullscreen mode

Exit fullscreen mode

Watch:

kubectl get pods -w

Enter fullscreen mode

Exit fullscreen mode

Result:

VISUAL: DEPLOYMENT VS STATEFULSET

This is why Deployments are unsafe for databases.

STEP 6 — VERIFY PERSISTENT STORAGE

kubectl get pvc

Enter fullscreen mode

Exit fullscreen mode

Expected:

data-mysql-0 data-mysql-1 data-mysql-2

Enter fullscreen mode

Exit fullscreen mode

Each pod has:

VISUAL: VOLUMECLAIMTEMPLATES

STEP 7 — VERIFY DNS (CRITICAL STEP)

Run a temporary client pod:

kubectl run dns-test --image=busybox:1.36 -it --rm --restart=Never -- sh

Enter fullscreen mode

Exit fullscreen mode

Inside the pod:

nslookup mysql-0.mysql-headless nslookup mysql-1.mysql-headless nslookup mysql-2.mysql-headless

Enter fullscreen mode

Exit fullscreen mode

Each resolves to a different IP.

Exit:

exit

Enter fullscreen mode

Exit fullscreen mode

VISUAL: POD DNS NAMES

Format:

<pod-name>.<headless-service>.<namespace>.svc.cluster.local

Enter fullscreen mode

Exit fullscreen mode

STEP 8 — CONNECT TO MYSQL (REAL TEST)

kubectl exec -it mysql-0 -- mysql -uroot -prootpass

Enter fullscreen mode

Exit fullscreen mode

Inside MySQL:

CREATE DATABASE labdb; USE labdb; CREATE TABLE test (id INT); INSERT INTO test VALUES (1); SELECT * FROM test;

Enter fullscreen mode

Exit fullscreen mode

Exit:

exit

Enter fullscreen mode

Exit fullscreen mode

STEP 9 — DELETE POD, DATA MUST SURVIVE

kubectl delete pod mysql-0

Enter fullscreen mode

Exit fullscreen mode

Wait until it comes back:

kubectl get pods -w

Enter fullscreen mode

Exit fullscreen mode

Reconnect:

kubectl exec -it mysql-0 -- mysql -uroot -prootpass

Enter fullscreen mode

Exit fullscreen mode

Check:

USE labdb; SELECT * FROM test;

Enter fullscreen mode

Exit fullscreen mode

✅ Data is still there.

VISUAL: DATA SURVIVES POD DELETION

STEP 10 — WHAT THIS LAB PROVES (LOCK THIS IN)

Kubernetes guarantees:

Kubernetes does NOT:

SENIOR DEVOPS MENTAL MODEL (INTERVIEW READY)

“StatefulSets are required for databases because they provide stable pod identities and ordered lifecycle management. Headless services expose pod-level DNS so clients can target specific replicas. VolumeClaimTemplates ensure each pod has persistent storage that survives restarts.”

For further actions, you may consider blocking this person and/or reporting abuse

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

Читайте також