Grafana Loki — Log Aggregation pre Cloud-Native
Loki je horizontálne škálovateľný log aggregation systém od Grafana Labs, inšpirovaný Prometheom. Jeho hlavná myšlienka je jednoduchá — neindexovať obsah logov, ale iba metadáta (labels), a samotné logy ukladať komprimované na objektové úložisko (S3, GCS, Azure Blob, local filesystem).
Dôsledok: prevádzka Loki je rádovo lacnejšia než klasický Elasticsearch/OpenSearch stack, najmä pri veľkom objeme logov. Grafana Labs ho spúšťa na produkcii s desiatkami TB logov denne.
Prečo Loki a nie Elastic?
| Aspekt | Elasticsearch (ELK) | Loki |
|---|---|---|
| Indexovanie | Full-text inverted index nad celým obsahom | Iba labels (metadata), obsah neindexovaný |
| Úložisko | Disk (SSD) v ES klastri | Object storage (S3, GCS, MinIO) |
| Query model | DSL (Query DSL) alebo KQL | LogQL (Prometheus-like) |
| Cena/GB | Vysoká (RAM + SSD + index) | Nízka (lacné object storage) |
| Škálovateľnosť | Komplexná (shards, replicas) | Microservices mód + object storage |
| Typ vyhľadávania | Full-text, rýchle aj na starých dátach | Grep-like nad časovým oknom |
Hlavný kompromis: full-text search nad celou historickou databázou je v Loki pomalý, pretože obsah nie je indexovaný. Preto Loki cielí na use-case, kde sa viete zúžiť pomocou labels (service, pod, namespace, level) a až potom hľadať v obsahu.
Ak v ELK hľadáte error za posledný rok bez žiadneho filtra, dostanete výsledok v sekundách. V Loki toto bude pomalé — ale rovnaká otázka so zúžením {namespace="production",app="api"} je rýchla a desaťkrát lacnejšia.
Architektúra Loki
Loki má dva módy nasadenia:
1. Monolitický (single binary)
Všetky komponenty v jednom binary. Ideálne na laboratórium, lab, malé klastre do ~100 GB/deň.
2. Microservices / SSD (scalable)
Komponenty bežia ako samostatné pody, škálujú sa nezávisle. Produkčný setup.
┌─────────┐
Logs ───► │Distributor│─┐
└─────────┘ │
▼
┌─────────┐
│Ingester │──► Chunks → S3/GCS
└─────────┘
▲
│
┌─────────┐ │
Query ◄── │ Querier │─┘
└─────────┘
▲
┌─────────┐
│Query Fr.│
└─────────┘
- Distributor — prijíma logy cez HTTP (
/loki/api/v1/push), validuje, rozdistribuuje do ingesterov pomocou consistent hashing nad labels. - Ingester — drží logy v pamäti (in-memory chunks), pravidelne ich flushuje ako komprimované chunks na objekt storage.
- Querier — obsluhuje
queryaquery_rangeHTTP endpointy, číta chunks z objektového storage + z ingesterov (pre recent data). - Query Frontend — cacheuje a paralelizuje dotazy, rozdeľuje ich do sub-queries podľa času.
- Compactor — merguje a deduplikuje staré chunks, aplikuje retention policy.
LogQL — query language
LogQL je úmyselne podobný PromQL. Má dve hlavné časti:
1. Log stream selector
Vyberie streamy podľa labels:
{namespace="production", app="api"}
Regex tiež funguje:
{namespace=~"prod-.*", app!="sidecar"}
2. Log pipeline
Filtruje a parsuje riadky streamu. Operátory:
|=— obsahuje reťazec!=— neobsahuje|~— regex match!~— regex no-match| json— parsuje JSON logy| logfmt— parsuje logfmt (key=value)| pattern— custom pattern parser
Príklady:
# Error logy z API v produkcii
{namespace="production", app="api"} |= "error"
# 5xx HTTP chyby z nginx
{app="nginx"} | json | status >= 500
# Latencia nad 1s
{app="api"} | logfmt | latency > 1s
# Extrakcia user_id z pattern logu
{app="auth"} | pattern `<_> user_id=<user> <_>` | user="42"
3. Metric queries
LogQL umožňuje robiť metriky zo samotných logov (čo ELK samostatne neponúka):
# Počet errorov za minútu
sum(rate({app="api"} |= "error" [1m])) by (pod)
# 95. percentil latencie
quantile_over_time(0.95,
{app="api"} | logfmt | unwrap latency [5m]
)
Výstup je časová rada, takže sa dá použiť priamo v Grafana dashboardoch a Alertmanager alerts bez nutnosti mať Prometheus metriky pre tieto hodnoty.
Log shippers — ako dostať logy do Loki
Promtail
Klasický agent od Grafana Labs. Beží ako DaemonSet v Kubernetes, číta /var/log/pods/*, enrichuje labels z K8s API:
server:
http_listen_port: 9080
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: kubernetes-pods
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
target_label: app
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
pipeline_stages:
- docker: {}
- match:
selector: '{app="api"}'
stages:
- json:
expressions:
level: level
msg: message
- labels:
level:
Grafana Alloy (budúcnosť)
Grafana Alloy je nový unified agent, ktorý nahrádza Promtail aj Grafana Agent. Podporuje Loki push, OTLP, Prometheus scrape, Pyroscope a ďalšie, všetko cez jednotný konfiguračný jazyk River. Grafana odporúča nové deploye postaviť už nad Alloy.
OpenTelemetry Collector
OTel Collector má natívny loki exporter:
exporters:
loki:
endpoint: http://loki:3100/loki/api/v1/push
labels:
resource:
service.name: "service_name"
k8s.namespace.name: "namespace"
Praktický príklad — docker-compose demo
Minimálny stack s Loki, Promtail a Grafana:
services:
loki:
image: grafana/loki:3.1.0
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
promtail:
image: grafana/promtail:3.1.0
volumes:
- /var/log:/var/log:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yaml:/etc/promtail/config.yaml
command: -config.file=/etc/promtail/config.yaml
grafana:
image: grafana/grafana:11.2.0
ports:
- "3000:3000"
environment:
- GF_AUTH_ANONYMOUS_ENABLED=true
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
Po docker compose up otvoríte Grafana na localhost:3000, pridáte Loki data source (http://loki:3100) a v Explore viete skúšať LogQL.
Integrácia s Alertmanagerom
LogQL metric query môže byť zdrojom alertu — Loki beží s ruler komponentom, ktorý periodicky vyhodnocuje pravidlá a posiela alerty do Alertmanagera (Prometheus alebo vlastný Loki ruler):
groups:
- name: api-errors
rules:
- alert: HighErrorRate
expr: |
sum(rate({app="api"} |= "error" [5m])) > 5
for: 2m
labels:
severity: warning
annotations:
summary: "High error rate v API"
Produkčné tipy
- Label cardinality — nikdy nedávajte high-cardinality veci ako
user_id,trace_iddo labels. Tie patria do log line. Každá unikátna kombinácia labels = nový stream. - Retention — nastavte
retention_perioda compactor povinne zapnite, inak staré chunks zostávajú v object storage. - Chunk size — default
max_chunk_age: 2h,chunk_target_size: 1.5MB. Väčšie chunky = lepšia kompresia ale pomalšie queries. - Limits — nastavte
ingestion_rate_mb,max_streams_per_user, inak jeden misbehaved tenant môže zabiť klaster. - Multi-tenancy — Loki podporuje
X-Scope-OrgIDheader, vďaka čomu viete zdieľať jeden klaster medzi tímami. - S3 lifecycle policies — po expirácii chunks si nechajte S3 upratať, compactor iba maže pointery.
Loki vs existujúci ELK článok
Ak už máte ELK stack v KB a zvažujete Loki, neznamená to výber buď-alebo. Typický moderný setup:
- Loki — primárny log pipeline pre všetky služby (lacný, label-based).
- Elastic — iba pre špecifické security/audit logy, kde potrebujete full-text search nad celou históriou.
Najčastejší postup je postupná migrácia aplikačných logov do Loki a ponechanie Elastic len na niečo, čo ho naozaj vyžaduje (SIEM).
Zhrnutie
Loki je pragmatická alternatíva k Elastic pre log aggregation v prostredí, kde náklady a Kubernetes-native škálovanie rozhodujú. Nie je to drop-in replacement — stratíte full-text search nad neobmedzenou históriou — ale získate rádovo lacnejší a jednoduchší systém, ktorý sa zapája do Grafana LGTM stacku (Loki, Grafana, Tempo, Mimir) rovnakým dotazovacím štýlom ako Prometheus.
Pre väčšinu cloud-native prostredí je to dnes default voľba.