Lab 12 - DaemonSets
Lab 12 - DaemonSets
Goal: one Pod per node, and the two surprises that come with it. Chapter: DaemonSets
# 1 - the cluster already runs several
kubectl get ds -A
kubectl get pods -n kube-system -o wide | grep -i -E 'proxy|calico|cilium|flannel'
kube-proxy and the CNI agent are DaemonSets: they must exist on every node,
including nodes that join tomorrow. There is no replicas field anywhere - the
node list is the count.
# 2 - your own
cd ~
cat > logger-ds.yaml <<'YAML'
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-logger
spec:
selector:
matchLabels:
app: node-logger
template:
metadata:
labels:
app: node-logger
spec:
containers:
- name: logger
image: busybox
command: ["sh", "-c", "while true; do echo \"$(date) $(hostname)\"; sleep 30; done"]
resources:
requests: { cpu: "10m", memory: "16Mi" }
YAML
kubectl apply -f logger-ds.yaml
kubectl get ds node-logger
kubectl get pods -l app=node-logger -o wide
Three Pods, one per worker - and none on control01.
# 3 - why control01 was skipped
kubectl describe node control01 | grep -i -A2 taint
node-role.kubernetes.io/control-plane:NoSchedule. A taint repels Pods that do
not tolerate it. Ordinary workloads stay off the control plane by design.
# 4 - tolerate the taint and watch a fourth Pod appear
kubectl patch ds node-logger --type merge -p '{"spec":{"template":{"spec":{"tolerations":[{"key":"node-role.kubernetes.io/control-plane","operator":"Exists","effect":"NoSchedule"}]}}}}'
kubectl get pods -l app=node-logger -o wide
This is how the CNI and kube-proxy get onto the control plane: they tolerate the taint. Yours should not, normally - revert it in a moment.
# 5 - read the logs of one Pod per node
kubectl logs -l app=node-logger --tail=2 --prefix
--prefix puts the Pod name in front of each line, which is what makes
label-selected logs readable across nodes.
# 6 - target a subset of nodes instead
kubectl label node worker01 storage=nfs
kubectl patch ds node-logger --type merge -p '{"spec":{"template":{"spec":{"nodeSelector":{"storage":"nfs"},"tolerations":[]}}}}'
kubectl get pods -l app=node-logger -o wide
One Pod, on worker01 only. nodeSelector is how storage or GPU agents are
restricted to the machines that actually have the hardware.
# 7 - the drain interaction you will meet again in Lab 16
kubectl drain worker01 --ignore-daemonsets --dry-run=server 2>&1 | head -5
Drain never evicts DaemonSet Pods - the Pod belongs to the node, and the node is
still there. That is why --ignore-daemonsets is on every drain command.
Clean up
# 8 -
kubectl delete -f logger-ds.yaml
kubectl label node worker01 storage-