· 17 мин чтения

Grafana Loki: лёгкое централизованное логирование без Elasticsearch

Grafana Loki: лёгкое централизованное логирование без Elasticsearch

Привет! Меня зовут Семёнов Евгений Сергеевич, я руковожу ITFresh. На нашей практике, когда объём логов у клиента не зашкаливает — до 50–100 ГБ в день, и не нужен сложный полнотекстовый поиск типа «найди всё по этому слову», мы почти всегда выбираем Loki. Почему? Да потому что ресурсов он ест в разы меньше, а администрировать его — одно удовольствие: всего один бинарник и S3. Где это всё крутится? На наших мощных серверах Dell Xeon Platinum 8280 в дата-центре МТС Москва Loki спокойно обрабатывает логи десятка клиентских инфраструктур. Готовы узнать, как мы его ставим и используем?

Зачем Loki, если есть ELK

Конечно, есть и минусы. Полнотекстовый поиск здесь медленнее. Если речь идёт о security-форензике по терабайтам данных, то тут Elastic пока удобнее, спору нет.

Архитектура

КомпонентФункция
Promtail / Grafana AgentАгент на источнике, читает файлы/Event Log
LokiПриём, хранение, запросы
GrafanaUI, дашборды, алерты
MinIO / S3Хранилище чанков и индекса (для scale)

Для небольших проектов — когда мы говорим о single-binary mode — всё крутится на одной машине, используя локальную файловую систему. Если же нужно масштабирование, то тут в дело вступает microservices mode, где компоненты вроде distributor, ingester, querier и compactor уже разносятся.

Установка Loki (single-binary)

# Docker Compose
services:
  loki:
    image: grafana/loki:3.1.0
    ports: ["3100:3100"]
    restart: unless-stopped
    volumes:
      - ./loki-config.yaml:/etc/loki/local-config.yaml
      - loki-data:/loki
    command: -config.file=/etc/loki/local-config.yaml

  grafana:
    image: grafana/grafana:11.1.0
    ports: ["3000:3000"]
    restart: unless-stopped
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      GF_AUTH_ANONYMOUS_ENABLED: "false"

volumes:
  loki-data:
  grafana-data:

Минимальный loki-config.yaml:

auth_enabled: false

server:
  http_listen_port: 3100

common:
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore: { store: inmemory }

schema_config:
  configs:
    - from: 2024-01-01
      store: tsdb
      object_store: filesystem
      schema: v13
      index: { prefix: index_, period: 24h }

limits_config:
  retention_period: 720h
  max_query_length: 720h

compactor:
  working_directory: /loki/compactor
  retention_enabled: true
  delete_request_store: filesystem

Promtail: агент на Linux-сервере

server:
  http_listen_port: 9080

positions:
  filename: /tmp/positions.yaml

clients:
  - url: https://loki.company.ru/loki/api/v1/push
    basic_auth: { username: "promtail", password: "${LOKI_PASS}" }

scrape_configs:
  - job_name: system
    static_configs:
      - targets: [localhost]
        labels:
          job: varlogs
          host: web-01
          __path__: /var/log/*.log

  - job_name: nginx
    static_configs:
      - targets: [localhost]
        labels:
          job: nginx
          env: prod
          __path__: /var/log/nginx/*.log
    pipeline_stages:
      - regex:
          expression: '^(?P[^ ]+) .*? "(?PGET|POST|PUT|DELETE) (?P[^ ]+) HTTP/\d\.\d" (?P\d+)'
      - labels:
          method:
          status:

LogQL: поиск и агрегация

Синтаксис напоминает PromQL. Примеры:

{job="nginx"} |= "500"

# Только GET с кодом 5xx за последний час
{job="nginx", method="GET"} |~ " 5\\d\\d "

# Счётчик ошибок по сервисам
sum by (service) (
  count_over_time({env="prod"} |= "ERROR" [5m])
)

# Топ-5 URL с 4xx
topk(5,
  sum by (path) (count_over_time({job="nginx"} |~ " 4\\d\\d " [1h]))
)

Оператор |= — содержит подстроку, |~ — регулярка, != — не содержит, !~ — не матчит regex. | json — парсит JSON-поля на лету.

Дашборды и алерты в Grafana

Подключение Loki как источника — Configuration → Data Sources → Loki → URL http://loki:3100. В дашбордах используем LogQL-запросы, визуализация — Logs, Stat, Time series (с sum_over_time).

Алерты создаются через Grafana Alerting:

# Пример правила — более 10 ошибок за 5 минут
expr: |
  sum(count_over_time({service="api", env="prod"} |= "ERROR" [5m])) > 10
for: 2m
labels:
  severity: warning
annotations:
  summary: "Много ошибок в API"

Масштабирование: когда single-node мало

Single-node конфигурация справляется примерно со 100 ГБ логов в день и 1 ТБ хранилища. Если объёмы растут, есть только один путь — microservices mode.

Для работы в microservices mode нам, конечно, понадобится S3 или MinIO. Мы в ITFresh используем MinIO на наших серверах Dell Xeon Platinum 8280 с NVMe-дисками. Это даёт нам внушительные 40 Гбит/с пропускной способности. Отлично, правда?

Реальный кейс: логирование для интернет-магазина

В 2024 году к нам обратился один клиент — крупный онлайн-магазин детских товаров. У них была приличная инфраструктура: 18 серверов, из которых 10 веб-бэкендов, 3 базы данных, плюс DNS, почта и CDN-кешпулы. До нас ELK им настраивали уже дважды разные подрядчики. И что? Три ноды Elasticsearch постоянно захлёбывались, приходилось буквально каждый месяц перетряхивать конфиги. Мы решили проблему кардинально: заменили всё на Loki в режиме single-node, развернув его на обычной виртуалке с 8 vCPU, 16 ГБ ОЗУ и 1 ТБ NVMe.

Представьте: всего за четыре рабочих дня наша команда провела огромную работу! Мы установили Loki и Promtail на все 18 источников, тонко настроили парсинг логов nginx (как access, так и error), подключили все Docker-контейнеры через docker driver и, конечно, импортировали готовые дашборды. Итоговая стоимость проекта? Всего 58 000 рублей. В результате, клиент получил не просто быстрый поиск по логам за целых 90 дней и удобные алерты прямо в Telegram. Главное — это фантастическая экономия ресурсов: в 5 раз меньше затрат, чем с ELK!

Грабли Loki

Поставим логирование, которое не съедает ресурсы

У нас на практике Loki для клиентов с объёмом 1–200 ГБ логов/день. 15+ лет опыта в Linux-инфраструктуре, 8 серверов Dell Xeon Platinum 8280 с 40G Mellanox в дата-центре МТС Москва. Проектирование архитектуры, установка, парсеры, дашборды, алерты — под ключ.

Телефон: +7 903 729-62-41
Telegram: @ITfresh_Boss
Семёнов Евгений Сергеевич, директор АйТи Фреш

FAQ — Grafana Loki

Чем Loki лучше ELK?
Loki индексирует только лейблы, а не содержимое логов — это раз в 10 экономит место и CPU. Проще в эксплуатации: один бинарь + S3 хранилище. Но полнотекстовый поиск медленнее, чем в Elasticsearch.
Сколько ресурсов нужно Loki для 50 ГБ логов в день?
Single-node: 4 vCPU, 8 ГБ ОЗУ, 500 ГБ диск (или S3). Масштабируемая схема (distributor/ingester/querier) оправдана от 500 ГБ/день. На NVMe ingester работает быстрее.
Можно ли собирать Windows Event Logs в Loki?
Да, через Grafana Agent или Promtail с виндовым экспортером wevtutil/windows_exporter. Поля Event Log преобразуются в лейблы и сообщение. Поиск по EventID удобен через LogQL.
Как ограничить ретенцию в Loki?
В config.yaml: limits_config.retention_period = 720h (30 дней), плюс compactor с retention_enabled=true. Можно задавать ретенцию по лейблам: разные длительности для security/app/debug.
Что такое высокая кардинальность в Loki?
Loki хранит индекс по уникальным комбинациям лейблов. Лейбл с высокой кардинальностью (user_id, request_id) создаёт миллионы стримов и убивает производительность. Такие значения должны быть в сообщении, а не в лейблах.

Подпишитесь на рассылку ITfresh

Каждую неделю мы выпускаем практические гайды, заточенные под руководителей IT и системных администраторов. Что внутри? Самое ценное: от безопасности и тонкостей работы с 1С до сложных миграций, резервных копий и, конечно, настоящих лайфхаков из наших реальных проектов.

Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.