Episode ini mengubah teori menjadi praktik: menjalankan Grafana, Loki, Tempo, dan Mimir beserta OpenTelemetry Collector dan Grafana Alloy dengan Docker Compose. Kalian juga menghubungkan data source dan mengirim telemetry pertama dari aplikasi sample.

Teori sudah cukup. Mulai episode ini, kalian akan membangun LGTM Stack lokal yang benar-benar berjalan — Grafana, Loki, Tempo, dan Mimir, ditambah OpenTelemetry Collector dan Grafana Alloy sebagai collector telemetry. Semua dijalankan lewat Docker Compose agar mudah diulang dan dihancurkan.
Episode ini adalah fondasi praktis untuk hampir semua episode berikutnya. Setelah selesai, kalian akan memiliki environment observability lengkap di localhost, terhubung sebagai data source di Grafana, dan mengirim telemetry pertama dari aplikasi sample. Pastikan Docker berjalan sebelum memulai.
Buat direktori project dan file compose.yaml. Susunan komponen:
mkdir -p lgtm-stack
cd lgtm-stackPerintah cd lgtm-stack membawa kalian ke direktori kerja utama; semua file konfigurasi dibuat di sini.
services:
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
loki:
image: grafana/loki:latest
ports:
- "3100:3100"
tempo:
image: grafana/tempo:latest
ports:
- "3200:3200"
- "4317:4317"
mimir:
image: grafana/mimir:latest
command: ["-config.file=/etc/mimir.yaml"]
ports:
- "9009:9009"
otel-collector:
image: otel/opentelemetry-collector-contrib:latest
ports:
- "4317:4317"
- "4318:4318"
alloy:
image: grafana/alloy:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /var/lib/docker/containers:/var/lib/docker/containers
- ./config.alloy:/etc/alloy/config.alloy
volumes:
grafana-data:Catatan penting: volumes: di bagian bawah mendefinisikan volume bernama untuk menyimpan data Grafana. Sementara Mimir butuh file konfigurasi, jadi siapkan mimir.yaml sederhana yang menyalakan mode single-binary.
target: all
multitenancy_enabled: false
blocks_storage:
backend: filesystem
filesystem:
dir: /data/blocksKonfigurasi di atas menonaktifkan multi-tenancy agar lokal lebih sederhana dan menyimpan blok data ke filesystem. Konsep target: all berarti satu proses menjalankan seluruh komponen Mimir sekaligus — kalian akan belajar memecahnya di episode 22.
Grafana menyediakan mekanisme provisioning agar data source tersedia otomatis:
apiVersion: 1
datasources:
- name: Mimir
type: prometheus
url: http://mimir:9009/prometheus
access: proxy
- name: Loki
type: loki
url: http://loki:3100
access: proxy
- name: Tempo
type: tempo
url: http://tempo:3200
access: proxyNama data source Mimir, Loki, dan Tempo dipakai sebagai referensi di episode berikutnya. Mimir diekspos sebagai type: prometheus karena kompatibel dengan Prometheus.
Jalankan seluruh stack dan tunggu container sehat:
docker compose up -d
docker compose psPastikan semua service dalam status Up. Lalu verifikasi kesehatan tiap backend lewat API:
curl -s http://localhost:3000/api/health
curl -s http://localhost:3100/ready
curl -s http://localhost:3200/ready
curl -s "http://localhost:9009/ready"Jika curl -s http://localhost:3100/ready mengembalikan ready, Loki siap menerima log. Lakukan hal yang sama untuk tiga endpoint lain.
Buka http://localhost:3000, login dengan admin / admin, lalu buka menu Connections → Data sources. Kalian akan melihat Mimir, Loki, dan Tempo sudah terdaftar. Jika belum, periksa kembali provisioning dan jalankan docker compose restart grafana.
Tip
Gunakan nama service Docker sebagai hostname saat menghubungkan antar container, misalnya http://mimir:9009. Nama ini hanya valid di dalam network Compose, sedangkan dari host gunakan localhost.
Untuk mengirim telemetry pertama, buat aplikasi Python kecil yang mengekspor trace lewat OTLP ke Collector:
from opentelemetry import trace
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
provider = TracerProvider(resource=Resource.create({"service.name": "checkout"}))
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint="http://localhost:4317")))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer("checkout")
with tracer.start_as_current_span("checkout.process"):
passpip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-grpc
python3 app.pyJalankan aplikasi beberapa kali, lalu buka Grafana → Explore, pilih data source Tempo, dan kalian akan menemukan trace bernama checkout.process. Inilah telemetry pertama yang berhasil mengalir: aplikasi → OTLP → Collector → Tempo → Grafana.
Di episode 4 ini kalian berhasil membangun environment LGTM Stack lengkap di lokal: menjalankan enam container dengan Docker Compose, mengonfigurasi Mimir single-binary, menghubungkan data source Grafana lewat provisioning, memverifikasi kesehatan backend, dan mengirim trace pertama dari aplikasi sample.
Inti yang harus dibawa pulang:
Di episode 5 selanjutnya kita akan membahas Grafana fundamentals — arsitektur server dan plugin, navigasi UI, pembuatan dashboard dan panel pertama, variabel dan templating, hingga perbedaan query editor PromQL, LogQL, dan TraceQL. Environment kalian sudah hidup, jadi mari kita pelajari cara membacanya dengan benar.