Jam 2 pagi, HP saya bergetar. Bukan alarm - itu chat dari user: "webnya error gan".
Saya buru-buru buka laptop, cek website... normal. Cek server... SSH masuk. RAM cukup, CPU santai. Semua keliatan baik-baik saja. Tapi user tetap bilang error. 30 menit kemudian baru ketemu biang keroknya: disk penuh. Sudah penuh sejak 3 jam lalu, dan saya baru tahu setelah user yang komplain lebih dulu.
Sejak malam itu saya sadar satu hal. Server yang bagus bukan yang tidak pernah error, tapi yang error-nya ketahuan lebih cepat daripada user. Dan cara paling efektif untuk itu adalah observability. Dua tools yang paling sering saya pakai: Prometheus untuk mengumpulkan metrik, dan Grafana untuk visualisasinya.
Artikel ini bukan teori. Ini setup yang benar-benar saya pakai di production - lengkap dengan docker-compose, konfigurasi Prometheus, dashboard Grafana, sampai alerting ke Telegram. Kalau kamu pernah ngerasain panik karena server down dan baru tahu dari user, artikel ini untuk kamu.
Kenapa Cuma "Cek Server" Tidak Cukup
Dulu pola saya klasik: SSH ke server, jalankan htop, lihat RAM dan CPU, kalau aman ya sudah. Masalahnya, cek manual itu cuma snapshot 5 detik. Server bisa kehabisan disk 3 jam lalu, tapi htop hari ini tetap keliatan normal karena yang penuh partisi /var, bukan yang keliatan di tampilan utama.
Monitoring yang benar itu proaktif. Metrik harus dikumpulkan terus-menerus, disimpan, dan divisualisasikan dalam bentuk grafik. Dengan grafik, kamu bisa lihat tren: disk menipis dari minggu lalu, bukan cuma tahu "penuh" hari ini. Dan yang paling penting: alert. Ketika metrik melewati batas, sistem yang harus lapor ke kamu - bukan user.
Apa itu Prometheus dan Grafana?
Prometheus adalah sistem monitoring open-source yang awalnya dibuat di SoundCloud, sekarang bagian dari Cloud Native Computing Foundation. Tugasnya: menarik metrik dari target (server, database, aplikasi) secara berkala, menyimpannya di time-series database sendiri, dan menyediakan query language bernama PromQL.
Grafana adalah platform visualisasi open-source. Dia tidak mengumpulkan data sendiri - dia membaca dari berbagai data source: Prometheus, MySQL, PostgreSQL, Loki, dan ratusan lainnya. Grafana yang bikin data mentah Prometheus jadi dashboard cantik dengan grafik, gauge, dan alert.
Analoginya gampang: Prometheus itu sensor dan gudang datanya, Grafana itu dashboard speedometer-nya. Dua-duanya open-source dan gratis dipakai di production.
Arsitektur yang Saya Pakai
Setup paling umum untuk satu server VPS:
- Node Exporter - agent kecil yang membacakan metrik server (CPU, RAM, disk, network) ke Prometheus
- Prometheus - menarik metrik dari node exporter tiap 15 detik, menyimpan, dan mengevaluasi alert rules
- Grafana - baca data dari Prometheus, tampilkan dashboard
- Alertmanager - terima alert dari Prometheus, teruskan ke Telegram atau email
Semua jalan di Docker Compose. Satu file konfigurasi, satu perintah docker compose up -d, beres.
Setup dengan Docker Compose
Buat folder project dulu:
mkdir -p ~/monitoring && cd ~/monitoring
Lalu buat file docker-compose.yml:
version: '3.8'
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./alert.rules.yml:/etc/prometheus/alert.rules.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
ports:
- '9090:9090'
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
restart: unless-stopped
pid: host
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/rootfs'
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
environment:
- GF_SECURITY_ADMIN_PASSWORD=GantiPasswordIni
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
ports:
- '3000:3000'
alertmanager:
image: prom/alertmanager:latest
container_name: alertmanager
restart: unless-stopped
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
ports:
- '9093:9093'
volumes:
prometheus_data:
grafana_data:
Catatan penting: jangan expose port Grafana 3000 dan Prometheus 9090 langsung ke internet tanpa proteksi. Di bagian tips produksi nanti saya kasih cara amannya.
Konfigurasi Prometheus
Buat prometheus.yml:
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- /etc/prometheus/alert.rules.yml
alerting:
alertmanagers:
- static_configs:
- targets: ['alertmanager:9093']
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['node-exporter:9100']
scrape_interval: 15s artinya Prometheus narik data tiap 15 detik. evaluation_interval adalah seberapa sering alert rules dicek. Untuk server production, 15 detik itu reasonable - jangan terlalu kecil karena makan resource.
Kalau aplikasi kamu sudah expose metrik sendiri (misalnya Spring Boot Actuator, atau endpoint /metrics dari aplikasi Go), tinggal tambah job baru:
- job_name: 'my-app'
static_configs:
- targets: ['my-app:8080']
Dashboard Grafana - Visualisasi Data
Jalankan stack-nya:
docker compose up -d
Buka http://SERVER_IP:3000, login dengan admin dan password yang tadi kamu set di environment. Langkah pertama: tambah data source.
Menu Configuration -> Data sources -> Add data source -> Prometheus. Isi URL dengan http://prometheus:9090 (nama service di docker-compose, bukan localhost). Klik Save & Test. Kalau hijau, koneksi sukses.
Sekarang bagian paling seru: dashboard. Kamu tidak perlu bikin dari nol. Komunitas Grafana punya ribuan dashboard siap import. Yang paling populer untuk node exporter:
- Buka grafana.com/grafana/dashboards
- Cari dashboard ID 1860 (Node Exporter Full)
- Di Grafana: Dashboards -> Import, masukkan ID 1860, pilih data source Prometheus
- Klik Import
Dalam 10 detik kamu punya dashboard lengkap: CPU, RAM, disk, network, uptime, semuanya. Tinggal sesuaikan kalau mau.
PromQL - Bahasa Query yang Wajib Kamu Tahu
Dashboard import itu keren, tapi kamu bakal butuh query sendiri. PromQL (Prometheus Query Language) itu inti dari semuanya. Beberapa query yang paling sering saya pakai:
Status server hidup atau mati:
up
Hasil 1 berarti target sehat, 0 berarti down. Query ini juga yang paling umum dipakai buat alert.
CPU usage per core dalam 5 menit:
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
RAM terpakai dalam persen:
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
Sisa disk per filesystem:
node_filesystem_avail_bytes{mountpoint="/"} / 1024 / 1024 / 1024
Network traffic:
rate(node_network_receive_bytes_total[5m])
Kalau mau coba-coba query, buka menu Explore di Grafana. Di situ kamu bisa ketik query, lihat hasilnya langsung dalam bentuk grafik, tanpa perlu bikin dashboard dulu. Ini playground-nya.
Alerting - Biar Server yang Lapor, Bukan User
Ini bagian yang paling mengubah cara saya kerja. Dashboard itu pasif - kamu harus buka untuk lihat. Alert itu proaktif - sistem yang datang ke kamu.
Buat file alert.rules.yml:
groups:
- name: server-alerts
rules:
- alert: ServerDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Server {{ $labels.instance }} down"
- alert: DiskHampirPenuh
expr: (1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})) * 100 > 85
for: 5m
labels:
severity: warning
annotations:
summary: "Disk {{ $labels.instance }} terisi {{ $value | humanizePercentage }}"
for: 2m artinya kondisi harus bertahan 2 menit sebelum alert dikirim - biar tidak spam karena spike sesaat. Rules di atas cuma contoh; tambahkan alert untuk RAM, CPU, dan service lain sesuai kebutuhan.
Sekarang konfigurasi Alertmanager alertmanager.yml untuk kirim notifikasi ke Telegram:
route:
receiver: telegram
group_by: ['alertname']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receivers:
- name: telegram
telegram_configs:
- bot_token: 'TOKEN_BOT_TELEGRAM'
chat_id: 123456789
api_url: 'https://api.telegram.org'
Cara dapet bot token: chat ke @BotFather di Telegram, ketik /newbot, ikuti instruksinya. Chat ID bisa kamu dapat dari @userinfobot. Jangan pernah commit token bot ke repository publik.
Test alert-nya: stop salah satu service (docker compose stop node-exporter), tunggu 2 menit, dan notifikasi "ServerDown" harus masuk ke Telegram kamu. Kalau masuk, hidup kamu berubah. Kalau belum, cek docker compose logs alertmanager.
Tips Buat Production
Beberapa hal yang saya pelajari dari pemakaian nyata:
1. Jangan expose Grafana langsung ke internet. Port 3000 itu tanpa proteksi bawaan. Pasang di belakang nginx reverse proxy dengan SSL dan basic auth, atau setidaknya batasi IP. Kalau pakai Cloudflare, aktifkan Access rule.
2. Atur retensi data. Prometheus default menyimpan data 15 hari. Di docker-compose di atas saya set 30 hari via --storage.tsdb.retention.time=30d. Semakin lama retensi, semakin besar disk yang dibutuhkan. Untuk VPS 2GB, 30 hari itu angka yang aman.
3. Monitor disk Prometheus itu sendiri. Ironisnya, Prometheus sering habis disk karena data metriknya sendiri. Pastikan partisi tempat prometheus_data disimpan ikut dimonitor.
4. Jangan scrape terlalu sering. scrape_interval: 5s terdengar keren, tapi untuk VPS kecil itu buang-buang resource. 15s sudah lebih dari cukup untuk kebanyakan kasus.
5. Pakai basic auth di nginx untuk Grafana. Contoh konfigurasi:
location / {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd_grafana;
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
}
Generate password dengan htpasswd -c /etc/nginx/.htpasswd_grafana admin.
Memantau Database dan Aplikasi Lain
Node exporter cuma menutupi metrik server. Database dan aplikasi juga butuh dipantau, dan kabar baiknya: hampir semua tools populer punya exporter sendiri.
Untuk MySQL/MariaDB ada mysqld_exporter. Tambahkan service-nya di docker-compose:
mysqld-exporter:
image: prom/mysqld-exporter:latest
container_name: mysqld-exporter
restart: unless-stopped
environment:
- DATA_SOURCE_NAME=exporter:password@(mysql:3306)/
ports:
- '9104:9104'
Buat user khusus exporter di MySQL dengan permission minimal:
CREATE USER 'exporter'@'%' IDENTIFIED BY 'password';
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'%';
Untuk PostgreSQL ada postgres_exporter, untuk Redis ada redis_exporter, untuk container Docker ada cadvisor. Polanya sama: jalanin exporter, tambahin job di prometheus.yml, refresh data source. Setelah itu kamu bisa bikin alert seperti "koneksi database melebihi 100" atau "query lambat meningkat".
Prinsipnya sekali setup, dan satu dashboard Grafana bisa memantau semua layer sekaligus: server, database, dan aplikasi.
Troubleshooting yang Sering Terjadi
Setup monitoring juga bisa error. Ini tiga masalah yang paling sering saya temui:
1. Grafana bilang "No data" padahal Prometheus punya data. Penyebab paling umum: data source salah, atau query pakai label yang tidak ada. Cek dulu di menu Explore - kalau Explore bisa tampilkan data, berarti query dashboard yang bermasalah, bukan stack-nya.
2. Target merah di halaman Status -> Targets. Artinya Prometheus tidak bisa narik metrik dari target itu. Cek apakah container exporter masih jalan (docker compose ps), dan pastikan nama host di prometheus.yml cocok dengan nama service docker-compose. Ingat: pakai nama service, bukan localhost.
3. Alert tidak pernah masuk Telegram. Cek tiga hal: apakah alert rules ke-load (lihat di menu Alerts Prometheus), apakah Alertmanager bisa dijangkau (menu Status -> Runtime & Build Info), dan apakah bot token benar. Log Alertmanager biasanya langsung menunjukkan errornya.
Kalau stuck, jangan sungkan buka dokumentasi resmi Prometheus dan Grafana - dokumentasinya lengkap banget.
Ceklis Sebelum Go-Live
Biar tidak setengah-setengah, ini ceklis yang saya jalani sebelum mengandalkan monitoring ini di production:
- Semua target hijau di halaman Status -> Targets
- Dashboard import menampilkan data, bukan "No data"
- Alert test terkirim: stop node-exporter, notifikasi ServerDown masuk ke Telegram dalam 2-3 menit
- Alert disk terpicu saat penggunaan di atas 85% (test dengan file dummy kalau perlu)
- Grafana tidak bisa diakses publik tanpa basic auth
- Retensi data sudah diatur sesuai kapasitas disk
- Backup folder
grafana_datadan file konfigurasi (semua cuma file teks, gampang di-commit ke git)
Kalau tujuh poin ini beres, kamu bisa tidur lebih nyenyak. Server yang error bukan lagi rahasia yang baru ketahuan besok pagi - tapi notifikasi yang sudah nunggu di HP kamu.
Kesimpulan
Malam itu disk penuh dan saya baru tahu dari user. Dengan Grafana dan Prometheus, kejadian seperti itu sekarang ketahuan 5 menit setelah terjadi - lengkap dengan grafik tren dan notifikasi Telegram di HP saya. Investasi setup-nya sekitar satu jam sekali, dan efeknya bertahan terus.
Mulai dari yang kecil: pasang node exporter, import dashboard, buat satu alert disk. Nanti tambahin alert RAM, CPU, dan service aplikasi kamu. Jangan langsung bangun semuanya sekaligus - biar tidak overwhelmed.
Kamu sendiri gimana? Pernah kena kejadian server down yang baru ketahuan dari user? Atau sudah pakai stack monitoring tertentu? Cerita di kolom komentar, siapa tahu bisa saling belajar.