Home › CKAD practice tasks › Choose the right workload controller
CKAD · Application Design and Build

Convert Deployments to a DaemonSet and a StatefulSet

Namespace `platform` runs a node agent as a Deployment, so it only covers one node. The queue team drafted `/root/queue.yaml` as a Deployment, but each replica needs a stable name and its own storage. This cluster has a control-plane node and a worker node.

Live lab access

This task description is public. Live practice requires full access unless this is the selected free weekly task. AI Lab Coach is available in single-task labs, including the free weekly task. See this week's free task.

Create an account to continue →

Read this week's free task →

On a phone? Read the task and create your account here, then sign in on a desktop or laptop for the terminal lab. Nothing starts until you choose Start.

The task

Namespace platform runs a node agent as a Deployment, so it only covers one node. The queue team drafted /root/queue.yaml as a Deployment, but each replica needs a stable name and its own storage. This cluster has a control-plane node and a worker node.

Requirements
1. Replace Deployment node-agent with a DaemonSet node-agent that uses the same Pod template and runs one Pod on every node, including the control-plane node. Remove the Deployment.
2. Create a headless Service queue in platform that selects app=queue on port 9000.
3. Run the queue from /root/queue.yaml as StatefulSet queue with 2 replicas, governed by Service queue, giving each replica its own 64Mi ReadWriteOnce volume named data from the default StorageClass, mounted at /data.
4. Ensure queue-0 and queue-1 are ready.

Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster. It needs a default StorageClass and, ideally, a control-plane node plus at least one worker.

Pick the controller by the guarantee you need

All workload controllers create Pods from a template. What differs is the promise each one makes about those Pods, and exam questions are usually written so that only one promise fits. Ask what the Pods need: interchangeable copies, a fixed identity with private storage, one copy per node, or a run that finishes.

Deployment   N identical, replaceable Pods        random names, shared or no storage
StatefulSet  N Pods with identity                 name-0..N-1, own PVC each, needs headless Service
DaemonSet    1 Pod per eligible node              follows nodes, taints decide eligibility
Job          Pods that run to completion          restartPolicy Never or OnFailure

1. StatefulSet: identity comes from the name, the Service and the claim

Save this as kv.yaml. It pairs a headless Service (clusterIP: None) with a StatefulSet that names it in serviceName, and gives each replica its own volume through volumeClaimTemplates. No storageClassName is set, so the default StorageClass provisions the volumes.

apiVersion: v1
kind: Service
metadata:
  name: kv-peers
  namespace: prepium-tutorial
spec:
  clusterIP: None
  selector:
    app: kv
  ports:
  - name: http
    port: 80
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: kv
  namespace: prepium-tutorial
spec:
  serviceName: kv-peers
  replicas: 3
  selector:
    matchLabels:
      app: kv
  template:
    metadata:
      labels:
        app: kv
    spec:
      containers:
      - name: server
        image: nginx:1.27-alpine
        ports:
        - name: http
          containerPort: 80
        volumeMounts:
        - name: state
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: state
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 100Mi
kubectl create namespace prepium-tutorial
kubectl apply -f kv.yaml
kubectl -n prepium-tutorial get pods -l app=kv -w
kubectl -n prepium-tutorial get pvc

Pods appear as kv-0, kv-1, kv-2, and under the default OrderedReady policy each waits for the previous one to be Running and Ready. The claims are named after template, StatefulSet and ordinal: state-kv-0 and so on. A StatefulSet does not create its governing Service for you; that is your job.

2. Prove the identity survives a restart

kubectl -n prepium-tutorial exec kv-1 -- sh -c 'echo written-by-kv-1 > /usr/share/nginx/html/id.txt'
kubectl -n prepium-tutorial delete pod kv-1
kubectl -n prepium-tutorial wait --for=condition=Ready pod/kv-1 --timeout=120s
kubectl -n prepium-tutorial exec kv-1 -- cat /usr/share/nginx/html/id.txt
kubectl -n prepium-tutorial run dns --image=busybox:1.28 --restart=Never --rm -it -- nslookup kv-1.kv-peers

The replacement Pod has the same name, remounts state-kv-1, and still has the file. Each Pod also gets a DNS name of the form pod.service.namespace.svc.cluster.local, which is what clustered software uses to find specific peers. By default, deleting or scaling down the StatefulSet leaves the PVCs behind on purpose.

3. DaemonSet: one Pod per node, if the node's taints allow it

A DaemonSet has no replica count; the node list is the count. kubeadm taints control-plane nodes with node-role.kubernetes.io/control-plane:NoSchedule, so a DaemonSet skips them unless its Pod template tolerates that taint. To see it, write a small DaemonSet of your own (say node-echo, running busybox:1.36 with sleep 3600), apply it once without and once with this block in the Pod template:

    spec:
      tolerations:
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
kubectl describe nodes | grep -i taints
kubectl -n prepium-tutorial get ds
kubectl -n prepium-tutorial get pods -o wide

Compare the DaemonSet's DESIRED count with the number of nodes, and the NODE column with your node names. The controller adds some tolerations by itself (for not-ready, unreachable, pressure and unschedulable conditions), but not this one.

4. Job: when "done" is the goal

If the work ends, use a Job (or a CronJob for a schedule). A Deployment would restart a finished container forever, because its Pods must use restartPolicy: Always.

Common mistakes

Example checkEvidence
Every node runs the agentDaemonSet DESIRED and READY equal the node count
Headless governing Servicespec.clusterIP: None and StatefulSet serviceName match
Per-replica storageOne Bound PVC per ordinal with the requested size and mode
Stable identityRecreated Pod keeps its name and its data

Cleanup: kubectl delete namespace prepium-tutorial (this also removes the leftover PVCs in it). References: StatefulSets, DaemonSet, StatefulSet basics. Next, try CronJobs or taints and tolerations.

Difficulty
Medium · 10 minutes target
Domain
Application Design and Build
Grading
Live checks · partial credit

Practice scope

This additional curriculum lab is available in single-task practice with the existing 12-minute limit. The three CKAD mocks keep their original 17-task sets. Hints, an explained solution and requirement-by-requirement feedback are available in the lab.

Browse CKAD practice tasks →