Polyaxon v3 is coming →

StatefulSet vs. Deployment: differences and use cases

Compare Kubernetes StatefulSets and Deployments, including identity, storage, scaling, rollout behavior, and common use cases.

February 20, 2024by Polyaxon
Feb 20, 2024

StatefulSet vs. Deployment: differences and use cases

Compare Kubernetes StatefulSets and Deployments, including identity, storage, scaling, rollout behavior, and common use cases.

Picture

Not every replicated workload is stateless. Deployments assume pods can be replaced freely. StatefulSets give pods stable identity and storage semantics for workloads that care about order, names, and durable state.

Choose wrong and the symptoms are ugly: data loss, broken clustering, stuck rollouts, or services that seem fine until the first restart.

What is a Deployment in Kubernetes?

A Deployment is a Kubernetes resource object that provides declarative updates for pods that encapsulate application containers. A Deployment represents a number of identical pods without unique IDs, while specifying the pods' desired state and attributes. Deployments are typically used to autoscale the number of pod replicas, perform controlled rollouts for application code, and perform rollbacks when necessary.

Kubernetes administrators rely on Deployments to manage a containerized application's lifecycle by defining the number of pods to be deployed, the image to be used for the application, and how to perform code updates. Kubernetes deployments help automate repeatable application updates, subsequently reducing the effort, time, and number of errors associated with manual updates.

Components of a Kubernetes Deployment

The primary components used to create and apply a Deployment to a cluster include:

  • Deployment template: This is a JSON or YAML configuration file that is used to define the Deployment's configuration specification. The Kubernetes Deployment controller relies on the desired state described in the Deployment template to create, update, and scale pods. The JSON or YAML file is static, and it includes a pod template that defines what each pod should look like, as well as other common parameters, such as:
    • Number of pod replicas
    • Name of the image running in the pods
    • Deployment's image tag
    • Secrets, ConfigMaps, and other settings injected into the pod
    • Service labels
  • Service: Defines a single endpoint that is used to enable network access and expose workloads running on the pods within the Deployment. A service is a REST object that points to the Deployment pods and includes a policy to access them.
  • Persistent Volume: Allows pods within the Deployment to access a portion of node storage to store data.

Deployment configuration manifest

Consider a static YAML file for a Kubernetes deployment named darwin-deployment.yaml with the following specifications:


apiVersion: apps/v1
kind: Deployment
metadata:
  name: darwin-deployment
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 1
  selector:
    matchLabels:
      app: darwin-app
  replicas: 3
  template:
    metadata:
      labels:
        app: darwin-app
    spec:
      containers:
        - name: web-app
          image: novice
          volumeMounts:
            - name: counter
              mountPath: /app/
      volumes:
        - name: darwin-volume
          persistentVolumeClaim:
            claimName: darwin-volume-claim

The above static file represents a Deployment named darwin-deployment that deploys three replicas of a pod to encapsulate containers running the novice image workload. The pods are attached to the darwin-volume-claim PersistentVolumeClaim with a specification similar to:


apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: darwin-volume-claim
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 50Mi
  storageClassName: default

To execute the Deployment within the cluster, it should be exposed using a service, such as the NodePort service, specified by the service.yaml file below:


apiVersion: v1
kind: Service
metadata:
  name: darwin-service
spec:
  ports:
    - name: http
      port: 80
      nodePort: 30080
  selector:
    name: darwin-app
  type: NodePort

To deploy the application, the Deployment, volume claim, and service are all applied to the cluster using the following commands:

$ kubectl apply -f service.yaml

$ kubectl apply -f darwin-volume-claim.yaml

$ kubectl apply -f darwin-deployment.yaml

Discovering Deployment details

Administrators can use the kubectl command to discover details of the Deployment and the pods they control. To check for the successful creation of the deployment, run the command:

$ kubectl get deployments

To check for the pods automatically created by the deployment, run the command:

$ kubectl get pods

Scaling deployments

The 'kubect'l command can also be used to scale the number of pods with changing patterns of an application load. To increase the number of pods for darwin-deployment to 5, run the command:

$ kubectl scale deployment/darwin-deployment --replicas=5

Kubernetes deployment strategies

Kubernetes supports multiple rollout strategies for pod deployments. These include:

  • Recreate: Simultaneously terminates and replaces all pods running the old version of the application with new pods.
  • Ramped: Rolls out new application versions while terminating the old pods.
  • Rolling update: Replaces old pods with new ones, one-by-one, with zero downtime.
  • Canary deployment: Replaces a subset of existing pods with new ones, keeping both versions running, and then rolls out the new version to more pods if the test deployment is a success.

What is a StatefulSet in Kubernetes?

A StatefulSet is a Kubernetes resource object that manages a set of pods with unique identities. By assigning a persistent ID that is maintained even if the pod is rescheduled, a StatefulSet helps maintain the uniqueness and ordering of pods. With unique pod identifiers, administrators can efficiently attach cluster volumes to new pods across failures.

Although the StatefulSet controller deploys pods using similar specifications, pods are not interchangeable. As a StatefulSet does not create a ReplicaSet, the pod replicas cannot be rolled back to previous versions. StatefulSets are typically used for applications that require persistent storage for stateful workloads, and ordered, automated rolling updates.

Components of a Kubernetes StatefulSet configuration manifest

A Kubernetes StatefulSet configuration comprises the following:

  • StatefulSet: The template that defines pod selectors and replicas of containers that will run on the pods.
  • Headless service: The network domain controller that allows clients to connect with the pods using a DNS entry.
  • Volume claim template: The template specification that allows administrators to provision stateful storage using persistent volumes.

StatefulSet configuration manifest

Consider a StatefulSet configuration named statefulset.yaml with the following specification:


apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: darwin
spec:
  selector:
    matchLabels:
      app: darwin-app
  serviceName: "darwin-set"
  replicas: 3
  template:
    metadata:
      labels:
        app: darwin
    spec:
      containers:
        - name: darwin-app
          image: novice
          ports:
            - containerPort: 80
              name: web
          volumeMounts:
            - name: www
              mountPath: /var/log
      volumes:
        - name: darwin-volume
          persistentVolumeClaim:
            claimName: darwin-claim

The above StatefulSet can be attached to a PersistentVolume named darwin-claim.yaml as follows:


apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: darwin-claim
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

To expose the StatefulSet via a headless service named darwin-service.yaml, the following configuration can be used:


apiVersion: v1
kind: Service
metadata:
  name: darwin
  labels:
    app: darwin #should match .spec.metadata.app in the statefulset template
spec:
  ports:
    - port: 80
      name: web
  clusterIP: None
  selector:
    app: darwin

All the above configurations can be applied to the cluster using the kubectl apply command, as follows:

$ kubectl apply -f statefulset.yaml

$ kubectl apply -f darwin-claim.yaml

$ kubectl apply -f darwin-service.yaml

The above commands create three pod replicas with ordered identities.

Discovering StatefulSet details

Pods within the StatefulSet can be verified with the get pods command:.

$ kubectl get pods

Kubernetes Deployment vs. StatefulSet: how to choose

The table below shows the primary differences between a StatefulSet and a Deployment:

Aspect | Deployment | StatefulSet Data persistence | Stateless | Stateful Pod name and identity | Pods are assigned an ID that consists of the deployment name and a random hash to generate a temporarily unique identity | Each pod gets a persistent identity consisting of the StatefulSet name and a sequence number Interchangeability | Pods are identical and can be interchanged | Pods in a StatefulSet are neither identical nor interchangeable Behavior | A pod can be replaced by a new replica at any time | Pods retain their identity when rescheduled on another node Volume claim | All replicas share a PVC and a volume | Each pod gets a unique volume and PVC Allowed volume access mode(s) | ReadWriteMany and ReadOnlyMany | ReadWriteOnce Pod interaction | Requires a service to interact with the pods | The headless service handles pod network identities Order of pod creation | Pods are created and deleted randomly | Pods are created in a strict sequence and cannot be deleted randomly

When to use

A StatefulSet is better suited to stateful workloads that require persistent storage on each cluster node, such as databases and other identity-sensitive workloads. A Deployment, on the other hand, is suitable for stateless workloads that use multiple replicas of one pod, such as web servers like Nginx and Apache.

This practical scenario demonstrates how a StatefulSet differs from a Deployment:

Consider a web app that uses a relational database to store data. When traffic to the application increases, administrators intend to scale up the number of pods to support the workload. A straightforward approach is simply to change the replica count within the Deployment's configuration manifest; then the Deployment controller will take care of scaling. Since new pod replicas are assigned the same set of ConfigMaps and environment variables when starting, they communicate with the backend the same way as the original pod, retaining the user experience for incoming traffic.

Similar to the web servers, the relational database may also need to be scaled up to meet the increased workload. Since the master and replica pods need to implement a leader-follower pattern, the pods of the database cannot be created or deleted randomly. In addition, while each pod needs to sync its data with the previous pod, it retains its own copy of the data stored. In such an instance, a StatefulSet helps create the database pods in an ordered sequence where every new pod acquires its copy of data from the last pod generated. If a pod fails, the StatefulSet controller automatically deploys new pod replicas incrementally with the same identity and attaches them to the same PVC.

Use cases

StatefulSet | Deployment Stateful workloads that require persistent storage on each cluster node | Stateless workloads such as web servers Ideal for key-value stores or database systems | For balancing requests between replicas Assigning ordered, unique identities | To automatically scale (creation/termination) pod replicas of a cluster For gradual rollouts | For controlled rollout and rollbacks Deploy new pod replicas incrementally | For deploying new pods with similar environment variables and ConfigMaps

Conclusion

Use Deployments for stateless replicated services. Use StatefulSets when identity, ordering, and persistent storage matter. The distinction is not academic; it changes how Kubernetes creates, names, updates, and recovers pods.

For Polyaxon users, this matters around supporting services and platform infrastructure. Training jobs and model services have different lifecycles, and the Kubernetes primitive should match the lifecycle instead of fighting it.