Skip to content

DaemonSets

Some workloads are not about how many replicas, but about every node having one. A CNI plugin, a log shipper, a metrics exporter and a CSI node driver all have the same shape: one Pod per node, wherever nodes happen to be.

That is what a DaemonSet does. There is no replicas field — the number of Pods follows the number of nodes automatically. Add a node, and a Pod appears on it without anyone doing anything.

Reference

Terminology

  • DaemonSet — Ensures a copy of a Pod runs on every node matching its node selector, including nodes added later.
  • Toleration — Permission to run on a tainted node. DaemonSets almost always need them, because the nodes they most need to reach are the ones with taints.
  • updateStrategyRollingUpdate (default) replaces Pods node by node, bounded by maxUnavailable. OnDelete waits for you to delete each Pod yourself.
  • Node affinity / nodeSelector — Limits which nodes the DaemonSet targets. Without one it targets every node it is allowed to tolerate.

Why Tolerations Matter Here

Control plane nodes carry a taint such as node-role.kubernetes.io/control-plane:NoSchedule, which keeps ordinary workloads off them. A DaemonSet that does not tolerate that taint will silently skip those nodes — you asked for one per node and got fewer, with no error to explain why.

This is the most common DaemonSet surprise, and the diagnostic is always the same:

kubectl get nodes                                       # how many nodes are there?
kubectl get pods -o wide -l app=my-daemonset            # how many Pods, on which nodes?
kubectl describe node <missing-node> | grep -A3 Taints   # what is keeping it away?

A Minimal Example

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: node-info
spec:
  selector:
    matchLabels:
      app: node-info
  template:
    metadata:
      labels:
        app: node-info
    spec:
      tolerations:
        - operator: Exists          # tolerate everything, deliberately
      containers:
        - name: node-info
          image: docker.io/library/busybox
          command: ["sh", "-c", "while true; do echo $(hostname) $(date); sleep 60; done"]
          resources:
            requests:
              cpu: 10m
              memory: 16Mi

tolerations: [{operator: Exists}] tolerates every taint. It is right for a node agent that must reach every node, and wrong for anything else — use it deliberately, not by copy-paste.

Note the resource requests. A DaemonSet multiplies its request by the number of nodes, so a container asking for 500m on a fifty-node cluster is asking for 25 CPUs before your applications get anything.

Exercises

  1. Look at the ones you already have. Every cluster runs DaemonSets, and they are the best examples available:

    kubectl get daemonsets -A
    kubectl get daemonsets -n kube-system -o custom-columns=NAME:.metadata.name,DESIRED:.status.desiredNumberScheduled,READY:.status.numberReady

    DESIRED versus READY is the whole health story for a DaemonSet: if they differ, some node is missing its Pod.

  2. Create one and compare counts.

    kubectl apply -f node-info.yaml
    kubectl get pods -l app=node-info -o wide
    kubectl get nodes

    If the numbers do not match, it is a taint, a nodeSelector, or a resource request that does not fit. kubectl describe daemonset node-info says which.

  3. Inspect what a node agent actually does. Pick a CNI or kube-proxy Pod from kube-system and look at its command, mounts and host network settings:

    kubectl get pods -n kube-system
    kubectl describe pod -n kube-system <pod-name>

    Note hostNetwork: true and the /host mounts. Node agents need to see the node, not a sandbox — which is also why they are a common source of privilege-escalation findings in a security review.

What to Take Away

  • DaemonSets are for per-node agents; the replica count is a consequence of the node count, not a setting.
  • If some nodes have no Pod, look for a taint the DaemonSet does not tolerate.
  • Resource requests multiply by node count — size them accordingly.
  • Their access to the host is exactly what makes them useful and exactly what makes them worth reviewing.