DevOps

Kubernetes Logging yang Bener: Fluent Bit ke Elasticsearch

Asep Alazhari

Gimana gue implementasi centralized logging buat Kubernetes pake Fluent Bit dan Elasticsearch, ngesolve masalah log sementara dan mengaktifkan pengumpulan log multi namespace.

Kubernetes Logging yang Bener: Fluent Bit ke Elasticsearch

Hari Dimana Gue Kehilangan Logs Debugging Penting Selamanya

Bayangin deh. Aplikasi Next.js production lo crash jam 3 pagi. User pada komplain. Lo langsung cek logs tapi pod nya udah restart duluan. Semua logs hilang. Selamanya. Ini kejadian sama gue tiga kali sebelum gue akhirnya mutusin buat benerin ini bener bener.

Ngejalanin aplikasi di Kubernetes itu bikin skalabilitas dan ketahanan jadi luar biasa. Pod lo restart otomatis kalo gagal. Naik turun skalanya berdasarkan trafik. Diganti saat deployment. Tapi nih masalahnya. Setiap kali pod mati, semua logs nya ikut ilang.

Selama berbulan bulan, gue ngandalin Axiom buat logging level aplikasi. Tapi itu cuma nangkep apa yang gue tulis secara eksplisit di code Next.js aja. System error, startup message, sama crash dump tetep ada di log container sementara. Pas pod restart, petunjuk debugging penting itu langsung lenyap.

Gue butuh solusi yang bisa nyimpen setiap log dari setiap pod di namespace my-app gue, bahkan pas pod dateng dan pergi. Jawabannya adalah centralized logging pake Fluent Bit ngirim ke Elasticsearch.

Kenapa Centralized Logging Penting di Kubernetes

Pod Kubernetes itu didesain buat jadi sementara. Dateng dan pergi. Naik turun. Restart. Desain ini bikin Kubernetes powerful tapi bikin logging jadi mimpi buruk.

Pas lo jalanin kubectl logs, lo cuma liat logs dari pod yang lagi jalan aja. Kalo pod crash dua jam yang lalu, logs itu udah hilang kecuali lo punya centralized logging.

Centralized logging ngesolve ini dengan ngumpulin logs dari semua container dan ngirim ke sistem penyimpanan permanen. Sekarang pas pod mati, logs nya tetep hidup. Lo bisa nyari log historis, melacak error di seluruh restart pod, dan debug masalah yang kejadian berjam jam atau berhari hari lalu.

Buat captive portal my-app gue yang ngelayani ribuan pengguna WiFi setiap hari, kehilangan logs itu artinya kehilangan visibilitas ke masalah user, kejadian keamanan, dan masalah performa. Gue butuh setiap log tersimpan selamanya.

Milih Fluent Bit Dibanding Solusi Lain

Ada beberapa tools yang nangani logging Kubernetes. Fluentd, Filebeat, Logstash, sama Fluent Bit semua bisa. Gue pilih Fluent Bit karena tiga alasan kuat nih.

Pertama, efisiensi resource. Fluent Bit cuma pake sekitar 100 sampe 200MB memori per node dibanding Fluentd yang bisa 300MB atau lebih. Pas lo jalanin ini sebagai DaemonSet di setiap node cluster lo, penghematannya lumayan banget.

Kedua, kesederhanaan. Kebutuhan gue sederhana. Ngumpulin logs dari namespace tertentu dan ngirim ke Elasticsearch. Fluent Bit nangani ini dengan sempurna tanpa kompleksitas plugin Fluentd atau pipeline Logstash.

Ketiga, integrasi Kubernetes bawaan. Fluent Bit otomatis memperkaya logs dengan nama pod, namespace, label, sama annotation. Metadata ini bikin pencarian dan penyaringan logs jadi jauh lebih gampang.

Status proyek CNCF resmi juga bikin gue yakin. Fluent Bit udah teruji di ribuan cluster Kubernetes production di seluruh dunia.

Arsitekturnya: Gimana Fluent Bit Ngumpulin Logs

Ngerti gimana Fluent Bit ngumpulin logs bantu gue debug masalah nanti. Ini cara kerjanya nih.

Kubernetes nulis semua log container ke file di setiap node di /var/log/containers/. Setiap file ikutin pola penamaan. Nama pod, namespace, nama container, sama container ID semua muncul di nama file.

Contohnya, file log kayak myapp-698fdf7c65-2lz2p_my-app_myapp-abc123.log. Perhatiin gimana namespace my-app ada tepat di tengah nama file. Pola ini jadi penting banget nanti.

Fluent Bit jalan sebagai DaemonSet, artinya satu pod jalan di setiap node. Setiap pod Fluent Bit mantau direktori log di node nya pake tail input plugin. Pas baris log baru muncul, Fluent Bit baca.

Filter Kubernetes terus nyambung ke Kubernetes API server dan memperkaya setiap log dengan metadata. Dia nambahin nama pod, namespace, label, annotation, dan lainnya. Pengayaan ini ngubah log teks biasa jadi data terstruktur.

Akhirnya, Elasticsearch output plugin ngirim log yang udah diperkaya ke cluster Elasticsearch lo. Fluent Bit nangani retry, buffering, sama batching otomatis. Kalo Elasticsearch down sementara, logs ngantri dan dikirim pas koneksi balik.

Implementasi Awal: Deploy Fluent Bit

Gue mulai dengan bikin resource Kubernetes yang dibutuhin. Pertama, namespace logging khusus buat misahin infrastruktur logging dari beban kerja aplikasi.

Berikutnya RBAC permission. Fluent Bit butuh baca metadata pod dari Kubernetes API. Gue bikin ServiceAccount, ClusterRole, sama ClusterRoleBinding yang kasih Fluent Bit akses baca ke pod, namespace, sama log.

ConfigMap nyimpen konfigurasi Fluent Bit. Ini tempat lo nentuin input, filter, sama output. Konfigurasi awal gue baca semua log container, diperkaya dengan metadata Kubernetes, dan dikirim ke Elasticsearch.

Deployment DaemonSet mastiin Fluent Bit jalan di semua enam node di cluster gue. Gue atur batas resource buat nyegah Fluent Bit makan terlalu banyak CPU atau memori. Konfigurasi mount tiga path utama. Direktori /var/log/containers buat baca log. Direktori /var/log/pods buat metadata tambahan. Dan direktori /var/fluent-bit/state buat melacak posisi baca.

Akhirnya, gue integrasiin deployment ke pipeline GitLab CI/CD gue. Sekarang setiap git push otomatis nge-update infrastruktur logging bareng aplikasi gue.

Ini struktur inti ConfigMap yang gue mulai:

[INPUT]
    Name tail
    Path /var/log/containers/*.log
    Tag kube.*

[FILTER]
    Name kubernetes
    Match kube.*
    Merge_Log On
    Keep_Log On

[OUTPUT]
    Name es
    Match kube.*
    Host 10.0.1.100
    Port 9200
    Index app_logs
    Logstash_Format On

Konfigurasi ini ngumpulin semua logs dari semua namespace. Yang bawa gue ke masalah besar pertama.

Masalah Pertama: Ngumpulin Terlalu Banyak Logs

Dalam hitungan jam, gue nyadar Elasticsearch penuh sama logs dari mana mana. Namespace sistem kayak kube-system, cattle-system, sama logging nge-generate logs dalam jumlah gede banget. Log aplikasi my-app gue tenggelam di kebisingan.

Gue butuh nyaring logs buat ngumpulin cuma dari namespace my-app aja. Ini kayaknya simpel. Tambahin grep filter buat nge-match field namespace. Ini yang gue coba:

[FILTER]
    Name grep
    Match kube.*
    Regex kubernetes.namespace_name my-app

Gue terapin konfigurasi, restart Fluent Bit, dan tunggu. Ga ada yang berubah. Logs dari semua namespace tetep ngalir masuk. Gue habisin berjam jam debugging ini sebelum nemuin akar masalahnya.

Misteri Grep Filter: Kenapa Nested Field Bikin Rusak Semua

Dokumentasi grep filter bilang pake nama field langsung. Tapi gagal tanpa suara. Ga ada error. Ga ada warning. Cuma ga jalan aja.

Setelah meriksa data Elasticsearch, gue nemuin kenapa. Filter Kubernetes bikin objek bersarang. Struktur field nya kayak gini:

{
    "kubernetes": {
        "namespace_name": "my-app",
        "pod_name": "myapp-abc123"
    }
}

Grep filter di Fluent Bit ga bisa ngakses nested field pake dot notation. Pas gue pake kubernetes.namespace_name, grep ga bisa nemuin field nya. Jadi dia ngebiarin semua logs lewat.

Gue coba mindahin grep filter sebelum nest filter. Gue coba ganti nama field. Gue coba pola regex yang beda. Ga ada yang jalan konsisten. Keterbatasan grep filter sama nested field adalah jalan buntu.

Kalo lo lagi baca Kenapa Docker Buildx Mengubah CI/CD Gue Selamanya, lo tau gue benci buang waktu di workaround. Gue butuh solusi lebih baik.

Solusi Elegan: Filter di Sumber

Terus gue sadar. Kenapa nyaring setelah baca logs padahal gue bisa nyaring sebelum bacanya. File log container udah nyertain namespace di nama file.

Daripada baca /var/log/containers/_.log terus nyaring belakangan, gue ganti input path jadi /var/log/containers/_my-app*.log. Pola ini cuma cocok sama file dari namespace my-app.

Ini konfigurasi yang udah di-update:

[INPUT]
    Name tail
    Path /var/log/containers/*_my-app_*.log
    Tag myapp
    DB /var/fluent-bit/state/flb_myapp.db

Pendekatan ini punya beberapa keuntungan. Pertama, nyaring di level filesystem sebelum Fluent Bit bahkan buka file. Lebih efisien daripada baca semuanya terus nyaring.

Kedua, ngurangin penggunaan memori. Fluent Bit cuma nge-buffer logs dari pod my-app. 50MB buffer memori jadi jauh lebih cukup.

Ketiga, nyederhanain konfigurasi. Ga ada rantai filter yang kompleks. Ga perlu khawatir soal nama field atau nesting. Cuma pola path yang sederhana.

Gue terapin perubahan ini, restart Fluent Bit, dan verifikasi. Sempurna. Cuma logs my-app yang muncul di Elasticsearch. Solusinya elegan, efisien, dan andal.

Memperluas ke Beberapa Namespace

Beberapa minggu kemudian, gue butuh nambahin logging buat proyek lain. Namespace my-second-app ngejalanin aplikasi captive portal terpisah di cluster Kubernetes yang sama.

Kerennya pendekatan path filtering adalah gimana gampangnya di-scale. Gue tambahin bagian input kedua dengan tag dan pola path yang beda:

[INPUT]
    Name tail
    Path /var/log/containers/*_my-app_*.log
    Tag myapp
    DB /var/fluent-bit/state/flb_myapp.db

[INPUT]
    Name tail
    Path /var/log/containers/*_my-second-app_*.log
    Tag secondapp
    DB /var/fluent-bit/state/flb_secondapp.db

Terus gue arahin setiap tag ke index Elasticsearch yang beda pake bagian output terpisah:

[OUTPUT]
    Name es
    Match myapp
    Index app_logs
    Logstash_Prefix app_logs

[OUTPUT]
    Name es
    Match secondapp
    Index second_app_logs
    Logstash_Prefix second_app_logs

Sekarang logs my-app masuk ke index app_logs-YYYYMMDD dan logs my-second-app masuk ke index second_app_logs-YYYYMMDD. Kedua proyek berbagi DaemonSet Fluent Bit yang sama tapi mempertahankan aliran log terpisah.

Pendekatan terpusat ini lebih efisien daripada ngejalanin deployment Fluent Bit terpisah buat setiap namespace. Satu DaemonSet nangani beberapa namespace sambil ngejaga log tetep teratur.

Best Practice Deployment Production

Setelah ngejalanin setup ini di production selama berminggu minggu, beberapa best practice muncul nih.

Pertama, selalu pake file database terpisah buat setiap input. Parameter DB bilang Fluent Bit dimana melacak posisi bacanya. Kalo beberapa input berbagi database yang sama, mereka saling ganggu satu sama lain.

Kedua, atur batas buffer memori yang sesuai. Gue pake 50MB per input, yang nangani volume log aplikasi Next.js tipikal tanpa masalah. Pantau penggunaan memori dan sesuaikan sesuai kebutuhan.

Ketiga, aktifin logika retry di output Elasticsearch. Gangguan jaringan pasti terjadi. Parameter Retry_Limit mastiin Fluent Bit terus nyoba ngirim logs bahkan pas Elasticsearch down sementara.

Keempat, pake rotasi indeks harian. Parameter Logstash_Format sama Logstash_DateFormat bikin indeks baru setiap hari. Ini bikin penghapusan log lama lebih gampang dan ngejaga performa query tetep cepet.

Kelima, implementasiin pemantauan. Fluent Bit mengekspos metrik di port 2020. Integrasiin sama Prometheus buat melacak laju pengumpulan log, penggunaan buffer, sama kesehatan koneksi Elasticsearch.

Keenam, rencanain manajemen siklus hidup indeks. Logs tumbuh terus kalo lo biarin. Tentuin berapa lama nyimpen logs dan otomasi penghapusan indeks lama. Gue simpen 30 hari logs buat debugging terus hapus indeks yang lebih lama.

Manfaat: Apa yang Centralized Logging Aktifkan

Implementasi centralized logging ngubah gimana gue debug masalah production.

Pas user ngelaporin masalah, gue nyari di Elasticsearch pake session ID atau alamat IP mereka. Semua request mereka muncul di seluruh restart pod dan deployment. Gue liat perjalanan pengguna yang lengkap.

Pemantauan performa meningkat drastis. Gue query Elasticsearch buat waktu respons API yang lambat atau tingkat error yang tinggi. Pola muncul yang tadinya ga kelihatan.

Audit keamanan jadi mungkin. Gue melacak kegagalan autentikasi, pola akses mencurigakan, sama potensi serangan. Semua tersimpan bahkan pas pod scale down.

Perencanaan kapasitas pake data nyata sekarang. Gue menganalisis volume log berdasarkan waktu dalam sehari sama hari dalam seminggu. Pola trafik memandu keputusan penskalaan infrastruktur.

Integrasi sama Panduan Praktis Automated Docker Tagging di GitLab CI/CD artinya gue bisa menghubungkan log dengan deployment tertentu. Pas versi Docker image baru nyebabin masalah, logs bilang gue persis apa yang rusak.

Masalah Umum dan Troubleshooting

Beberapa masalah bisa bikin lo kesulitan pas implementasi logging Fluent Bit.

Kalo logs ga muncul di Elasticsearch, cek tiga hal. Pertama, pastiin pod Fluent Bit jalan. Kedua, cek log Fluent Bit buat error koneksi. Ketiga, pastiin Elasticsearch bisa diakses dari dalam cluster.

Kalo logs muncul tapi kurang metadata Kubernetes, cek RBAC permission. ServiceAccount butuh permission get, list, sama watch di pod sama namespace.

Kalo penggunaan memori tumbuh ga terkendali, batas buffer lo kemungkinan terlalu tinggi. Atau Elasticsearch ga bisa ngimbangin volume log. Cek parameter Mem_Buf_Limit sama laju ingestion Elasticsearch.

Kalo log lama dari sebelum perubahan konfigurasi tetep muncul, lo lagi liat data historis. Query Elasticsearch pake rentang waktu buat liat log terbaru aja. Indeks lama masih berisi log sebelum filter.

Kalo logs dari namespace yang ga diduga muncul, periksa ulang pola input path lo. Pastiin posisi underscore cocok sama format nama file log Kubernetes persis.

Poin Penting buat Kubernetes Logging

Centralized logging ngesolve masalah pod sementara di Kubernetes. Logs lo tetep bertahan bahkan pas pod mati. Debugging jadi mungkin. Analisis historis jadi kenyataan.

Fluent Bit nyediain solusi yang efisien dan ringan buat pengumpulan log. Penyaringan level input pake pola file path ngalahin rantai filter kompleks setiap waktu. Pendekatan ini sederhana, efisien, dan gampang banget di-scale ke beberapa namespace.

RBAC permission itu penting. Tanpa permission yang tepat, Fluent Bit ga bisa memperkaya logs sama metadata Kubernetes. ServiceAccount, ClusterRole, sama ClusterRoleBinding bukan opsional.

Rencanain manajemen siklus hidup indeks dari hari pertama. Logs tumbuh tanpa batas. Tentuin kebijakan retensi dari awal dan otomasi penghapusan data lama.

Mulai dari satu namespace. Bikin sampe jalan. Pastiin logs ngalir dengan bener. Terus perluas ke namespace tambahan. Pendekatan bertahap ngurangin kompleksitas dan bikin troubleshooting lebih gampang.

Kubernetes logging ga harus rumit. Dengan pendekatan yang tepat, lo dapet log yang persisten dan bisa dicari yang ngubah gimana lo ngerti sistem production lo. Ketenangan pikiran tau lo ga bakal kehilangan informasi debugging penting lagi sepadan sama setiap jam yang dihabisin buat nge-implementasi ini dengan bener.

Back to Blog

Related Posts

View All Posts »