2026
Kubernetes DaemonSet: One Pod Per Node
Some workloads do not scale with load. They scale with nodes. Log collectors, metrics agents, network plugins and storage drivers all need to run exactly once on every machine in the cluster. DaemonSets are how Kubernetes handles that requirement automatically.
Most workloads in Kubernetes are things you want to run some number of copies of. Three replicas of your API server. Two replicas of a background worker. The scheduler finds nodes with available capacity and places pods there. You specify how many, Kubernetes figures out where.
A DaemonSet is different. Instead of asking how many, it asks where: exactly one copy of a pod on every node in the cluster. Not because a high number of replicas was requested, but because the node itself is what needs serving. The pod is not an instance of an application scaled for load. It is an agent attached to a machine.
This pattern comes up constantly in infrastructure tooling. Log collectors, metrics exporters, network plugins, storage drivers, security agents. All of them need to be everywhere, all the time, one per host. DaemonSets are how Kubernetes handles that requirement.
How it works
The DaemonSet controller runs inside the control plane and watches the cluster continuously. When a new node registers, the controller creates a pod for it. When a node is removed, the pod on that node is deleted. The process is automatic and requires no human input.
This is meaningfully different from a Deployment with replicas set to match the node count. A Deployment does not know or care which nodes its pods land on. If you have ten nodes and ten replicas, the scheduler might put two pods on some nodes and none on others. A DaemonSet guarantees exactly one pod per node, distributed precisely. Adding a node adds a pod. Removing a node removes one. The count tracks the fleet automatically.
Worth noting
DaemonSet pods bypass the normal scheduler. The controller sets the nodeName field directly when creating each pod, which causes the pod to land on a specific node without going through scheduling. This means scheduler predicates like pod affinity rules do not apply to DaemonSet pods the same way they do to Deployment pods. Node selectors and tolerations still work, but the mechanism underneath is different.
Core concepts
Understanding four properties of DaemonSets covers the vast majority of what you need to work with them in practice.
One pod per node
The scheduler does not place DaemonSet pods. The DaemonSet controller places them directly, one per eligible node, as soon as the node joins the cluster. If you have forty nodes, you get forty pods. If a node leaves, its pod is cleaned up. If a new node arrives, a pod is created on it automatically within seconds.
Node selector and tolerations
By default a DaemonSet targets every node in the cluster. You can narrow this with a nodeSelector or a more expressive nodeAffinity rule. Tolerations let the pod run on nodes that would normally repel it, such as control plane nodes tainted to keep application workloads away. These two controls together let you precisely define which nodes the daemon should run on.
Update strategy
DaemonSets support two update strategies. RollingUpdate replaces pods one node at a time, waiting for each to be ready before moving to the next. OnDelete requires manual deletion of each pod to trigger the update, giving full control over timing. RollingUpdate is the default and works well for most cases. OnDelete is useful when the update requires coordinated action on the node itself.
Ownership and garbage collection
Each pod created by a DaemonSet is owned by it. If you delete the DaemonSet, the pods are deleted with it. If a pod is deleted manually, the controller creates a replacement immediately. This ownership relationship means the DaemonSet is the authoritative source of truth for how many copies should exist and where.
What a DaemonSet looks like
The manifest is structured like a Deployment. There is a selector that ties the controller to its pods, a template that describes each pod and a spec that holds the container definition. The key difference is that there is no replicas field. The count is always one per eligible node.
DaemonSet — node exporter on every node
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true
hostPID: true
containers:
- name: node-exporter
image: prom/node-exporter:v1.7.0
ports:
- containerPort: 9100
hostPort: 9100
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
The hostNetwork: true and hostPID: truefields give the pod access to the node's network stack and process table. Node Exporter needs both to collect accurate metrics. The hostPath volumes mount /proc and /sys from the node into the container so the exporter can read them. These are common patterns in DaemonSets but they carry privilege implications and should only be enabled when genuinely necessary.
When to use a DaemonSet
The same pattern appears across a surprisingly wide range of infrastructure components. If something needs to run once per node and interact with the host, a DaemonSet is almost always the right choice.
Log collection
A log shipper like Fluentd, Fluent Bit or Filebeat needs to read log files from every node in the cluster. Since containers write logs to a directory on the host filesystem, the collector must run on that same host to access them. A DaemonSet ensures every node has a collector without any manual coordination.
Metrics and monitoring
Node-level metrics about CPU, memory, disk and network are only visible from within the node. Prometheus Node Exporter is almost always deployed as a DaemonSet so that every node exposes metrics to Prometheus. The same applies to any agent that needs access to kernel-level telemetry.
Storage drivers
Container Storage Interface drivers often run as DaemonSets because they need to interact with the kubelet on each node to mount volumes. The driver pod must be co-located with the node it serves. There is no alternative to a DaemonSet for this kind of tight node coupling.
Network plugins
CNI plugins like Calico, Cilium and Weave run as DaemonSets to manage networking on each node. They configure network interfaces, routing rules and iptables entries directly on the host. Losing the pod on any node would break network connectivity for all pods scheduled there.
Security agents
Runtime security tools like Falco monitor system calls on each node to detect suspicious activity. They need access to kernel interfaces that are only available locally. A DaemonSet ensures coverage does not have gaps. A node without the agent is a node that is not being watched.
Targeting specific nodes
Not every DaemonSet should run on every node. GPU monitoring only makes sense on nodes that have GPUs. A storage driver for a particular cloud disk type only belongs on nodes that support it. Two mechanisms in the pod spec handle this.
A nodeSelector matches nodes by label. Only nodes that have the specified label will receive a pod. A nodeAffinity rule in the affinity block gives you more expressive matching, including operators like In, NotIn and Exists. The two approaches serve the same purpose. Node affinity is the more flexible version and the one worth reaching for when the matching logic is anything beyond a simple equality check.
Node affinity — run only on GPU nodes
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: accelerator
operator: In
values:
- nvidia-gpu
Tolerations work the other direction. A taint on a node repels pods unless they carry a matching toleration. Control plane nodes in most clusters carry a node-role.kubernetes.io/control-plane taint for this reason. A DaemonSet that needs to run on control plane nodes must explicitly tolerate that taint. Without it, the controller skips those nodes entirely.
Toleration — allow scheduling on control plane nodes
spec:
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
Things that go wrong
DaemonSets are conceptually simple but the details around node access, privileges and update behaviour catch people out regularly.
Not setting resource requests
A DaemonSet pod runs on every node, including nodes that are already under pressure. Without resource requests, the pod competes for resources with no guaranteed allocation. In the worst case it gets evicted repeatedly on busy nodes, defeating the purpose of having it there. Setting sensible requests also helps the scheduler reason about capacity correctly.
Missing tolerations for control plane nodes
Control plane nodes carry a taint that prevents regular workloads from landing on them. If your DaemonSet needs to run on control plane nodes, you must add a toleration for that taint explicitly. Forgetting this is easy to miss in smaller clusters where control plane nodes are visible but in larger managed clusters the taint is always present.
Mounting host paths carelessly
DaemonSets often need access to host directories. Mounting the entire root filesystem or a directory with sensitive content opens a privilege escalation path. Mount only what is needed, use readOnly where the pod does not need to write and review whether hostPID or hostNetwork are genuinely required before enabling them.
Assuming pod identity is stable
DaemonSet pods are recreated when a node restarts. Their names include a random suffix that changes each time. Any system that tracks the pod by name rather than by the node it lives on will lose track of it after a restart. The node name is the stable identifier, not the pod name.
Where it fits
DaemonSets sit below the application layer in the cluster. They are the infrastructure underneath your workloads rather than the workloads themselves. The log shipper, the metrics agent, the network plugin: these are things your applications depend on implicitly without ever talking to them directly. They need to be present on every node before the applications that rely on them land there.
In practice, most DaemonSets in a cluster were not put there by the team running the applications. They were put there by whoever manages the cluster itself. The CNI plugin came with the cluster. The log shipper was deployed by the platform team. The node exporter was added when Prometheus was set up. Application developers often do not interact with DaemonSets at all, but understanding what is running on each node helps when debugging problems that appear across every pod on a node simultaneously.
The closest alternatives are static pods and init containers. Static pods are placed directly on a node by the kubelet reading a local directory, without any involvement from the API server. They exist before the cluster does and are how core components like etcd and the API server itself run. Init containers run before the main container in a pod and are used for setup within a single pod, not for spreading work across nodes. When the requirement is one process per node, managed by Kubernetes, responding to cluster changes automatically, a DaemonSet is the right tool.