Some programs belong on every machine: a log shipper, a metrics agent, the network plugin itself. A Deployment cannot promise "one per node". A DaemonSet can.
One per node
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-agent
spec:
selector:
matchLabels:
app: node-agent
template:
metadata:
labels:
app: node-agent
spec:
containers:
- name: agent
image: busybox
command: ["sh", "-c", "while true; do echo tick; sleep 10; done"]No replicas. The controller looks at the nodes instead: for every node that qualifies, one Pod, with spec.nodeName set to that node.
kubectl get dsNAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
node-agent 3 3 3 3 3 <none> 20sDESIRED is the count of eligible nodes. Add a node and it becomes 4 with a new Pod a moment later; drain a node and its Pod stays, because the Pod is the node's agent.
Which nodes qualify
unschedulable, nothing elseThe last line matters. A cordoned node still gets its agent. A node with your own dedicated=gpu:NoSchedule taint does not, unless the template adds a toleration. Agents that must run everywhere carry operator: Exists with no key, which tolerates every taint.
Updates and drains
Change the template and the DaemonSet replaces its Pods one node at a time. kubectl drain refuses to evict DaemonSet Pods and asks for --ignore-daemonsets, because evicting one is pointless: the controller would put it straight back.