CKA — DaemonSets & Static Pods
CKA Exam Domain
| Domain | Weight |
|---|---|
| Workloads & Scheduling | 15% |
DaemonSets and static Pods are CKA favorites. Expect questions on creating DaemonSets, identifying static Pods, and knowing where static Pod manifests live.
What Is a DaemonSet?
A DaemonSet ensures that a copy of a Pod runs on every node (or a selected subset of nodes) in the cluster. When a new node joins the cluster, the DaemonSet automatically schedules a Pod on it. When a node is removed, the Pod is garbage collected.
Key characteristics:
- One Pod per node (by default).
- Automatically adapts as nodes are added or removed.
- Bypasses the scheduler in older versions; uses the default scheduler since v1.12.
DaemonSet Use Cases
| Use Case | Example |
|---|---|
| Log collection | Fluentd, Filebeat |
| Monitoring agents | Prometheus Node Exporter, Datadog Agent |
| Networking | kube-proxy, Calico, Cilium CNI |
| Storage | CSI node plugins |
| Security | Falco, Twistlock |
Exam Tip: When a question says “run on every node,” think DaemonSet.
Creating a DaemonSet
Here’s a DaemonSet that deploys a Fluentd log collector on every node:
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:
containers:
- name: fluentd
image: fluentd:v1.16
resources:
requests:
cpu: "100m"
memory: "200Mi"
limits:
cpu: "200m"
memory: "400Mi"
volumeMounts:
- name: varlog
mountPath: /var/log
volumes:
- name: varlog
hostPath:
path: /var/log
tolerations:
- operator: "Exists"
kubectl apply -f fluentd-ds.yaml
kubectl get daemonset fluentd -n kube-system
Notice the
tolerationswithoperator: "Exists"— this ensures the DaemonSet runs even on tainted nodes (including the control plane).
DaemonSet vs Deployment
| Feature | DaemonSet | Deployment |
|---|---|---|
| Scheduling | One Pod per node | Replicas spread by scheduler |
| Replicas | Determined by number of nodes | Explicitly set |
| Use Case | Node-level agents | Stateless application workloads |
| Scaling | Add/remove nodes | Change replica count |
| Node targeting | Automatic (all or selected nodes) | Via affinity/nodeSelector |
What Are Static Pods?
A static Pod is managed directly by the kubelet on a specific node — not by the API server or controllers. The kubelet watches a directory for Pod manifest files and automatically creates/deletes Pods based on what it finds.
Key characteristics:
- Defined by YAML files on the node’s filesystem.
- Managed by kubelet, not the control plane.
- A mirror Pod is created in the API server so you can see it with
kubectl, but you cannot modify or delete it throughkubectl. - If you delete the mirror Pod, kubelet recreates it.
Static Pod Directory
The kubelet looks for static Pod manifests in a directory configured by staticPodPath. The default is:
/etc/kubernetes/manifests/
Verify the path:
cat /var/lib/kubelet/config.yaml | grep staticPodPath
Expected output:
staticPodPath: /etc/kubernetes/manifests
Exam Tip: On kubeadm clusters, the static Pod path is always
/etc/kubernetes/manifests/. If a question asks you to find or create a static Pod, that’s where to look.
Creating Static Pods
To create a static Pod, place a YAML manifest in the static Pod directory on the target node:
# SSH to the node (if needed)
ssh <node-name>
# Create the manifest
cat <<EOF > /etc/kubernetes/manifests/static-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
EOF
The kubelet detects the new file and starts the Pod automatically. Verify from the control plane:
kubectl get pods -A | grep static-nginx
The Pod name will have the node name appended, e.g., static-nginx-worker-1.
Delete a static Pod:
# On the node:
rm /etc/kubernetes/manifests/static-nginx.yaml
The kubelet will terminate the Pod automatically.
Static Pod vs Regular Pod
| Feature | Static Pod | Regular Pod |
|---|---|---|
| Managed By | kubelet | API server / controllers |
Visible in kubectl? |
Yes (mirror Pod) | Yes |
Can modify via kubectl? |
No | Yes |
| Restart Behavior | kubelet restarts it if it crashes | Depends on restartPolicy and controller |
| Mirror Pod | Created automatically | N/A |
| Use Case | Control plane components | Application workloads |
Control Plane as Static Pods
On kubeadm clusters, the control plane components are deployed as static Pods:
ls /etc/kubernetes/manifests/
etcd.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml
These are managed by the kubelet on the control plane node. This is why the control plane can recover even if the API server goes down — kubelet restarts the static Pods.
kubectl get pods -n kube-system | grep -E "etcd|apiserver|controller|scheduler"
Exam Tip: If a question asks “how are control plane components managed in kubeadm?”, the answer is static Pods.
Combining Scheduling with DaemonSets
You can use nodeSelector and tolerations with DaemonSets to limit which nodes get the Pod.
Run only on nodes with a specific label:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: monitoring-agent
spec:
selector:
matchLabels:
app: monitoring
template:
metadata:
labels:
app: monitoring
spec:
containers:
- name: agent
image: prom/node-exporter:v1.7.0
nodeSelector:
monitoring: enabled
tolerations:
- key: "dedicated"
operator: "Equal"
value: "monitoring"
effect: "NoSchedule"
This DaemonSet only places Pods on nodes labeled monitoring=enabled and tolerates the dedicated=monitoring:NoSchedule taint.
kubectl Commands
# List DaemonSets
kubectl get daemonsets -n kube-system
# Describe a DaemonSet
kubectl describe daemonset kube-proxy -n kube-system
# Check DaemonSet Pods
kubectl get pods -n kube-system -l k8s-app=kube-proxy -o wide
# Create a DaemonSet from YAML
kubectl apply -f daemonset.yaml
# Static Pods — check the manifests directory
ls /etc/kubernetes/manifests/
# Find the staticPodPath
cat /var/lib/kubelet/config.yaml | grep staticPodPath
# Identify static Pods (they have the node name appended)
kubectl get pods -n kube-system -o wide | grep <node-name>
Practice Questions
Q1. Create a DaemonSet named log-collector in the default namespace that runs busybox:1.36 on every node.
Show Answer
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
spec:
selector:
matchLabels:
app: log-collector
template:
metadata:
labels:
app: log-collector
spec:
containers:
- name: busybox
image: busybox:1.36
command: ["sleep", "infinity"]
tolerations:
- operator: "Exists"
kubectl apply -f log-collector.yaml
kubectl get daemonset log-collector
Q2. Where are static Pod manifests stored on a kubeadm cluster? How do you verify this?
Show Answer
Static Pod manifests are stored in /etc/kubernetes/manifests/.
Verify:
cat /var/lib/kubelet/config.yaml | grep staticPodPath
Q3. How do you create a static Pod named static-web on node worker-1?
Show Answer
SSH to the node and place a manifest in the static Pod directory:
ssh worker-1
cat <<EOF > /etc/kubernetes/manifests/static-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-web
spec:
containers:
- name: nginx
image: nginx:1.27
EOF
The kubelet will create the Pod automatically. Verify with kubectl get pods -A | grep static-web.
Q4. What happens if you kubectl delete a static Pod’s mirror Pod?
Show Answer
The kubelet recreates the mirror Pod immediately. The only way to permanently delete a static Pod is to remove its manifest file from the static Pod directory on the node.
Q5. A DaemonSet needs to run only on nodes labeled tier=edge. How do you configure this?
Show Answer
Add nodeSelector to the DaemonSet’s Pod template:
spec:
template:
spec:
nodeSelector:
tier: edge
The DaemonSet will only schedule Pods on nodes with the tier=edge label.