Loki и LogQL: логи без накладных расходов Elasticsearch

Published: 2026-03-21

Loki индексирует только метки логов, а не их содержимое. Это делает его существенно дешевле Elasticsearch — в 10 раз меньше диска, минимальный CPU при приёме. Компромисс: полнотекстовый поиск медленнее (regex-сканирование строк, а не инвертированный индекс). Для большинства задач — поиска ошибок, трассировки запросов, отладки — LogQL достаточно быстр, а экономия реальна.


Установка через Helm

yamlapiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
  name: loki
  namespace: observability
spec:
  chart:
    spec:
      chart: loki
      version: "6.x"
      sourceRef:
        kind: HelmRepository
        name: grafana
  values:
    deploymentMode: SingleBinary
    loki:
      commonConfig:
        replication_factor: 1
      storage:
        type: filesystem
      auth_enabled: false
      limits_config:
        retention_period: 30d
        ingestion_rate_mb: 16
        ingestion_burst_size_mb: 32
    singleBinary:
      replicas: 1
      persistence:
        enabled: true
        storageClass: local-path
        size: 50Gi
    monitoring:
      serviceMonitor:
        enabled: true
        labels:
          release: kube-prom-stack

SingleBinary запускает все компоненты в одном поде. Для HA — SimpleScalable или Distributed с объектным хранилищем.


Grafana Alloy (замена Promtail)

Promtail устарел, его заменяет Grafana Alloy. Alloy отправляет логи в Loki, метрики в Prometheus и трейсы в Tempo:

yamlvalues:
  alloy:
    configMap:
      content: |
        discovery.kubernetes "pods" {
          role = "pod"
        }

        discovery.relabel "pods" {
          targets = discovery.kubernetes.pods.targets
          rule {
            source_labels = ["__meta_kubernetes_namespace"]
            target_label  = "namespace"
          }
          rule {
            source_labels = ["__meta_kubernetes_pod_label_app"]
            target_label  = "app"
          }
        }

        loki.source.kubernetes "pods" {
          targets    = discovery.relabel.pods.output
          forward_to = [loki.write.default.receiver]
        }

        loki.write "default" {
          endpoint {
            url = "http://loki.observability.svc.cluster.local:3100/loki/api/v1/push"
          }
        }

Основы LogQL

Stream selectors:

logql{namespace="app", app="my-service"}
{namespace="app"} |= "ERROR"
{namespace="app"} |~ "timeout|refused"
{namespace="app"} != "healthz"
  • |= строка содержит подстроку
  • |~ строка совпадает с regex
  • != строка не содержит подстроку
  • !~ строка не совпадает с regex

Парсинг JSON:

logql{namespace="app", app="my-service"}
  | json
  | level="error"
  | line_format "{{.message}}"

| json парсит строку как JSON и извлекает поля. Фильтр | level="error" применяется к извлечённому полю.

Rate-запросы для Grafana:

logqlrate({namespace="app"} |= "ERROR" [5m])

Количество ошибок по сервисам:

logqlsum by (app) (
  rate({namespace="app"} |= "ERROR" [5m])
)

Datasource в Grafana

yamladditionalDataSources:
  - name: Loki
    type: loki
    url: http://loki.observability.svc.cluster.local:3100
    jsonData:
      derivedFields:
        - name: TraceID
          matcherRegex: '"traceId":"(\w+)"'
          url: "${__value.raw}"
          datasourceUid: jaeger

derivedFields превращает trace ID в кликабельную ссылку, открывающую трейс в Jaeger.


Loki vs Elasticsearch

Возможность Loki Elasticsearch
Стоимость хранилища Низкая (индекс только меток) Высокая (полный инвертированный индекс)
CPU при приёме Минимальный Значительный
Полнотекстовый поиск Regex-сканирование (медленнее) Инвертированный индекс (быстро)
Фильтрация по полям Через JSON-парсер Встроенная
Интеграция Grafana Kibana

Диагностика

Too many streams: избегайте меток с высокой кардинальностью (имя пода, request ID). Ограничьтесь метками namespace, app, job, level.

Превышен лимит приёма: увеличьте ingestion_rate_mb в limits_config.

Таймаут запросов: добавьте |= "search term" перед парсингом — быстрая фильтрация по меткам сочетается с фильтром по содержимому, который сужает выборку.