A DaemonSet makes sure every (eligible) node runs exactly one pod. There is no replicas field: the pod count equals the number of matching nodes. New nodes get a pod automatically; removed nodes take their pod with them.
Use it for node-level services: log shipping (fluentd, fluent-bit), monitoring (node-exporter), networking (kube-proxy, calico-node).
apiVersion: apps/v1
kind: DaemonSet
metadata: { name: ssd-monitor }
spec:
selector:
matchLabels: { app: ssd-monitor }
template:
metadata:
labels: { app: ssd-monitor }
spec:
nodeSelector:
disk: ssd
containers:
- name: main
image: busybox:1.36
command: ["sh", "-c", "while true; do sleep 3600; done"]
flowchart LR DS["DaemonSet ssd-monitor<br/>nodeSelector disk=ssd"] --> W1["worker-1 (disk=ssd): 1 pod"] DS -.-> W2["worker-2 (no label): 0 pods"]
- After applying it, if no node has
disk=ssdthere are no pods yet;kubectl label nodes worker-2 disk=ssdmakes a pod appear on that node at once. - Built-in node labels:
kubernetes.io/hostname,kubernetes.io/os,topology.kubernetes.io/zone(replacing the deprecatedbeta.kubernetes.io/*andfailure-domain.beta…). - Control-plane nodes carry the taint
node-role.kubernetes.io/control-plane:NoSchedule, so a DaemonSet does not run there unless it has a matching toleration. updateStrategyRollingUpdate (default) or OnDelete; roll back withkubectl rollout undo ds/<name>.
| Command | Meaning |
|---|---|
kubectl get ds -n kube-system |
DESIRED / CURRENT / READY by node count |
kubectl label nodes worker-2 disk=ssd |
Label a node |
kubectl rollout undo ds/ssd-monitor |
Roll back a DaemonSet |
Typical DaemonSets in a real cluster
| Agent | Purpose |
|---|---|
| kube-proxy | Service rules on every node |
| CNI agent (calico-node, cilium) | Pod networking and policies |
| fluent-bit, Promtail, Vector | Ship container logs from /var/log/containers |
| node-exporter | Host CPU, memory, disk metrics for Prometheus |
| CSI node plugin | Attach and mount storage volumes |
| Security agents | Runtime threat detection such as Falco |
Most of these need access to the host, through hostPath volumes, hostNetwork, or privileged security contexts. That is why DaemonSets usually live in system namespaces with tight RBAC.
Running on every node, including tainted ones
To run on control-plane or special nodes, add tolerations:
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
A toleration with only operator: Exists and no key tolerates every taint, a common choice for logging agents that must cover all nodes.
Rolling out safely
With RollingUpdate, maxUnavailable (default 1) controls how many nodes lose the agent at once during an upgrade, and maxSurge can start the new pod before removing the old one on each node. For a networking agent, a bad update can break pod traffic cluster-wide, so roll out to a few nodes first using a node selector or test cluster.
Resource discipline
A DaemonSet pod runs on every node, so its requests are multiplied by the node count. Keep requests small and set limits; give important agents a PriorityClass such as system-node-critical so they are not evicted before ordinary pods.
DaemonSet or Deployment?
Choose a DaemonSet when the work is tied to each node (its logs, its disks, its network). Choose a Deployment when you need a certain number of copies anywhere in the cluster, such as a web API, even if that number happens to equal the node count today.