DaemonSet #

Di dalam kluster Kubernetes yang terus berkembang, ada kebutuhan infrastruktur tertentu di mana setiap Worker Node harus menjalankan satu kontainer pendukung yang sama. Misalnya, kita ingin mengumpulkan log dari seluruh kontainer di setiap node, memantau utilisasi CPU dan RAM fisik di tingkat mesin host, atau menjalankan agen routing jaringan (CNI plugin). Jika kita mendeploy agen-agen ini menggunakan Deployment biasa, tidak ada jaminan bahwa setiap node akan mendapatkan tepat satu Pod. Beberapa node mungkin akan memiliki dua Pod, sementara node lain kosong. Untuk menjamin distribusi agen secara presisi satu Pod per node, Kubernetes menyediakan objek khusus bernama DaemonSet.

DaemonSet bertugas memastikan bahwa satu replika Pod yang kita spesifikasikan selalu berjalan secara konsisten di setiap node kluster (atau di setiap node yang memenuhi kriteria seleksi tertentu). Memahami cara kerja DaemonSet, penggunaan akses tingkat sistem (host access), serta aturan toleransi (Tolerations) Control Plane sangat penting bagi administrator kluster untuk mengelola sistem pemantauan dan agen jaringan secara aman dan efisien.


Mengapa DaemonSet Dibutuhkan? (Node-Level Agents) #

Secara konseptual, DaemonSet bekerja dengan prinsip yang sangat sederhana:

Satu Node = Satu Pod DaemonSet

Ketika kita mendeploy DaemonSet:

  1. Deteksi Otomatis Node Baru: Jika kluster kita melakukan autoscaling dan ada 3 Worker Node baru bergabung, DaemonSet Controller akan langsung mendeteksi hal tersebut dan secara otomatis menjadwalkan Pod DaemonSet baru ke 3 node baru tersebut tanpa campur tangan manual.
  2. Pembersihan Node Hancur: Sebaliknya, jika ada node yang dihapus dari kluster, DaemonSet Controller akan menghapus Pod yang terikat pada node tersebut dan membiarkan Garbage Collector membuang sisa-sisa datanya.

Berbeda dengan Deployment biasa yang diserahkan penuh kepada algoritma Scheduler untuk diletakkan di node mana saja yang paling kosong, DaemonSet secara tradisional melewati sebagian besar kalkulasi scheduler normal. Ia langsung menetapkan Pod ke node target menggunakan field spec.nodeName di dalam manifest internal Pod.


Interaksi DaemonSet dengan Node Cordon, Drain, dan Taints #

Salah satu karakteristik unik dari DaemonSet adalah perilakunya yang sangat persisten terhadap perubahan status node host:

1. Perilaku Saat Node di-Cordon #

Ketika seorang administrator menjalankan perintah kubectl cordon <node-name>, node tersebut akan ditandai sebagai Unschedulable. Scheduler Kubernetes dijamin tidak akan pernah menempatkan Pod baru dari objek Deployment ke node tersebut. Namun, DaemonSet Controller mengabaikan batasan cordon ini.

  • Jika ada DaemonSet baru dideploy atau ada pod DaemonSet yang terhapus secara tidak sengaja di node yang di-cordon, DaemonSet Controller tetap akan menjadwalkan ulang Pod DaemonSet ke sana.
  • Hal ini dilakukan karena kita tetap membutuhkan layanan infrastruktur dasar (seperti CNI network agent atau log shipper) untuk tetap menyala mengawasi node meskipun node tersebut tidak lagi menerima Pod aplikasi baru.

2. Perilaku Saat Node di-Drain #

Saat kita menjalankan kubectl drain <node-name>, seluruh Pod aplikasi akan diusir (evicted) secara paksa dari node tersebut agar node dapat dipelihara dengan aman.

  • Secara default, perintah kubectl drain akan menolak berjalan dan mengembalikan error jika mendeteksi adanya Pod DaemonSet di node tersebut.
  • Untuk melanjutkan proses drain tanpa menghapus DaemonSet (karena DaemonSet memang didesain untuk tetap bertahan di node), kita harus menyertakan flag khusus:
    kubectl drain <node-name> --ignore-daemonsets=true
    

Tabel Komparasi: DaemonSet vs Static Pods #

Kubernetes memiliki mekanisme lain untuk menjalankan Pod langsung di tingkat node, yaitu Static Pods. Berikut perbandingan mendasar untuk membantu kita memilih pendekatan yang tepat:

Dimensi Perbandingan DaemonSet Static Pods
Otoritas Pengelola Controller Manager (API Server kluster) Kubelet Lokal (melalui direktori manifest host)
Visibilitas Objek Terdaftar penuh sebagai objek API Server Hanya dibuat sebagai “Mirror Pod” bayangan di API Server
Metode Deployment Sentralisasi via manifest YAML kluster Desentralisasi (harus menulis berkas ke /etc/kubernetes/manifests)
Update Strategi Otomatis via RollingUpdate atau OnDelete Manual dengan mengganti file konfigurasi di disk fisik host
Use Case Utama Log shipper, Exporter metrik, CNI Komponen inti Control Plane (API Server, Scheduler, etcd)

Struktur Manifes DaemonSet Secara Mendalam #

Karena DaemonSet sering kali bertindak sebagai agen pemantau sistem (system monitoring) atau pengelola jaringan, ia membutuhkan hak akses yang jauh lebih tinggi dibanding aplikasi biasa.

Berikut adalah contoh manifest DaemonSet tingkat produksi untuk memantau metrik fisik hardware (Node Exporter):

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: prometheus-node-exporter
  namespace: monitoring
  labels:
    app.kubernetes.io/name: node-exporter
spec:
  selector:
    matchLabels:
      app: node-exporter
  updateStrategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1          # Lakukan update satu node secara berurutan
  template:
    metadata:
      labels:
        app: node-exporter
    spec:
      hostNetwork: true          # Menggunakan network namespace host secara langsung
      hostPID: true              # Menggunakan PID namespace host untuk melihat proses OS
      containers:
      - name: node-exporter
        image: prom/node-exporter:v1.7.0
        securityContext:
          readOnlyRootFilesystem: true
        ports:
        - containerPort: 9100
          hostPort: 9100         # Mengikat port 9100 langsung ke IP fisik node
        resources:
          requests:
            cpu: "50m"
            memory: "64Mi"
          limits:
            cpu: "150m"
            memory: "128Mi"
        volumeMounts:
        - name: proc
          mountPath: /host/proc
          readOnly: true
        - name: sys
          mountPath: /host/sys
          readOnly: true
      volumes:
      - name: proc
        hostPath:
          path: /proc            # Mount filesystem proc milik host
      - name: sys
        hostPath:
          path: /sys             # Mount filesystem sys milik host

Peringatan Keamanan Hak Akses Host (hostPath & hostNetwork) #

  • hostNetwork: true: Memungkinkan kontainer menggunakan jaringan IP fisik Worker Node langsung. Ini sangat cepat karena menghindari overhead translasi jaringan (NAT), namun berbahaya jika port kontainer bentrok dengan aplikasi lain di sistem operasi host.
  • hostPath: Me-mount file atau direktori langsung dari harddisk Worker Node host ke dalam kontainer. Ini wajib digunakan oleh log collector untuk membaca file /var/log/pods.

[!CAUTION] Membiarkan kontainer menggunakan hostPath: / (akses root filesystem host) dengan parameter securityContext.privileged: true memberikan akses kontrol penuh ke sistem operasi node. Jika kontainer ini berhasil dieksploitasi oleh hacker, mereka dapat dengan mudah mengambil alih seluruh server fisik. Selalu terapkan akses baca saja (readOnly: true) pada volume hostPath di produksi.


Use Case 1: Pengumpul Log Tingkat Node (Log Collectors) #

Di Kubernetes, log keluaran kontainer (stdout/stderr) ditulis oleh Kubelet ke dalam folder lokal /var/log/pods di server host Worker Node. Untuk mengumpulkan log-log ini secara realtime, kita menempatkan agen log collector (seperti Fluent Bit atau Promtail) sebagai DaemonSet yang me-mount folder tersebut.

flowchart TD
    subgraph HostNode ["Worker Node Host OS"]
        LogDir["/var/log/pods/\n(Penyimpanan Log Kontainer)"]
    end

    subgraph DaemonSetPod ["DaemonSet Pod (Fluent Bit)"]
        direction TB
        HostMount["Volume Mount: /var/log"]
        Shipper["Fluent Bit Engine"]
    end

    subgraph CentralLogging ["Central Infrastructure"]
        Loki["Grafana Loki / Elasticsearch"]
    end

    LogDir -->|1. Akses Fisik hostPath| HostMount
    HostMount -->|2. Baca Log| Shipper
    Shipper -->|3. Kirim Log asinkron| Loki

    style DaemonSetPod stroke:#9b59b6,stroke-width:2px

Dengan model ini, berapa pun jumlah Pod aplikasi baru yang dibuat di node tersebut, log-nya akan otomatis terbaca oleh satu instansi Fluent Bit DaemonSet yang sama, menghemat RAM dibanding memasang sidecar log shipper di setiap Pod aplikasi.


Use Case 2: Plugin Jaringan (CNI - Container Network Interface) #

Plugin jaringan kluster (seperti Cilium, Calico, atau Flannel) wajib berjalan di setiap node. Tugas mereka adalah memanipulasi aturan tabel jaringan kernel Linux, menyusun rute paket data, serta mengelola enkripsi traffic jaringan antarnode.

  • CNI selalu dideploy sebagai DaemonSet dengan konfigurasi hostNetwork: true dan privileged: true agar dapat langsung membuat virtual interface jaringan di tingkat sistem operasi kernel Linux Worker Node.
  • Calico CNI misalnya, membutuhkan mount filesystem /run/cni, /etc/cni/net.d, dan /lib/modules agar dapat menyuntikkan file konfigurasi konfigurasi routing langsung ke folder konfigurasi jaringan host.

Menjadwalkan DaemonSet di Master/Control Plane Node #

Secara default, master node (Control Plane) kluster memiliki tanda penolak (Taint) bawaan dari Kubernetes untuk mencegah aplikasi biasa berjalan di sana agar master node tidak kehabisan CPU:

node-role.kubernetes.io/control-plane:NoSchedule

Namun, agen pemantau metrik (Node Exporter) atau plugin jaringan (CNI) wajib berjalan di control plane node juga agar master node dapat diawasi kesehatannya dan terhubung ke jaringan kluster. Untuk melewati pembatasan ini, kita harus menambahkan spesifikasi Tolerations di dalam manifes DaemonSet:

spec:
  template:
    spec:
      tolerations:
      # Mengizinkan penempatan Pod di master node Kubernetes lama
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      # Mengizinkan penempatan Pod di control-plane node Kubernetes modern
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      # Mengizinkan penempatan Pod saat status node sedang tidak siap (maintenance)
      - key: node.kubernetes.io/not-ready
        operator: Exists
        effect: NoExecute

Penjadwalan di Sebagian Wilayah Node (Subset of Nodes) #

DaemonSet tidak selalu harus berjalan di 100% total node kluster. Kita dapat membatasi penempatannya hanya pada kelompok node yang memiliki karakteristik perangkat keras (hardware) tertentu menggunakan selektor label nodeSelector atau nodeAffinity.

Contoh use case: Kita ingin mendeploy DaemonSet pemantau temperatur GPU (seperti NVIDIA Device Plugin) yang hanya boleh berjalan di node yang memiliki kartu grafis GPU fisik:

spec:
  template:
    spec:
      nodeSelector:
        accelerator: nvidia-gpu # Hanya jalankan Pod di node yang memiliki label ini

Strategi Update: RollingUpdate vs OnDelete #

Sama seperti Deployment, DaemonSet mendukung dua strategi pembaruan versi kontainer:

  1. RollingUpdate (Default): Begitu kita menerapkan update image pada manifest DaemonSet, Controller akan menghapus Pod DaemonSet lama di satu node, menunggu hingga Pod baru di node tersebut menyala sehat (Ready), barulah melangkah menghapus Pod di node berikutnya secara berurutan. Kapasitas update dikendalikan oleh properti maxUnavailable (biasanya diatur bernilai 1).
  2. OnDelete: Ketika kita mengupdate manifest DaemonSet, Kubernetes tidak akan melakukan restart pada Pod yang sedang berjalan. Update baru akan diterapkan pada suatu node hanya jika kita secara manual menghapus Pod di node tersebut.

[!TIP] Strategi OnDelete sangat direkomendasikan saat memperbarui plugin jaringan (CNI) atau modul kernel kritis di kluster produksi berskala besar. Kita ingin mengontrol secara manual dan bertahap kapan setiap node mengalami gangguan koneksi sementara selama transisi update jaringan guna menghindari putusnya koneksi kluster secara massal.


Anti-Pattern dalam Manajemen DaemonSet #

Berikut adalah dua kesalahan fatal yang sering kali menyebabkan pemborosan resource kluster secara tidak sadar:

Anti-Pattern 1: Menggunakan DaemonSet untuk Aplikasi Web Stateless Biasa #

Mendeploy aplikasi bisnis di bawah kendali DaemonSet demi kepraktisan routing.

ANTI-PATTERN: Mendeploy payment-gateway API sebagai DaemonSet di Kluster 100 Node
// KITA MELAKUKAN:
- Menulis manifest DaemonSet untuk aplikasi payment-api agar ia berjalan di setiap node kluster.
- Kluster kita saat ini memiliki 100 Worker Node.

// KONSEKUENSI DI PRODUKSI:
- Pemborosan CPU & RAM Ekstrem: Kubernetes akan memaksa menjalankan 100 replika aplikasi payment-api.
- Jika traffic transaksi sebenarnya sangat sepi dan cukup dilayani oleh 3 replika saja, 
  kita telah menyia-nyiakan alokasi biaya 97 kontainer kosong yang memakan CPU/RAM secara pasif.
- Kita kehilangan manfaat utama autoscaling dinamis.
✓ SOLUSI YANG BENAR:
- Gunakan objek `Deployment` digabung dengan `Horizontal Pod Autoscaler` (HPA) untuk aplikasi stateless.
- Biarkan Kubernetes menyesuaikan jumlah replika secara dinamis (misal scale down ke 2 saat sepi, scale up ke 20 saat ramai).

Anti-Pattern 2: Mengabaikan Limit Resource Komputasi (Resource Starvation) #

Tidak membatasi alokasi RAM dan CPU untuk agen DaemonSet yang berjalan di seluruh node.

ANTI-PATTERN: Menyuntikkan Log Collector DaemonSet Tanpa limits.memory
// KITA MELAKUKAN:
- Mendeploy Fluent Bit DaemonSet tanpa menuliskan batas limits.memory di manifest.
- Terjadi kebocoran memori (memory leak) di dalam biner log shipper akibat memproses log corrupt.

// KONSEKUENSI DI PRODUKSI:
- Kebocoran Memori Host: Memori Fluent Bit akan terus membengkak hingga memakan seluruh RAM fisik Worker Node.
- Karena DaemonSet adalah proses sistem utama, kernel Linux akan mendeteksi kehabisan RAM fisik 
  dan mulai membunuh aplikasi bisnis penting kita (yang berada di kelas QoS lebih rendah) untuk menyelamatkan node.
- Node menjadi tidak stabil, memicu kegagalan startup berantai.
✓ SOLUSI YANG BENAR:
- Selalu batasi secara ketat memori limits pada DaemonSet (misalnya limit memory 128Mi atau 256Mi).
- Karena DaemonSet berjalan di setiap node, overhead resource yang tidak dibatasi akan terakumulasi 
  secara masif lintas kluster.

Ringkasan #

  • Agen Tingkat Node Otomatis — DaemonSet bertugas memastikan satu replika Pod pendukung selalu berjalan secara konsisten di setiap node kluster yang memenuhi syarat.
  • Penyelaras Skala Kluster — Begitu ada node baru bergabung via autoscaling, DaemonSet secara otomatis akan menempatkan Pod baru di sana tanpa campur tangan operator.
  • Abaikan Batasan Cordon — DaemonSet Controller secara khusus mengabaikan status cordon (Unschedulable) pada node agar agen infrastruktur dasar tetap menyala mendeteksi kesehatan node.
  • Gunakan hostPath & hostNetwork Cermat — Batasi penggunaan hak akses fisik hostPath dan jaringan hostNetwork guna meminimalkan celah keamanan kontainer.
  • Tolerasi untuk Control Plane — Tuliskan blok tolerations secara eksplisit pada spesifikasi manifest jika DaemonSet harus berjalan di control plane master node.
  • Batasi dengan Selektor Node — Manfaatkan selektor nodeSelector atau nodeAffinity jika DaemonSet hanya perlu berjalan di node dengan hardware khusus (seperti node GPU).
  • OnDelete untuk Jaringan Kritis — Pilih strategi update OnDelete saat memperbarui komponen jaringan (CNI) guna menghindari gangguan koneksi kluster secara serentak.
  • Resource Limits Wajib — Terapkan batas limits CPU/RAM yang ketat pada DaemonSet untuk menghindari terjadinya kehabisan memori host fisik node (Resource Starvation).

← Sebelumnya: StatefulSet   Berikutnya: Job & CronJob →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact