While Deployments distribute Pods across nodes based on available capacity, DaemonSets ensure that a copy of a specific Pod runs on all (or selected) worker nodes in the cluster. As nodes are added to or removed from the cluster, DaemonSet Pods are added or garbage-collected automatically.
TL;DR (Quick Summary)#
- Use Cases: Node monitoring agents (
prometheus-node-exporter), container log shippers (fluentbit,logstash), storage daemons (glusterfs,ceph), and CNI network plugins (cilium,calico,kube-proxy). - Node Lifecycle Integration: When a new node joins the cluster, the DaemonSet controller schedules a DaemonSet pod onto it automatically.
- Tolerations: DaemonSets frequently specify
tolerationsto ensure they run on Control Plane nodes despite master taints.
1. DaemonSet Architecture#
graph TD
DS["DaemonSet Controller: node-exporter"] -->|Ensures 1 Pod per Node| N1["Worker Node 1"]
DS -->|Ensures 1 Pod per Node| N2["Worker Node 2"]
DS -->|Ensures 1 Pod per Node| N3["Control Plane Node
(Tolerates Master Taint)"]
N1 --> P1["Pod: node-exporter-n1
(Collects CPU/RAM metrics)"]
N2 --> P2["Pod: node-exporter-n2
(Collects CPU/RAM metrics)"]
N3 --> P3["Pod: node-exporter-n3
(Collects CPU/RAM metrics)"]
2. Declarative DaemonSet Manifest (Prometheus Node Exporter)#
Let’s write a production-ready DaemonSet manifest deploying the Prometheus Node Exporter to collect hardware and OS metrics directly from worker host filesystems (/proc and /sys).
Create daemonset-node-exporter.yaml:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: kube-system
labels:
app.kubernetes.io/name: node-exporter
spec:
selector:
matchLabels:
app.kubernetes.io/name: node-exporter
template:
metadata:
labels:
app.kubernetes.io/name: node-exporter
spec:
# Run on control plane nodes as well
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: node-exporter
image: prom/node-exporter:v1.7.0
args:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --collector.filesystem.mount-points-exclude=^/(dev|proc|sys|var/lib/docker/.+)($|/)
ports:
- name: metrics
containerPort: 9100
hostPort: 9100 # Binds directly to node host IP port 9100
resources:
requests:
cpu: "50m"
memory: "32Mi"
limits:
cpu: "100m"
memory: "64Mi"
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
hostNetwork: true
hostPID: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sysApply manifest:
kubectl apply -f daemonset-node-exporter.yaml3. Inspecting DaemonSet Execution#
Check DaemonSet status in kube-system:
kubectl get daemonsets -n kube-system node-exporterExpected Terminal Output:
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
node-exporter 3 3 3 3 3 <none> 20sList the individual DaemonSet pods scheduled per node:
kubectl get pods -n kube-system -l app.kubernetes.io/name=node-exporter -o wideNAME READY STATUS RESTARTS AGE IP NODE
node-exporter-4z8kl 1/1 Running 0 35s 192.168.1.10 minikube
node-exporter-8p2mx 1/1 Running 0 35s 192.168.1.11 minikube-worker-01
node-exporter-k9q1w 1/1 Running 0 35s 192.168.1.12 minikube-worker-02Notice how exactly 1 Pod instance runs on every single worker node!
4. Summary & Next Steps#
DaemonSets are essential for managing cluster observability, log shipping, and network daemons.
In Episode 11: Jobs, CronJobs & Batch Processing, we will explore run-to-completion workloads: Jobs (batch tasks) and CronJobs (scheduled maintenance & backup tasks)!

