DaemonSets: one Pod on every node
A Deployment asks "how many copies of my app do users need?". Some programs do not care about users at all. They look after the machine: collect its logs, measure its CPU, set up its network. Those need exactly one copy on every node, and that is what a DaemonSet gives you.
The idea: a caretaker in every building
Imagine a company with many office buildings. Each building needs its own caretaker who checks the heating and empties the bins. You never want two caretakers in one building, and you never want a building without one. When the company buys a new building, a caretaker moves in on day one. When a building is sold, its caretaker leaves with it.
Nodes are the buildings. A DaemonSet is the rule "every building gets one caretaker".
DaemonSet vs Deployment
| Deployment | DaemonSet | |
|---|---|---|
| How many Pods? | You choose: replicas: 3 | One per matching node; there is no replicas field |
| Where? | Wherever the scheduler finds room | On every node (or every node you select) |
| New node joins | Nothing happens | A Pod is started on it automatically |
| Node removed | Its Pods are recreated elsewhere | Its Pod simply goes away |
| Serves | Your users | The node itself, and the cluster |
Try it: nodes come and go
Add and remove nodes, then try the two switches. Watch the DaemonSet keep "one per matching node" without you ever choosing a number:
- A new node gets its copy right away.
- The control-plane node is skipped because it carries a taint ("no ordinary Pods here"). A toleration lets the DaemonSet in anyway (chapter 40 explains taints).
- With a
nodeSelector, only labelled nodes get a copy.
The YAML
It looks like a Deployment without replicas. Click the highlighted parts:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-agent
namespace: kube-system
spec:
selector:
matchLabels:
app: log-agent
template:
metadata:
labels:
app: log-agent
spec:
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: agent
image: fluent/fluent-bit:3.0
resources:
requests: { cpu: 50m, memory: 64Mi }
limits: { memory: 128Mi }
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
kind: DaemonSet
Same selector and template as a Deployment, but no replicas. The number of Pods is "however many nodes match".
tolerations
Lets the Pod run on control-plane nodes too, which normally refuse ordinary Pods. Leave it out if the agent only belongs on worker nodes.
Keep it small
This Pod runs on every machine, so its requests are multiplied by the node count. A log agent that asks for 1 CPU on 50 nodes reserves 50 CPUs.
hostPath
The agent reads the node's own log folder. This is one of the few good uses of hostPath (chapter 30): the Pod is meant to look at the node it runs on.
$ kubectl get daemonset -n kube-system
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR
log-agent 3 3 3 3 3 <none>
kube-proxy 3 3 3 3 3 kubernetes.io/os=linux
DESIRED is not something you typed: it is the number of matching nodes. Note that kube-proxy itself runs as a DaemonSet.
What people run as DaemonSets
Log collectors
Fluent Bit, Vector, Promtail: read every container's logs from the node and ship them to one place.
Node metrics
Prometheus node-exporter: CPU, memory and disk of each machine.
Networking
kube-proxy and the CNI plugin (Calico, Cilium) that wires Pods together (chapter 25).
Storage and security
CSI node drivers that attach disks, security scanners watching every process.
Your blog app's services do not belong here. posts and comments serve users, so they stay Deployments.
Only some nodes
Not every agent belongs everywhere. A GPU monitor only makes sense on GPU machines:
spec:
template:
spec:
nodeSelector:
accelerator: nvidia # only nodes with this label get a copy
$ kubectl label node node-4 accelerator=nvidia # node-4 now gets one
$ kubectl label node node-4 accelerator- # remove the label: its copy is deleted
Node affinity works too, for more complex rules. Both are covered in chapter 40.
Talking to a DaemonSet Pod
Most DaemonSets push data out (to a log server, to Prometheus) and nobody calls them. When something does need to reach one, there are three common ways:
containers:
- name: agent
ports:
- containerPort: 24224
hostPort: 24224 # open this port on the node's own IPEach app talks to the agent on its own node, using the node IP. Fast and local. The app can learn its node's IP from the Downward API (chapter 20).
apiVersion: v1
kind: Service
metadata:
name: node-exporter
spec:
clusterIP: None # headless
selector: { app: node-exporter }
ports: [{ port: 9100 }]DNS returns every copy's IP. Prometheus uses this to scrape each node (chapter 26).
A normal ClusterIP or NodePort Service picks a random copy. Fine when any copy can answer, which is rare for node agents, because each one usually knows only about its own node.
Updating a DaemonSet
Change the image and apply, just like a Deployment. Two update strategies:
RollingUpdate (default)
Replaces the copy on one node at a time (maxUnavailable: 1). Each node briefly has no agent while its new copy starts.
OnDelete
Nothing happens until you delete a Pod; its replacement then uses the new template. Gives full control, for example to upgrade a network plugin one node at a time.
$ kubectl set image daemonset/log-agent agent=fluent/fluent-bit:3.1 -n kube-system
$ kubectl rollout status daemonset/log-agent -n kube-system
Static Pods
A static Pod is a Pod file placed directly in a folder on the node, usually /etc/kubernetes/manifests/. The node's kubelet runs it by itself, without the API server or any controller. That is how many clusters start the control plane: the API server cannot schedule itself before it exists. You will see these Pods (with the node name added to their names) in kube-system, but for your own agents, use a DaemonSet.
Which one?
- Ship the logs of every container on every machine
Logs live on each node's disk, so each node needs its own collector.
- The comments API, scaled to handle traffic
Its copies depend on user load, not on how many machines exist.
- A monitor for the GPUs in the GPU nodes only
A DaemonSet with a nodeSelector for the GPU label.
Recap
- A DaemonSet runs one Pod on every node, or on every node you select.
- No
replicas: the count follows the nodes automatically. - Used for node agents: logs, metrics, networking, storage drivers.
- Tolerations let it run on tainted nodes;
nodeSelectorlimits it to some nodes. - Keep its requests small: they are paid on every node.
- Updates:
RollingUpdatenode by node, orOnDeletefor manual control.
Quick check
Show answer
None. The DaemonSet notices the new nodes and starts one copy on each, automatically.
DaemonSets: common questions
What is the difference between a DaemonSet and a Deployment?
A Deployment runs as many replicas as you choose, wherever there is room. A DaemonSet runs exactly one Pod on every matching node and follows nodes as they join or leave.