Daemon templates are surprisingly not about keeping a single service running forever; they’re about ensuring a consistent state of a service across all nodes in a cluster, even when nodes themselves are ephemeral.
Let’s see this in action. Imagine you need a distributed logging agent, like fluentd, running on every single machine in your Kubernetes cluster. We don’t want to manually install and manage fluentd on each node. That’s where DaemonSets come in.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-daemonset
labels:
app: fluentd
spec:
selector:
matchLabels:
app: fluentd
template:
metadata:
labels:
app: fluentd
spec:
containers:
- name: fluentd
image: fluent/fluentd:v1.14-debian
resources:
limits:
cpu: "200m"
memory: "200Mi"
requests:
cpu: "100m"
memory: "100Mi"
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
Here’s what’s happening:
apiVersion: apps/v1andkind: DaemonSet: Standard Kubernetes object definition. This tells the cluster we’re creating a DaemonSet.metadata.nameandlabels: Identifies our DaemonSet.spec.selector.matchLabels: This is crucial. It tells the DaemonSet which Pods it’s managing. In this case, any Pod with the labelapp: fluentd.spec.template: This is the blueprint for the Pods that the DaemonSet will create. Every Pod created by this DaemonSet will look exactly like this template.template.metadata.labels: These labels are applied to the Pods themselves, so thespec.selectorcan find them.spec.template.spec.containers: Defines the containers within the Pod.name: fluentd: The name of our container.image: fluent/fluentd:v1.14-debian: The Docker image to use for thefluentdagent.resources: Sets resource requests and limits. This is important for stability, preventing a single agent from hogging node resources.volumeMounts: This is where the magic for node-level access happens.varlogmounts the host’s/var/logdirectory into the container at/var/log. This allowsfluentdto read log files directly from the host.varlibdockercontainersmounts the host’s/var/lib/docker/containersdirectory, which is where Docker stores container log files.
spec.template.volumes: Defines the volumes that can be mounted into the containers.name: varlogandhostPath: path: /var/log: This specifies ahostPathvolume, meaning it maps a directory from the host node directly into the Pod.name: varlibdockercontainersandhostPath: path: /var/lib/docker/containers: AnotherhostPathvolume, mapping the Docker container logs directory.
When you apply this DaemonSet (kubectl apply -f your-daemonset.yaml), Kubernetes ensures that one Pod is running on each node in your cluster that matches the DaemonSet’s node selector (if one is specified, otherwise all nodes). If a new node joins the cluster, the DaemonSet controller will automatically create a Pod for it. If a node is removed, its associated Pod is garbage collected.
The core problem DaemonSets solve is ensuring that a specific agent or utility runs on every node without manual intervention. This is common for cluster-level agents like log collectors (fluentd, logstash), monitoring agents (node-exporter, datadog-agent), or network plugins.
The surprising part for many is how tightly coupled hostPath volumes make the Pod to the node’s filesystem. You’re not just getting a copy of data; you’re directly interacting with the host’s file system. This grants immense power (access to system logs, Docker socket, etc.) but also carries significant risk. A misconfigured hostPath can easily lead to accidental deletion of critical host files or security vulnerabilities if not carefully managed. The readOnly: true on the /var/lib/docker/containers mount is a good example of mitigating this risk.
The spec.template.spec.nodeSelector field is often used with DaemonSets to control which nodes the Pods are scheduled on, for instance, to only run on worker nodes or nodes with specific hardware. If omitted, the DaemonSet will try to schedule a Pod on every node.
The next thing you’ll likely encounter is managing the lifecycle of these DaemonSet Pods, especially when it comes to updates. You’ll want to investigate updateStrategy within the DaemonSet spec, which allows for rolling updates or even blue-green deployments of your DaemonSet Pods.