Kubernetes DaemonSets: Node-Level Services
DaemonSets are Kubernetes workload controllers that guarantee a pod runs on all (or some) nodes in your cluster. When you add a node, the DaemonSet automatically schedules its pod there. When you...
Key Insights
- DaemonSets ensure exactly one pod runs on each node (or selected nodes), making them ideal for node-level infrastructure services like log collectors, monitoring agents, and network plugins
- Unlike Deployments, DaemonSets bypass the scheduler and create pods directly on nodes, requiring careful resource management and security considerations since they often need privileged access
- Proper use of node selectors, taints/tolerations, and rolling update strategies prevents cluster-wide outages when deploying or updating critical node-level services
Introduction to DaemonSets
DaemonSets are Kubernetes workload controllers that guarantee a pod runs on all (or some) nodes in your cluster. When you add a node, the DaemonSet automatically schedules its pod there. When you remove a node, those pods are garbage collected. This is fundamentally different from Deployments, which distribute a specified number of replicas across the cluster based on scheduler decisions, or StatefulSets, which maintain persistent identities for pods.
The key distinction: DaemonSets are node-centric, not replica-centric. You don’t specify “I want 3 replicas”—you specify “I want this on every node that matches my criteria.”
Here’s a basic DaemonSet for a logging agent:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
namespace: kube-system
spec:
selector:
matchLabels:
app: log-collector
template:
metadata:
labels:
app: log-collector
spec:
containers:
- name: log-agent
image: fluent/fluent-bit:2.1
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 100Mi
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
This manifest creates a pod on every node that reads logs from /var/log. Notice the hostPath volume—a common pattern in DaemonSets since they typically interact with node-level resources.
Common Use Cases
DaemonSets shine in scenarios requiring node-level presence. The most common use cases include:
Log Collection: Every application writes logs. DaemonSets ensure log collectors run on every node to aggregate and forward logs to centralized systems.
Monitoring Agents: Tools like Prometheus Node Exporter, Datadog agents, or custom metric collectors need to run on each node to gather system and application metrics.
Network Plugins: CNI plugins like Calico, Weave, or Cilium deploy as DaemonSets to provide networking capabilities to pods on each node.
Storage Daemons: Distributed storage systems like Ceph or GlusterFS use DaemonSets to run storage daemons on nodes designated for storage.
Here’s a production-grade Fluentd DaemonSet for cluster-wide log aggregation:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd
namespace: kube-system
labels:
app: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
serviceAccountName: fluentd
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd-kubernetes-daemonset:v1-debian-elasticsearch
env:
- name: FLUENT_ELASTICSEARCH_HOST
value: "elasticsearch.logging.svc.cluster.local"
- name: FLUENT_ELASTICSEARCH_PORT
value: "9200"
resources:
limits:
memory: 512Mi
requests:
cpu: 200m
memory: 256Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
This configuration tolerates control plane nodes (so it runs there too) and mounts both /var/log and Docker container paths to capture all logs.
DaemonSet Configuration and Scheduling
While DaemonSets bypass the normal scheduler, you still control pod placement through node selectors, node affinity, and taints/tolerations.
Node Selectors are the simplest approach—specify labels that nodes must have:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: gpu-monitor
namespace: monitoring
spec:
selector:
matchLabels:
app: gpu-monitor
template:
metadata:
labels:
app: gpu-monitor
spec:
nodeSelector:
accelerator: nvidia-gpu
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: gpu-exporter
image: nvidia/dcgm-exporter:latest
securityContext:
privileged: true
volumeMounts:
- name: nvidia
mountPath: /usr/local/nvidia
readOnly: true
volumes:
- name: nvidia
hostPath:
path: /usr/local/nvidia
This DaemonSet runs only on nodes labeled accelerator=nvidia-gpu and tolerates the GPU taint, ensuring it doesn’t interfere with regular workloads while monitoring GPU nodes.
Taints and tolerations are critical for DaemonSets. Nodes often have taints to prevent regular pods from scheduling. Your DaemonSet needs appropriate tolerations to run on those nodes.
Update Strategies
DaemonSets support two update strategies: RollingUpdate (default) and OnDelete.
RollingUpdate automatically updates DaemonSet pods when you change the pod template. This is safer for most use cases but requires careful configuration to avoid taking down critical services across all nodes simultaneously.
OnDelete requires manual pod deletion before updates apply. Use this when you need precise control over update timing or when updates are risky.
Here’s a DaemonSet with a conservative rolling update strategy:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-agent
namespace: kube-system
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
selector:
matchLabels:
app: node-agent
template:
metadata:
labels:
app: node-agent
spec:
containers:
- name: agent
image: company/node-agent:v2.3.1
resources:
limits:
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
maxUnavailable: 1 ensures only one pod updates at a time. For critical services, this prevents cluster-wide failures. For less critical services, you might increase this number or use a percentage like maxUnavailable: 25%.
Resource Management and Monitoring
DaemonSets consume resources on every node. Multiply your resource requests by your node count to understand the total cluster impact. A seemingly modest 100Mi memory request becomes 10GB across 100 nodes.
Always set resource requests and limits. Without them, a misbehaving DaemonSet can starve node-level resources and impact all pods on affected nodes.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: metrics-collector
namespace: monitoring
spec:
selector:
matchLabels:
app: metrics-collector
template:
metadata:
labels:
app: metrics-collector
spec:
containers:
- name: collector
image: prom/node-exporter:v1.6.1
args:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)
ports:
- containerPort: 9100
name: metrics
resources:
limits:
cpu: 200m
memory: 128Mi
requests:
cpu: 100m
memory: 64Mi
livenessProbe:
httpGet:
path: /
port: metrics
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: metrics
initialDelaySeconds: 5
periodSeconds: 5
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
The liveness and readiness probes ensure Kubernetes can detect and restart unhealthy pods. This is crucial for DaemonSets since they provide infrastructure services that other workloads depend on.
Advanced Patterns
DaemonSets often require elevated privileges and access to node resources. This introduces security considerations you must address carefully.
hostPath Volumes: Grant access to node filesystems. Use sparingly and always with read-only mounts when possible.
hostNetwork Mode: Allows pods to use the node’s network namespace. Required for some network plugins and monitoring tools but bypasses network policies.
Privileged Containers: Grant nearly all capabilities of the host. Necessary for some system-level operations but should be your last resort.
Here’s a node monitoring DaemonSet demonstrating these patterns:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: system-monitor
namespace: kube-system
spec:
selector:
matchLabels:
app: system-monitor
template:
metadata:
labels:
app: system-monitor
spec:
hostNetwork: true
hostPID: true
hostIPC: true
containers:
- name: monitor
image: company/system-monitor:v1.2.0
securityContext:
privileged: true
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
resources:
limits:
memory: 256Mi
requests:
cpu: 100m
memory: 128Mi
volumeMounts:
- name: root
mountPath: /host
readOnly: true
- name: run
mountPath: /var/run
volumes:
- name: root
hostPath:
path: /
- name: run
hostPath:
path: /var/run
This configuration is powerful but dangerous. Only use these settings when absolutely necessary, and always:
- Document why each privilege is required
- Run as non-root user when possible
- Use Pod Security Standards to limit which namespaces can run privileged DaemonSets
- Regularly audit DaemonSet permissions
Troubleshooting Common Issues
When DaemonSets misbehave, start with these diagnostic commands:
# Check DaemonSet status
kubectl get daemonset -n kube-system
# See which nodes have pods
kubectl get pods -n kube-system -l app=fluentd -o wide
# Check for scheduling issues
kubectl describe daemonset fluentd -n kube-system
# View events for a specific pod
kubectl describe pod fluentd-xyz -n kube-system
# Check if nodes have taints preventing scheduling
kubectl get nodes -o json | jq '.items[].spec.taints'
# See DaemonSet pod distribution
kubectl get pods -n kube-system -l app=fluentd \
--field-selector=status.phase=Running \
-o custom-columns=NODE:.spec.nodeName,NAME:.metadata.name
Common issues include:
Pods not scheduling on all nodes: Check node selectors, taints, and resource availability. Use kubectl describe node to see resource pressure.
Update stuck: Verify maxUnavailable settings aren’t too conservative. Check if pods are failing readiness probes.
Resource exhaustion: DaemonSets can overwhelm nodes if resource limits are too high. Monitor node resource usage and adjust accordingly.
Permission errors: Ensure ServiceAccounts have necessary RBAC permissions, especially for DaemonSets that interact with the Kubernetes API.
DaemonSets are powerful tools for managing node-level infrastructure. Use them thoughtfully, secure them carefully, and monitor them closely. When configured correctly, they provide reliable, cluster-wide services that form the foundation of your Kubernetes infrastructure.