Введение в Loki
Grafana Loki — это система агрегации логов, разработанная специально для работы с метриками и логами в экосистеме Grafana. В отличие от традиционных систем логирования (ELK Stack), Loki не индексирует содержимое логов, а только метки (labels), что делает его значительно легче и быстрее.
Ключевые особенности Loki:
- ✅ Легковесность — потребляет в 10-100 раз меньше ресурсов, чем ELK
- ✅ Интеграция с Grafana — единый интерфейс для логов и метрик
- ✅ Простота — минимальная конфигурация
- ✅ Масштабируемость — горизонтальное масштабирование
- ✅ Экономичность — низкие требования к ресурсам
Когда использовать Loki:
- Сбор логов из Docker контейнеров
- Централизованное логирование микросервисов
- Интеграция с существующим стеком мониторинга Grafana
- Необходимость быстрого поиска по логам
- Ограниченные ресурсы сервера
Почему Loki для Docker?
Проблемы традиционного логирования Docker:
- Разрозненные логи — каждый контейнер пишет в свой файл
- Сложный поиск — нужно знать, на какой ноде находится контейнер
- Высокое потребление ресурсов — ELK Stack требует много памяти
- Сложная настройка — множество компонентов для конфигурации
Преимущества Loki для Docker:
- ✅ Автоматический сбор — Promtail собирает логи всех контейнеров
- ✅ Единый интерфейс — все логи в одном месте (Grafana)
- ✅ Низкое потребление ресурсов — ~100-200MB RAM для небольших установок
- ✅ Простая интеграция — работает «из коробки» с Docker
Архитектура Loki + Docker
┌─────────────────────────────────────────────────────────────┐
│ DOCKER CONTAINERS │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Bot 1 │ │ Bot 2 │ │ Bot N │ │
│ │ (stdout) │ │ (stdout) │ │ (stdout) │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └────────────┴──────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ Docker Logs │ │
│ │ (/var/lib/docker/ │ │
│ │ containers/) │ │
│ └───────────┬────────────┘ │
└───────────────────┼────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ PROMTAIL (Log Shipper) │
│ • Собирает логи из Docker │
│ • Добавляет метки (labels) │
│ • Отправляет в Loki │
└───────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ LOKI (Log Aggregator) │
│ • Хранит логи │
│ • Индексирует по меткам │
│ • Предоставляет API для запросов │
└───────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ GRAFANA (Visualization) │
│ • Отображение логов │
│ • Поиск и фильтрация │
│ • Интеграция с метриками │
└─────────────────────────────────────────────────────────────┘
Установка и настройка
Шаг 1: Docker Compose конфигурация
Создайте файл docker-compose.loki.yml:
version: '3.8'
services:
# Loki - агрегатор логов
loki:
image: grafana/loki:latest
container_name: loki
ports:
- "3100:3100"
command: -config.file=/etc/loki/local-config.yaml
volumes:
- loki-data:/loki
- ./loki-config.yml:/etc/loki/local-config.yaml:ro
networks:
- monitoring
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3100/ready"]
interval: 10s
timeout: 5s
retries: 3
# Promtail - сборщик логов
promtail:
image: grafana/promtail:latest
container_name: promtail
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- /var/lib/docker/containers:/var/lib/docker/containers:ro
- ./promtail-config.yml:/etc/promtail/config.yml:ro
command: -config.file=/etc/promtail/config.yml
networks:
- monitoring
restart: unless-stopped
depends_on:
- loki
# Grafana - визуализация
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana-data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning:ro
networks:
- monitoring
restart: unless-stopped
depends_on:
- loki
volumes:
loki-data:
driver: local
grafana-data:
driver: local
networks:
monitoring:
driver: bridge
Шаг 2: Конфигурация Loki
Создайте файл loki-config.yml:
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
instance_addr: 127.0.0.1
kvstore:
store: inmemory
schema_config:
configs:
- from: 2020-10-24
store: boltdb-shipper
object_store: filesystem
schema: v11
index:
prefix: index_
period: 24h
ruler:
alertmanager_url: http://localhost:9093
# Ограничения для оптимизации
limits_config:
reject_old_samples: true
reject_old_samples_max_age: 168h # 7 дней
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
max_query_length: 721h
max_query_parallelism: 32
max_streams_per_user: 10000
max_line_size: 256KB
Шаг 3: Конфигурация 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:
# Сбор логов из Docker контейнеров
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
filters:
- name: status
values: ["running"]
relabel_configs:
# Имя контейнера
- source_labels: ['__meta_docker_container_name']
regex: '/(.*)'
target_label: 'container_name'
# ID контейнера
- source_labels: ['__meta_docker_container_id']
target_label: 'container_id'
# Образ контейнера
- source_labels: ['__meta_docker_container_label_com_docker_compose_service']
target_label: 'service'
# Проект Docker Compose
- source_labels: ['__meta_docker_container_label_com_docker_compose_project']
target_label: 'project'
# Имя образа
- source_labels: ['__meta_docker_container_label_com_docker_compose_image']
target_label: 'image'
# Путь к логам
- source_labels: ['__meta_docker_container_log_path']
target_label: 'log_path'
replacement: '/var/lib/docker/containers/*/${__meta_docker_container_id}*.log'
# Job name
- target_label: 'job'
replacement: 'docker'
pipeline_stages:
# Парсинг JSON логов (если приложение пишет JSON)
- json:
expressions:
output: log
stream: stream
attrs: attrs
# Извлечение timestamp
- timestamp:
source: time
format: RFC3339Nano
# Добавление меток из JSON
- labels:
stream:
level:
service:
# Вывод лога
- output:
source: output
Шаг 4: Запуск
# Запустить стек Loki
docker-compose -f docker-compose.loki.yml up -d
# Проверить статус
docker-compose -f docker-compose.loki.yml ps
# Просмотр логов
docker-compose -f docker-compose.loki.yml logs -f loki
Сбор логов с Docker контейнеров
Автоматический сбор
Promtail автоматически обнаруживает все запущенные Docker контейнеры и собирает их логи. Никакой дополнительной настройки не требуется!
Метки (Labels) в Loki
Loki использует метки для индексации логов. Основные метки:
container_name— имя контейнераcontainer_id— ID контейнераservice— сервис из Docker Composeproject— проект Docker Composeimage— образ контейнераstream— stdout или stderr
Пример запроса в Grafana
{container_name="bot-1"} |= "error"
Этот запрос найдет все логи контейнера bot-1, содержащие слово «error».
Интеграция с Grafana
Шаг 1: Добавление Loki как источника данных
- Откройте Grafana:
http://localhost:3000 - Войдите (admin/admin)
- Перейдите в Configuration → Data Sources
- Нажмите Add data source
- Выберите Loki
- Укажите URL:
http://loki:3100 - Нажмите Save & Test
Шаг 2: Создание дашборда
Создайте новый дашборд и добавьте панель с логами:
Query:
{container_name=~".+"} |= "error" | json
Visualization: Logs
Шаг 3: Полезные запросы LogQL
Поиск ошибок в конкретном контейнере:
{container_name="my-bot"} |= "error"
Поиск по уровню логирования:
{container_name="my-bot"} | json | level="ERROR"
Поиск за последний час:
{container_name="my-bot"} |= "error" [1h]
Подсчет ошибок:
sum(count_over_time({container_name="my-bot"} |= "error" [5m]))
Топ контейнеров по количеству логов:
topk(10, sum by (container_name) (count_over_time({container_name=~".+"}[5m])))
Продвинутые настройки
Фильтрация логов
Исключите ненужные контейнеры из сбора:
# promtail-config.yml
scrape_configs:
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
filters:
- name: status
values: ["running"]
# Исключить системные контейнеры
- name: label
values: ["com.docker.compose.service!=loki", "com.docker.compose.service!=promtail"]
Парсинг структурированных логов
Если ваше приложение пишет JSON логи:
pipeline_stages:
- json:
expressions:
level: level
message: message
timestamp: timestamp
user_id: user_id
- labels:
level:
user_id:
- timestamp:
source: timestamp
format: RFC3339
Мультистрочная обработка
Для логов, которые занимают несколько строк:
pipeline_stages:
- multiline:
firstline: '^\d{4}-\d{2}-\d{2}'
max_wait_time: 3s
Мониторинг и алерты
Метрики Loki
Loki предоставляет метрики Prometheus:
loki_distributor_lines_received_total— количество полученных строкloki_ingester_chunks_created_total— количество созданных чанковloki_ingester_chunks_stored_bytes_total— размер хранимых данныхloki_request_duration_seconds— время обработки запросов
Создание алертов в Grafana
Алерт: слишком много ошибок
# Alert rule
- alert: HighErrorRate
expr: |
sum(rate({container_name=~".+"} |= "error" [5m])) > 10
for: 5m
annotations:
summary: "Высокий уровень ошибок в логах"
description: "Обнаружено {{ $value }} ошибок в секунду"
Дашборд для мониторинга Loki
Создайте дашборд с метриками:
- RPS (Requests Per Second) — количество запросов к Loki
- Ingestion Rate — скорость приема логов
- Storage Usage — использование хранилища
- Query Performance — производительность запросов
Оптимизация производительности
Ограничение объема логов
# loki-config.yml
limits_config:
# Максимальный размер строки
max_line_size: 256KB
# Максимальное количество потоков на пользователя
max_streams_per_user: 10000
# Максимальный возраст логов
reject_old_samples_max_age: 168h # 7 дней
# Лимит скорости приема
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
Retention политика
Автоматическое удаление старых логов:
# loki-config.yml
compactor:
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
Оптимизация запросов
Используйте метки для фильтрации:
❌ Плохо:
{container_name=~".+"} |= "error" | json | user_id="123"
✅ Хорошо:
{container_name="my-bot", user_id="123"} |= "error"
Сжатие данных
Включите сжатие для экономии места:
# promtail-config.yml
clients:
- url: http://loki:3100/loki/api/v1/push
headers:
Content-Type: application/json
tenant_id: "1"
# Сжатие
compression: gzip
Решение проблем
Loki не принимает логи
Проблема: Promtail не может отправить логи в Loki
Решение:
# Проверить доступность Loki
curl http://localhost:3100/ready
# Проверить логи Promtail
docker logs promtail
# Проверить конфигурацию
docker exec promtail promtail -config.file=/etc/promtail/config.yml -dry-run
Высокое потребление памяти
Проблема: Loki потребляет много памяти
Решение:
# Уменьшить retention
limits_config:
reject_old_samples_max_age: 24h # 1 день вместо 7
# Ограничить количество потоков
limits_config:
max_streams_per_user: 1000
Медленные запросы
Проблема: Запросы в Grafana выполняются медленно
Решение:
- Используйте метки для фильтрации
- Ограничьте временной диапазон запроса
- Используйте
topk()для агрегации
Пропуск логов
Проблема: Некоторые логи не попадают в Loki
Решение:
# Увеличить буфер Promtail
clients:
- url: http://loki:3100/loki/api/v1/push
batch_wait: 1s
batch_size: 1048576 # 1MB
timeout: 10s
Лучшие практики
1. Структурированное логирование
Используйте JSON формат для логов:
import json
import logging
class JSONFormatter(logging.Formatter):
def format(self, record):
log_data = {
'timestamp': self.formatTime(record),
'level': record.levelname,
'message': record.getMessage(),
'module': record.module,
'function': record.funcName,
}
return json.dumps(log_data)
logger = logging.getLogger()
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
2. Правильные метки
Используйте метки для важных атрибутов:
✅ Хорошо:
container_nameserviceenvironment(dev, staging, prod)level(ERROR, WARN, INFO)
❌ Плохо:
user_id(слишком много уникальных значений)request_id(слишком много уникальных значений)message(содержимое лога)
3. Retention политика
Настройте автоматическое удаление старых логов:
# Удалять логи старше 7 дней
compactor:
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
4. Мониторинг Loki
Следите за метриками Loki:
- Использование памяти
- Скорость приема логов
- Производительность запросов
- Размер хранилища
5. Безопасность
В продакшене:
- Включите аутентификацию
- Используйте TLS для соединений
- Ограничьте доступ к API
- Настройте rate limiting
Практический пример: Логирование Docker ботов
Конфигурация для хостинга ботов
# docker-compose.yml
version: '3.8'
services:
bot-1:
image: my-bot:latest
container_name: bot-1
environment:
- LOG_FORMAT=json
- LOG_LEVEL=INFO
labels:
- "logging=promtail"
- "service=bot"
- "environment=production"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
bot-2:
image: my-bot-2:latest
container_name: bot-2
environment:
- LOG_FORMAT=json
- LOG_LEVEL=INFO
labels:
- "logging=promtail"
- "service=bot"
- "environment=production"
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Promtail конфигурация для ботов
scrape_configs:
- job_name: bots
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
filters:
- name: label
values: ["logging=promtail"]
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/(.*)'
target_label: 'bot_name'
- source_labels: ['__meta_docker_container_label_environment']
target_label: 'environment'
- source_labels: ['__meta_docker_container_label_service']
target_label: 'service'
pipeline_stages:
- json:
expressions:
level: level
message: message
timestamp: timestamp
user_id: user_id
bot_id: bot_id
- labels:
level:
bot_id:
environment:
- timestamp:
source: timestamp
format: RFC3339
Запросы для анализа ботов
Ошибки конкретного бота:
{bot_name="bot-1", level="ERROR"}
Статистика по ботам:
sum by (bot_name) (count_over_time({service="bot"}[5m]))
Топ ошибок:
topk(10, sum by (message) (count_over_time({level="ERROR"}[1h])))
Заключение
Grafana Loki — это мощный инструмент для централизованного логирования Docker контейнеров. Он сочетает простоту настройки, низкое потребление ресурсов и отличную интеграцию с Grafana.
Ключевые преимущества:
- ✅ Простота — минимальная конфигурация
- ✅ Производительность — низкое потребление ресурсов
- ✅ Интеграция — единый интерфейс с метриками
- ✅ Масштабируемость — горизонтальное масштабирование
- ✅ Экономичность — подходит для небольших проектов
Следующие шаги:
- Установите Loki + Promtail + Grafana
- Настройте сбор логов из ваших контейнеров
- Создайте дашборды в Grafana
- Настройте алерты для критических ошибок
- Оптимизируйте retention политику