MAATRIX / Блог / Grafana Loki на Ubuntu 24.04: пошаговая установка

Grafana Loki на Ubuntu 24.04: пошаговая установка

MAATRIX

Логи сервера обычно живут в трёх местах одновременно: journalctl, файлы в /var/log и вывод docker logs, который исчезает при перезапуске контейнера. Когда что-то падает в три ночи, вы либо помните точный синтаксис journalctl -u myapp --since для каждого юнита, либо теряете десять минут на поиск нужного файла. Loki решает это без лишней сложности: он не индексирует содержимое строк, как Elasticsearch, а только метки — и благодаря этому требует в разы меньше памяти и диска. Ниже — установка Loki и Promtail на Ubuntu 24.04, подключение к Grafana и рабочие запросы LogQL, с которых стоит начать.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Почему Loki, а не ELK

Loki спроектирован Grafana Labs с явной оглядкой на Prometheus: та же модель меток, тот же принцип "индексируем только то, что нужно для поиска, а не весь текст". Это даёт заметно более скромные требования к ресурсам по сравнению с Elasticsearch — Loki хранит сырые логи сжатыми блоками и строит индекс только по меткам (job, host, container и так далее), а не по каждому слову в каждой строке.

Плата за экономию — полнотекстовый поиск внутри Loki работает медленнее, чем в Elasticsearch, особенно на больших объёмах без узких меток. Для сложной full-text аналитики по миллионам строк ELK или OpenSearch справятся лучше. Если же задача — "видеть логи всех сервисов в одном месте, коррелировать их с метриками Prometheus по времени, не тратя на это половину сервера" — Loki для типичного проекта на VPS ощутимо экономнее.

Разница в подходе:

LokiElasticsearch/ELK
Индексациятолько меткиполный текст
Потребление RAMнизкоевысокое
Порог входасинтаксис похож на PromQLсвой DSL, нужен Kibana
Интеграция с Grafanaнативнаячерез плагин
Подходит длялоги + метрики в одном стекесложный полнотекстовый поиск

Если Grafana и Prometheus у вас уже стоят — Loki логически продолжает эту связку, и настроить его быстрее, чем поднимать отдельный ELK-стек.

Требования к серверу

Для небольшого проекта (2–5 сервисов, разумный объём логов) достаточно 2 vCPU и 2–4 ГБ RAM — Loki и Promtail вместе съедают немного, но Grafana и кэш запросов тоже просят память. Для продакшена с десятками сервисов берите 4 ГБ RAM и следите за диском отдельно: логи растут быстрее, чем кажется, особенно в debug-режиме.

Диск — отдельный разговор. Loki хранит сжатые чанки логов локально (или в S3-совместимом хранилище), и без настроенного retention они будут копиться бесконечно. Закладывайте SSD от 40 ГБ на старте и обязательно настройте retention_period, об этом ниже.

Понадобится:

  • Ubuntu 24.04 LTS, root или sudo
  • Docker и Docker Compose (проще всего поднять весь стек контейнерами)
  • Открытые порты: 3000 (Grafana) наружу, 3100 (Loki) — только внутри docker-сети

Если Docker ещё не стоит, сначала разверните его по пошаговой установке для Ubuntu 24.04 — Loki удобнее всего запускать именно в контейнерах, конфиги проще версионировать в git.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Установка Loki и Grafana через Docker Compose

Создаём рабочую директорию и структуру:

mkdir -p /opt/loki-stack/{loki,promtail,grafana}
cd /opt/loki-stack

Конфиг Loki, loki/loki-config.yml — минимальный рабочий вариант для одного сервера (single-binary mode, без кластеризации):

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: 336h
  ingestion_rate_mb: 8
  ingestion_burst_size_mb: 16

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

retention_period: 336h — это 14 дней. Для продакшена подберите под ваши требования: держать логи месяцами локально на VPS обычно бессмысленно и дорого по месту, если только это не требование комплаенса.

Теперь docker-compose.yml:

services:
  loki:
    image: grafana/loki:3.2.0
    container_name: loki
    restart: unless-stopped
    volumes:
      - ./loki/loki-config.yml:/etc/loki/local-config.yaml
      - loki-data:/loki
    command: -config.file=/etc/loki/local-config.yaml
    networks:
      - monitoring

  promtail:
    image: grafana/promtail:3.2.0
    container_name: promtail
    restart: unless-stopped
    volumes:
      - ./promtail/promtail-config.yml:/etc/promtail/config.yml
      - /var/log:/var/log:ro
      - /var/lib/docker/containers:/var/lib/docker/containers:ro
      - /run/log/journal:/run/log/journal:ro
      - /var/log/journal:/var/log/journal:ro
    command: -config.file=/etc/promtail/config.yml
    networks:
      - monitoring
    depends_on:
      - loki

  grafana:
    image: grafana/grafana:11.2.0
    container_name: grafana
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=change-me-now
    networks:
      - monitoring
    depends_on:
      - loki

volumes:
  loki-data:
  grafana-data:

networks:
  monitoring:
    driver: bridge

Версии образов зафиксированы явно — обновляйте их сознательно, а не через latest, чтобы не поймать breaking change в схеме хранения посреди ночи. Пароль Grafana обязательно смените на реальный перед стартом.

Обратите внимание на монтирование /var/lib/docker/containers и путей journal — они нужны Promtail, чтобы читать логи контейнеров и systemd-юнитов напрямую с хоста. Конфиг Promtail собираем следующим шагом.

Сбор логов systemd и Docker через Promtail

Promtail — агент, который читает логи и пушит их в Loki с нужными метками. promtail/promtail-config.yml:

server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
  - url: http://loki:3100/loki/api/v1/push

scrape_configs:
  # systemd journal
  - job_name: journal
    journal:
      max_age: 12h
      labels:
        job: systemd-journal
    relabel_configs:
      - source_labels: ['__journal__systemd_unit']
        target_label: unit
      - source_labels: ['__journal_priority_keyword']
        target_label: level

  # логи Docker-контейнеров
  - job_name: docker
    docker_sd_configs:
      - host: unix:///var/run/docker.sock
        refresh_interval: 5s
    relabel_configs:
      - source_labels: ['__meta_docker_container_name']
        regex: '/(.*)'
        target_label: container

  # обычные текстовые логи из /var/log
  - job_name: syslog
    static_configs:
      - targets:
          - localhost
        labels:
          job: syslog
          __path__: /var/log/syslog

Для job docker нужен доступ к сокету Docker — добавьте в сервис promtail в compose-файле:

    volumes:
      # ...предыдущие volumes...
      - /var/run/docker.sock:/var/run/docker.sock

Ключевой момент по меткам: не создавайте label с высокой кардинальностью — например, не делайте label из user_id или request_id. Loki строит индекс по меткам, и тысячи уникальных значений одной метки распухнут индекс так, что запросы начнут тормозить. Правило простое: метки — для ЧТО и ГДЕ (сервис, хост, уровень), детали события ищите фильтрацией текста внутри самого запроса.

Запускаем стек:

docker compose up -d
docker compose logs -f promtail

В логах Promtail должны появиться записи об успешном подключении к http://loki:3100 и начале tailing файлов — если видите ошибки permission denied на /var/log/journal, добавьте пользователя контейнера в группу systemd-journal или временно смонтируйте с более широкими правами для теста.

Подключение Loki как источника данных в Grafana

Открываем http://<IP-сервера>:3000, логинимся под admin и паролем из GF_SECURITY_ADMIN_PASSWORD. Дальше:

  1. Connections → Data sources → Add data source
  2. Выбираем Loki
  3. URL: http://loki:3100 (имя сервиса из docker-сети, не localhost)
  4. Save & Test — должно появиться зелёное "Data source successfully connected"

Если у вас уже настроена связка Grafana и Prometheus по этой инструкции, Loki добавляется в ту же Grafana вторым источником данных — это и есть основная ценность подхода: метрики и логи в одном интерфейсе, с возможностью кликнуть на всплеск на графике Prometheus и сразу увидеть логи за этот момент.

Проверить, что данные идут, можно через Explore (иконка компаса в левом меню): выбираем Loki, в поле запроса вводим {job="systemd-journal"} и должны увидеть поток строк за последние часы.

LogQL: запросы, с которых стоит начать

LogQL синтаксически похож на PromQL — если вы уже писали запросы для Prometheus, освоитесь быстро. Базовая структура: селектор меток в фигурных скобках, затем опциональные фильтры и функции.

Все логи конкретного systemd-юнита:

{job="systemd-journal", unit="nginx.service"}

Логи Docker-контейнера с фильтром по тексту:

{container="my-app"} |= "error"

Исключить шумные health-check запросы:

{container="my-app"} != "GET /healthz"

Парсинг JSON-логов и фильтр по полю (если приложение логирует структурированно):

{container="my-app"} | json | level="error"

Скорость появления ошибок в секунду за последние 5 минут — это уже метрика, построенная из логов, и её можно вывести на график рядом с метриками Prometheus:

sum(rate({container="my-app"} |= "error" [5m]))

Регулярное выражение для более точного фильтра:

{job="syslog"} |~ "failed login.*root"

Эти пять паттернов покрывают большинство повседневных задач: найти сервис, отфильтровать по тексту, спарсить структурированные поля, построить метрику из частоты событий. Дальше LogQL позволяет комбинировать фильтры и агрегации — но начинать проще с простых селекторов, постепенно усложняя запрос и наблюдая за результатом в Explore.

Дашборд и алерты на основе логов

Готовый дашборд собирается за 10–15 минут из панелей двух типов: Logs (поток строк с фильтром) и Time series (график на основе rate() или count_over_time()). Практичный минимальный набор:

  • панель Logs с запросом {job=~".+"} |= "error" or "panic" or "fatal" — общий поток ошибок по всем сервисам;
  • панель Time series с sum by (unit) (rate({job="systemd-journal", level=~"err|crit"} [5m])) — частота ошибок в разрезе по юнитам;
  • панель Stat с count_over_time({container="my-app"} |= "OOM" [1h]) — счётчик конкретного события за час.

Алерты на логах работают через тот же механизм unified alerting, что и алерты на метриках: создаёте alert rule на основе LogQL-запроса с агрегацией ("если sum(rate(... [5m])) больше 10 — сработать"), задаёте condition и получателя (Telegram, email, webhook). Это удобно для событий, которые сложно поймать метрикой напрямую — например, конкретную фразу ошибки от стороннего API.

Практический совет: не заводите алерт на "любое слово error в логах" — почти в любом стеке найдётся сервис, который пишет error в штатных ситуациях (retry, expected exception). Начните с узких условий и расширяйте по мере того, как понимаете, какой шум реален для вашей системы.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Loki заменяет Prometheus?

Нет, это разные инструменты: Prometheus — метрики (числа во времени), Loki — логи (текстовые события). Обычно их ставят вместе, и Grafana объединяет оба источника в одном дашборде.

Сколько места займут логи за месяц?

Зависит от объёма логирования — единого числа тут нет, точную оценку даст только тест на вашем трафике. Ориентируйтесь по du -sh на volume спустя сутки-двое работы и экстраполируйте, плюс не забывайте про retention_period в конфиге.

Можно ли собирать логи с нескольких серверов в один Loki?

Да, Promtail на каждом сервере отправляет данные в clients.url, указывающий на центральный Loki. Тогда центральный сервер должен принимать входящие на порт 3100 — закройте его firewall-правилами, разрешающими только ваши серверы, см. настройку UFW на Ubuntu 24.04.

Нужен ли обратный прокси перед Grafana?

Для продакшена — да, ради HTTPS и чтобы не светить порт 3000 напрямую. Разверните nginx как reverse proxy с автоматическим SSL по этой инструкции.

Чем Loki отличается от ELK на практике?

Синтаксис запросов другой (LogQL vs Kibana DSL), интерфейс — та же Grafana, что и для метрик, а не отдельная Kibana. Для сложного полнотекстового поиска и агрегаций по произвольным полям ELK гибче; для низкого потребления ресурсов и единого интерфейса с метриками проще Loki.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →