Di episode ini kita akan coba bahas important Kubernetes controller yaitu DaemonSet. Kita akan mempelajari bagaimana DaemonSet memastikan copy dari Pod berjalan di semua (atau beberapa) node di cluster.

Catatan
Untuk kalian yang ingin membaca episode sebelumnya, bisa click thumbnail episode 12 di bawah ini
Di episode sebelumnya kita sudah belajar tentang ReplicaSet, modern replacement untuk ReplicationController dengan enhanced selector capability. Selanjutnya di episode 13 kali ini, kita akan coba bahas tipe controller yang berbeda yaitu DaemonSet.
Catatan: Disini saya akan menggunakan Kubernetes Cluster yang di install melalui K3s.
Tidak seperti ReplicaSet yang maintain jumlah Pod replica yang spesifik, DaemonSet memastikan bahwa copy dari Pod berjalan di semua (atau beberapa) node di cluster kalian. Ini sangat berguna untuk menjalankan cluster-wide service seperti log collector, monitoring agent, atau network plugin.
DaemonSet memastikan bahwa semua (atau beberapa) node menjalankan copy dari Pod. Saat node ditambahkan ke cluster, Pod otomatis ditambahkan ke node tersebut. Saat node dihapus dari cluster, Pod tersebut di-garbage collected.
Bayangkan DaemonSet seperti system daemon di Linux - dia berjalan di setiap machine untuk menyediakan system-level service. Di Kubernetes, DaemonSet menjalankan Pod di setiap node untuk menyediakan node-level service.
Karakteristik kunci DaemonSet:
DaemonSet dirancang untuk workload yang perlu berjalan di setiap node di cluster:
Tanpa DaemonSet, kalian perlu:
Mari kita pahami perbedaan kunci nya:
| Aspek | DaemonSet | ReplicaSet |
|---|---|---|
| Pod count | Satu per node | Fixed number across cluster |
| Scheduling | Automatic per node | Scheduler decide placement |
| Use case | Node-level service | Application replica |
| Scaling | Scale dengan node | Manual scaling |
| Node addition | Auto-create Pod | No automatic action |
| Node removal | Auto-remove Pod | No automatic action |
Contoh scenario:
Mari kita buat basic DaemonSet:
Buat file bernama daemonset-basic.yml:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-daemonset
labels:
app: nginx-daemon
spec:
selector:
matchLabels:
app: nginx-daemon
template:
metadata:
labels:
app: nginx-daemon
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80Apply konfigurasi:
sudo kubectl apply -f daemonset-basic.ymlVerifikasi DaemonSet dibuat:
sudo kubectl get daemonsetAtau gunakan shorthand:
sudo kubectl get dsOutput:
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
nginx-daemonset 3 3 3 3 3 <none> 30sDESIRED count match dengan jumlah node di cluster kalian.
Cek Pod:
sudo kubectl get pods -o wideOutput:
NAME READY STATUS RESTARTS AGE NODE
nginx-daemonset-abc12 1/1 Running 0 30s node1
nginx-daemonset-def34 1/1 Running 0 30s node2
nginx-daemonset-ghi56 1/1 Running 0 30s node3Perhatikan bahwa ada tepat satu Pod per node.
Untuk melihat informasi detail tentang DaemonSet:
sudo kubectl describe ds nginx-daemonsetOutput:
Name: nginx-daemonset
Selector: app=nginx-daemon
Node-Selector: <none>
Labels: app=nginx-daemon
Annotations: <none>
Desired Number of Nodes Scheduled: 3
Current Number of Nodes Scheduled: 3
Number of Nodes Scheduled with Up-to-date Pods: 3
Number of Nodes Scheduled with Available Pods: 3
Number of Nodes Misscheduled: 0
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=nginx-daemon
Containers:
nginx:
Image: nginx:1.25
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 2m daemonset-controller Created pod: nginx-daemonset-abc12
Normal SuccessfulCreate 2m daemonset-controller Created pod: nginx-daemonset-def34
Normal SuccessfulCreate 2m daemonset-controller Created pod: nginx-daemonset-ghi56By default, DaemonSet berjalan di semua node. Kalian bisa kontrol node mana yang menjalankan DaemonSet Pod menggunakan:
Jalankan DaemonSet hanya di node dengan label spesifik:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: ssd-monitor
spec:
selector:
matchLabels:
app: ssd-monitor
template:
metadata:
labels:
app: ssd-monitor
spec:
nodeSelector:
disktype: ssd
containers:
- name: monitor
image: nginx:1.25DaemonSet ini hanya berjalan di node yang dilabel dengan disktype: ssd.
Pertama, label node:
sudo kubectl label nodes node1 disktype=ssdApply DaemonSet:
sudo kubectl apply -f daemonset-node-selector.ymlCek Pod:
sudo kubectl get pods -o wideKalian akan melihat Pod hanya di node dengan label disktype: ssd.
Node selection yang lebih flexible menggunakan affinity rule:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: production-monitor
spec:
selector:
matchLabels:
app: prod-monitor
template:
metadata:
labels:
app: prod-monitor
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: environment
operator: In
values:
- production
- staging
containers:
- name: monitor
image: nginx:1.25DaemonSet ini berjalan di node dimana environment adalah production atau staging.
Jalankan DaemonSet di node dengan taint spesifik:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: special-daemon
spec:
selector:
matchLabels:
app: special-daemon
template:
metadata:
labels:
app: special-daemon
spec:
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: daemon
image: nginx:1.25DaemonSet ini bisa berjalan di control plane node (yang normally punya taint preventing regular Pod).
Contoh realistic menjalankan Fluentd log collector di setiap 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:
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
containers:
- name: fluentd
image: fluent/fluentd:v1.16
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
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/containersDaemonSet ini:
kube-system namespaceMenjalankan Prometheus Node Exporter di setiap node:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
hostNetwork: true
hostPID: true
containers:
- name: node-exporter
image: prom/node-exporter:latest
args:
- --path.procfs=/host/proc
- --path.sysfs=/host/sys
- --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($|/)
ports:
- containerPort: 9100
hostPort: 9100
name: metrics
resources:
limits:
memory: 180Mi
requests:
cpu: 100m
memory: 180Mi
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: /sysDaemonSet ini:
/proc dan /sys untuk system metricMenjalankan network plugin di setiap node:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: kube-proxy
namespace: kube-system
labels:
k8s-app: kube-proxy
spec:
selector:
matchLabels:
k8s-app: kube-proxy
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
template:
metadata:
labels:
k8s-app: kube-proxy
spec:
priorityClassName: system-node-critical
hostNetwork: true
tolerations:
- operator: Exists
effect: NoSchedule
containers:
- name: kube-proxy
image: registry.k8s.io/kube-proxy:v1.28.0
command:
- /usr/local/bin/kube-proxy
- --config=/var/lib/kube-proxy/config.conf
securityContext:
privileged: true
volumeMounts:
- name: kube-proxy
mountPath: /var/lib/kube-proxy
volumes:
- name: kube-proxy
configMap:
name: kube-proxyDaemonSet ini:
DaemonSet support dua update strategy:
Pod hanya di-update saat manually deleted:
spec:
updateStrategy:
type: OnDeleteDengan strategy ini:
Pod otomatis di-update secara rolling fashion:
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1Dengan strategy ini:
maxUnavailable settingContoh update DaemonSet:
# Edit DaemonSet
sudo kubectl edit ds nginx-daemonset
# Atau update file YAML dan apply
sudo kubectl apply -f daemonset-basic.ymlWatch rolling update:
sudo kubectl rollout status ds nginx-daemonsetsudo kubectl delete ds nginx-daemonsetIni menghapus DaemonSet dan semua Pod nya.
sudo kubectl delete ds nginx-daemonset --cascade=orphanIni hanya menghapus DaemonSet, membiarkan Pod berjalan sebagai orphan.
Deploy monitoring agent untuk collect metric dari setiap node:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: monitoring-agent
spec:
selector:
matchLabels:
app: monitoring
template:
metadata:
labels:
app: monitoring
spec:
containers:
- name: agent
image: monitoring-agent:latest
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 100MiCollect log dari semua node:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-collector
spec:
selector:
matchLabels:
app: logs
template:
metadata:
labels:
app: logs
spec:
containers:
- name: collector
image: log-collector:latest
volumeMounts:
- name: logs
mountPath: /var/log
volumes:
- name: logs
hostPath:
path: /var/logJalankan security agent di setiap node:
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: security-scanner
spec:
selector:
matchLabels:
app: security
template:
metadata:
labels:
app: security
spec:
containers:
- name: scanner
image: security-scanner:latest
securityContext:
privileged: trueDaemonSet Pod berjalan di setiap node, jadi resource usage multiply:
Problem: Tanpa limit, DaemonSet Pod bisa consume semua node resource.
Solusi: Selalu set resource request dan limit:
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256MiProblem: Menggunakan DaemonSet untuk regular application yang tidak perlu berjalan di setiap node.
Solusi: Gunakan Deployment atau ReplicaSet untuk application workload. Gunakan DaemonSet hanya untuk node-level service.
Problem: DaemonSet Pod tidak schedule di tainted node.
Solusi: Tambahkan appropriate toleration:
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoScheduleProblem: DaemonSet tidak bisa access host directory karena permission.
Solusi: Gunakan appropriate security context dan volume mount:
securityContext:
privileged: true
volumeMounts:
- name: host-path
mountPath: /host
readOnly: trueProblem: Manual Pod deletion required untuk update.
Solusi: Gunakan RollingUpdate strategy:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1Karena DaemonSet berjalan di setiap node, resource usage di-multiply:
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256MiEnable automatic update:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1Allow DaemonSet berjalan di semua node including control plane:
tolerations:
- operator: Exists
effect: NoScheduleSet appropriate priority untuk system DaemonSet:
priorityClassName: system-node-criticalTambahkan Probe untuk ensure DaemonSet Pod healthy:
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5System DaemonSet harus berjalan di system namespace:
metadata:
namespace: kube-systemsudo kubectl get dssudo kubectl describe ds nginx-daemonsetsudo kubectl get pods -l app=nginx-daemon -o widesudo kubectl rollout status ds nginx-daemonsetsudo kubectl get events --sort-by='.lastTimestamp' | grep DaemonSetPada episode 13 ini, kita telah membahas DaemonSet di Kubernetes secara mendalam. Kita sudah belajar apa itu DaemonSet, bagaimana dia berbeda dari ReplicaSet, dan kapan menggunakannya untuk node-level service.
Key takeaway:
DaemonSet essential untuk menjalankan infrastructure component yang perlu present di setiap node di cluster kalian. Dengan memahami DaemonSet, kalian bisa effectively deploy dan manage cluster-wide service seperti log collector, monitoring agent, dan network plugin.
Bagaimana, makin jelas kan tentang DaemonSet di Kubernetes? Di episode 14 berikutnya, kita akan membahas Job, controller yang dirancang untuk menjalankan task sampai selesai daripada keep Pod running continuously. Jadi, pastikan tetap semangat belajar dan nantikan episode selanjutnya!
Catatan
Untuk kalian yang ingin lanjut ke episode berikutnya, bisa click thumbnail episode 14 di bawah ini