Lab: Deployments vs StatefulSets (Side-by-Side)

January 7, 2026 ·

Lab Goal

In this lab, you will deploy the same application two ways:

  • Once using a Deployment
  • Once using a StatefulSet

You will then:

  • Scale both
  • Delete pods
  • Observe naming, ordering, and persistence behavior

By the end, the difference between the two controllers will be obvious.

Prerequisites

  • Access to a Kubernetes or OpenShift cluster
  • kubectl or oc CLI configured
  • A namespace you can work in

Create a fresh namespace:

oc create namespace workload-lab
oc config set-context --current --namespace=workload-lab

Part 1: Deployment (Stateless Workload)

Step 1: Create the Deployment

Create a file named deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: demo
  template:
    metadata:
      labels:
        app: demo
    spec:
      containers:
      - name: app
        image: nginx
        ports:
        - containerPort: 80

Apply it:

oc apply -f deployment.yaml

Step 2: Observe the Pods

oc get pods

Example output:

demo-deployment-6f9c5c8c8b-4n7qx
demo-deployment-6f9c5c8c8b-hkz9m
demo-deployment-6f9c5c8c8b-qpl2s

Observations:

  • Pod names are random
  • Pods are interchangeable
  • Kubernetes doesn’t care which pod is which

Step 3: Delete a Pod

oc delete pod demo-deployment-6f9c5c8c8b-4n7qx

Then:

oc get pods

What happens:

  • A new pod is created
  • It has a different name
  • Kubernetes replaces capacity, not identity

Step 4: Scale the Deployment

oc scale deployment demo-deployment --replicas=5
oc get pods

Key takeaway:
Scaling is fast, parallel, and unordered.

Part 2: StatefulSet (Stateful Workload)

Step 1: Create a Headless Service

StatefulSets require a stable network identity.

Create service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: demo-stateful
spec:
  clusterIP: None
  selector:
    app: demo-stateful

Apply it:

oc apply -f service.yaml

Step 2: Create the StatefulSet

Create statefulset.yaml:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: demo-stateful
spec:
  serviceName: demo-stateful
  replicas: 3
  selector:
    matchLabels:
      app: demo-stateful
  template:
    metadata:
      labels:
        app: demo-stateful
    spec:
      containers:
      - name: app
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi

Apply it:

oc apply -f statefulset.yaml

Step 3: Observe Pod Creation Order

oc get pods -w

You will see:

demo-stateful-0
demo-stateful-1
demo-stateful-2

Created one at a time, in order.

Step 4: Delete a Stateful Pod

oc delete pod demo-stateful-1

Then:

oc get pods

What happens:

  • demo-stateful-1 is recreated
  • The name stays the same
  • Its PersistentVolume is reused

This is identity preservation.

Step 5: Scale the StatefulSet

oc scale statefulset demo-stateful --replicas=5

Watch carefully:

oc get pods -w

Pods are created:

demo-stateful-3
demo-stateful-4

Part 3: Side-by-Side Comparison

BehaviorDeploymentStatefulSet
Pod namesRandomPredictable (-0, -1, -2)
Pod replacementNew identitySame identity
StorageOptional/sharedOne volume per pod
ScalingParallelSequential
Best forStateless appsDatabases, clustered systems

Key Takeaways

  • Deployments treat pods as cattle
  • StatefulSets treat pods as individuals
  • Identity and storage are the deciding factors
  • If you don’t need StatefulSets — don’t use them

Cleanup

oc delete deployment demo-deployment
oc delete statefulset demo-stateful
oc delete service demo-stateful
oc delete pvc --all