Проверять /var/log/messages или вывод journalctl на каждом сервере вручную - это потеря времени и прямой путь пропустить критическую ошибку диска. Когда серверов больше трёх, администратор физически не способен отследить все предупреждения о сбоях ввода-вывода, росте SMART-ошибок или заполнении раздела. Централизованный сбор логов решает эту проблему: все сообщения о состоянии дисков стекаются в единую панель, где автоматические правила мгновенно оповещают о проблеме через Telegram или email.
В этом руководстве мы построим систему мониторинга дисковых событий на базе rsyslog и Graylog. Настроим фильтрацию сообщений с тегами kernel и disk прямо на источнике, передадим логи в структурированном формате GELF в Graylog, развернутый в Docker, и создадим алерты для немедленной реакции на инциденты. Все конфигурации проверены на практике и готовы к адаптации под вашу среду.
Решение подходит для инфраструктур любого масштаба: от трёх физических хостов до кластеров с десятками нод. Если вы уже используете Docker для изоляции сервисов, логично углубиться в тему управления логами контейнеров - в нашем руководстве по логированию в Docker разобраны драйверы, ротация и интеграция с внешними системами.
Зачем нужен централизованный мониторинг дисковых логов
Типичная ситуация: у вас пять серверов, на каждом крутятся базы данных, веб-приложения, очереди. На одном из них контроллер диска начинает сыпать ошибки, но приложение пока работает. Вы узнаете об этом, когда раздел /var заполнится логами, или когда приложение упадет из-за невозможности записи. Ручной мониторинг не масштабируется.
Централизованная система меняет подход. Вместо реактивного просмотра логов после сбоя вы получаете проактивный инструмент. Graylog агрегирует сообщения со всех источников, индексирует их и позволяет строить поисковые запросы за секунды. Правила алертинга срабатывают автоматически при появлении ключевых фраз: I/O error, disk full, filesystem remounted read-only.
Экономия времени - измеримый результат. Системный администратор, обслуживающий 10 серверов, тратит на проверку логов минимум 15-20 минут в день. За месяц это более 7 часов. Автоматизация через связку rsyslog и Graylog сокращает эти затраты до нуля: система сама фильтрует шум и оповещает только о значимых событиях.
Архитектура решения: rsyslog, Graylog и Docker
Компоненты системы работают в четкой связке. На каждом сервере-источнике работает rsyslog - стандартный демон логирования в Linux. Он читает сообщения ядра через /proc/kmsg или journald, фильтрует их по заданным правилам и отправляет на центральный узел. Фильтрация происходит на стороне клиента: это снижает сетевой трафик и нагрузку на Graylog.
Graylog принимает логи через input GELF (Graylog Extended Log Format). GELF - это JSON-структура с обязательными полями version, host, short_message и timestamp. В отличие от сырого syslog-сообщения, GELF сохраняет структуру, что упрощает парсинг и поиск. Graylog индексирует каждое поле, позволяя строить сложные запросы вида facility:kern AND sda AND level:3.
Docker изолирует Graylog и его зависимости - MongoDB и Elasticsearch. Это упрощает развертывание и обновление: весь стек поднимается одной командой docker-compose up -d. Контейнеризация также решает проблему конфликта версий Java и библиотек, которая часто возникает при установке Graylog на голую ОС.
Для тех, кто строит комплексную систему наблюдаемости, будет полезен материал по маршрутизации логов и метрик в DevOps - там разобран полный конвейер телеметрии от Fluentd и Prometheus до Grafana.
Установка и настройка Graylog в Docker
Для развертывания Graylog подготовьте хост с Docker и Docker Compose. Минимальные требования: 4 ГБ ОЗУ, 2 ядра CPU, 20 ГБ дискового пространства. В продакшене рекомендуется 8 ГБ ОЗУ и SSD-накопитель для Elasticsearch.
Создайте файл docker-compose.yml:
version: '3.8'
services:
mongodb:
image: mongo:6.0
volumes:
- mongo_data:/data/db
restart: unless-stopped
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.18
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms1g -Xmx1g
- xpack.security.enabled=false
volumes:
- es_data:/usr/share/elasticsearch/data
restart: unless-stopped
graylog:
image: graylog/graylog:5.2
environment:
GRAYLOG_PASSWORD_SECRET: your-secret-key-min-16-chars
GRAYLOG_ROOT_PASSWORD_SHA2: sha256-hash-of-your-password
GRAYLOG_HTTP_EXTERNAL_URI: http://your-server-ip:9000/
GRAYLOG_ELASTICSEARCH_HOSTS: http://elasticsearch:9200
GRAYLOG_MONGODB_URI: mongodb://mongodb:27017/graylog
ports:
- "9000:9000"
- "12201:12201/udp"
- "1514:1514/tcp"
volumes:
- graylog_data:/usr/share/graylog/data
depends_on:
- mongodb
- elasticsearch
restart: unless-stopped
volumes:
mongo_data:
es_data:
graylog_data:Сгенерируйте GRAYLOG_PASSWORD_SECRET командой pwgen -N 1 -s 96 или openssl rand -hex 48. Для получения GRAYLOG_ROOT_PASSWORD_SHA2 выполните echo -n "your-password" | sha256sum. Запустите стек: docker-compose up -d. Веб-интерфейс станет доступен на порту 9000 через 30-60 секунд.
Создание GELF input для приема логов
GELF input - это точка входа для структурированных логов от rsyslog. В веб-интерфейсе Graylog перейдите в System → Inputs. В выпадающем списке выберите GELF UDP и нажмите Launch new input.
Заполните поля:
- Node: оставьте автоматически выбранный узел.
- Title: укажите понятное имя, например «Disk logs from rsyslog».
- Bind address:
0.0.0.0для приема со всех интерфейсов. - Port:
12201- стандартный порт GELF UDP.
Нажмите Save. Input появится в списке с пометкой RUNNING. Graylog готов принимать сообщения. Порт 12201 UDP уже проброшен в docker-compose.yml, дополнительных действий с файрволом на хосте не требуется, если вы не ограничивали трафик правилами iptables.
Настройка rsyslog на серверах-источниках
Rsyslog установлен по умолчанию в большинстве дистрибутивов Linux. Проверьте версию: rsyslogd -v. Для работы с GELF и расширенной фильтрацией требуется версия 8.x или выше. В CentOS 7 может потребоваться обновление из репозитория rsyslog официального сайта.
Конфигурацию разместим в отдельном файле /etc/rsyslog.d/30-disk-monitoring.conf. Такой подход изолирует наши правила от основного конфига и упрощает управление.
Фильтрация сообщений по тегам kernel и disk
Задача фильтра - отобрать сообщения ядра, связанные с дисковыми операциями, и отсечь системный шум. Ядро Linux генерирует тысячи сообщений в час: от подключения USB-устройств до сетевых событий. Нам нужны только те, что касаются блочных устройств, файловых систем и контроллеров хранения.
Базовый фильтр на RainerScript:
if ($syslogfacility-text == "kern") and (
$msg contains "sda" or
$msg contains "sdb" or
$msg contains "sd" or
$msg contains "nvme" or
$msg contains "hd" or
$msg contains "I/O error" or
$msg contains "disk full" or
$msg contains "No space left" or
$msg contains "filesystem" or
$msg contains "remount" or
$msg contains "READ FPDMA QUEUED" or
$msg contains "Buffer I/O error" or
$msg contains "EXT4-fs error" or
$msg contains "XFS" or
$msg contains "md" or
$msg contains "raid"
) then {
action(type="omfwd" target="graylog-server-ip" port="12201" protocol="udp" template="gelf_template")
stop
}Разберем ключевые элементы. Условие $syslogfacility-text == "kern" отбирает сообщения от ядра. Список проверок $msg contains захватывает типичные паттерны дисковых проблем: имена устройств (sda, nvme0n1), ошибки ввода-вывода, заполнение раздела, проблемы файловых систем ext4 и XFS, события программного RAID. Конструкция stop предотвращает дальнейшую обработку сообщения другими правилами.
Для расширенной фильтрации можно использовать регулярные выражения. Пример отбора сообщений о конкретном разделе:
if ($syslogfacility-text == "kern") and (
$msg regex "sd[a-z][0-9]" or
$msg regex "nvme[0-9]n[0-9]p[0-9]"
) then { ... }Этот фильтр отловит сообщения о конкретных партициях: sda1, sdb3, nvme0n1p2. Полезно, когда нужно мониторить только разделы с данными, исключая системные.
Отправка логов в формате GELF
GELF-шаблон преобразует сырое syslog-сообщение в JSON, который Graylog распарсит без дополнительных экстракторов. Определите шаблон в том же файле /etc/rsyslog.d/30-disk-monitoring.conf перед блоком фильтрации:
template(name="gelf_template" type="list") {
constant(value="{ \"version\": \"1.1\", ")
constant(value="\"host\": \"")
property(name="hostname")
constant(value="\", \"short_message\": \"")
property(name="msg" format="json")
constant(value="\", \"timestamp\": ")
property(name="timereported" dateFormat="rfc3339" format="json")
constant(value=", \"facility\": \"")
property(name="syslogfacility-text")
constant(value="\", \"severity\": ")
property(name="syslogseverity")
constant(value=", \"_tag\": \"")
property(name="syslogtag" format="json")
constant(value="\" }\n")
}Шаблон формирует JSON с обязательными полями GELF: version (строка «1.1»), host (имя сервера-источника), short_message (текст лога), timestamp (время в формате RFC 3339). Дополнительные поля с префиксом подчеркивания - _tag, facility, severity - становятся кастомными полями в Graylog и доступны для поиска.
Финальный конфигурационный файл целиком:
module(load="omfwd")
template(name="gelf_template" type="list") {
constant(value="{ \"version\": \"1.1\", ")
constant(value="\"host\": \"")
property(name="hostname")
constant(value="\", \"short_message\": \"")
property(name="msg" format="json")
constant(value="\", \"timestamp\": ")
property(name="timereported" dateFormat="rfc3339" format="json")
constant(value=", \"facility\": \"")
property(name="syslogfacility-text")
constant(value="\", \"severity\": ")
property(name="syslogseverity")
constant(value=", \"_tag\": \"")
property(name="syslogtag" format="json")
constant(value="\" }\n")
}
if ($syslogfacility-text == "kern") and (
$msg contains "sda" or
$msg contains "sdb" or
$msg contains "sd" or
$msg contains "nvme" or
$msg contains "I/O error" or
$msg contains "disk full" or
$msg contains "No space left" or
$msg contains "filesystem" or
$msg contains "remount" or
$msg contains "Buffer I/O error" or
$msg contains "EXT4-fs error"
) then {
action(type="omfwd" target="10.0.1.100" port="12201" protocol="udp" template="gelf_template")
stop
}Замените 10.0.1.100 на IP-адрес вашего Graylog-сервера. Примените конфигурацию: systemctl restart rsyslog. Проверьте статус: systemctl status rsyslog. Ошибки в конфигурации отобразятся в выводе команды.
Создание алертов и оповещений в Graylog
Система алертов Graylog строится на двух сущностях: Event Definitions (условия срабатывания) и Notifications (каналы доставки). Event Definition описывает поисковый запрос и временное окно, Notification определяет, куда отправить оповещение.
Перейдите в Alerts → Event Definitions и нажмите Create event definition. Заполните поля:
- Title: «Disk I/O Error Detected»
- Description: «Срабатывает при появлении ошибок ввода-вывода диска»
- Priority: High
В секции Condition задайте поисковый запрос: short_message:"I/O error" OR short_message:"Buffer I/O error". Укажите поток, в который попадают ваши логи (по умолчанию - All messages). Временное окно: 5 минут, срабатывание при появлении хотя бы одного сообщения.
Создайте аналогичные Event Definitions для других критических событий:
- Disk Space Critical: запрос
short_message:"No space left" OR short_message:"disk full" - Filesystem Remounted Read-Only: запрос
short_message:"remount" AND short_message:"read-only" - RAID Degraded: запрос
short_message:"md" AND short_message:"degraded"
Интеграция с Telegram
Создайте бота через @BotFather в Telegram. Получите токен вида 123456:ABC-DEF1234ghikl-zyx57W2v1u123ew11. Добавьте бота в целевой чат или начните с ним диалог. Чтобы узнать chat_id, отправьте боту сообщение и выполните запрос: curl -s "https://api.telegram.org/bot. В ответе найдите "chat":{"id":-123456789}.
В Graylog перейдите в Alerts → Notifications, нажмите Create Notification. Выберите тип HTTP Notification. URL: https://api.telegram.org/bot. Метод: POST. Тело запроса в формате JSON:
{
"chat_id": "-123456789",
"text": "[${event_definition_title}]\n\nMessage: ${event.message}\nSource: ${source}\nTimestamp: ${event.timestamp}",
"parse_mode": "HTML"
}Graylog подставляет переменные ${event_definition_title}, ${event.message} и другие при отправке. Протестируйте уведомление кнопкой Test.
Интеграция с email
Email остается резервным каналом, который не зависит от доступности мессенджеров. Настройте SMTP в System → Configurations: укажите адрес сервера, порт (587 для TLS), логин и пароль. Для Яндекс.Почты используйте smtp.yandex.ru:587, для Gmail - smtp.gmail.com:587 с паролем приложения.
Создайте Notification типа Email Notification. Укажите получателей через запятую, тему письма: Disk Alert: ${event_definition_title} on ${source}. В теле письма продублируйте ключевую информацию: хост, сообщение, время.
Привяжите Notifications к Event Definitions в секции Notifications каждого определения события. Один Event Definition может отправлять оповещения в несколько каналов одновременно.
Проверка и отладка системы мониторинга
Сгенерируйте тестовое сообщение на сервере-источнике: logger -p kern.err "TEST: I/O error on sda5". Утилита logger отправляет сообщение в syslog с указанным facility и severity. Через несколько секунд сообщение должно появиться в Graylog в поиске по запросу short_message:"TEST: I/O error".
Если сообщение не пришло, проверьте цепочку передачи:
- Локальный лог rsyslog:
tail -f /var/log/syslog | grep TEST. Сообщение должно быть видно. - Сетевой трафик:
tcpdump -i any udp port 12201 -Aна сервере-источнике. Вы увидите уходящие UDP-пакеты с JSON. - Файрвол на Graylog-сервере:
iptables -L -n | grep 12201. Порт должен быть открыт. - Логи Graylog:
docker logs graylog_graylog_1. Ошибки парсинга GELF или проблемы с Elasticsearch отобразятся здесь.
Типичная ошибка - неверный формат JSON в шаблоне. Проверьте валидность: скопируйте отправляемый JSON и прогоните через jq или онлайн-валидатор. Лишняя запятая или незакрытая кавычка ломают парсинг.
Другая частая проблема - расхождение версий GELF. Graylog ожидает строку "version":"1.1". Если в шаблоне указано число 1.1 без кавычек, сообщение будет отброшено.
Обеспечение отказоустойчивости и советы по эксплуатации
В продакшене Graylog может быть недоступен: перезагрузка, сбой сети, высокая нагрузка. Rsyslog должен буферизовать сообщения, а не терять их. Добавьте параметры очереди в конфигурацию действия:
action(type="omfwd" target="10.0.1.100" port="12201" protocol="udp" template="gelf_template"
queue.type="LinkedList"
queue.size="10000"
queue.filename="disk-log-queue"
queue.maxdiskspace="500m"
queue.saveonshutdown="on"
action.resumeRetryCount="-1"
action.resumeInterval="10"
)Эти параметры создают очередь в оперативной памяти (LinkedList) с сохранением на диск при заполнении 500 МБ. При недоступности Graylog rsyslog будет повторять попытки бесконечно (resumeRetryCount="-1") с интервалом 10 секунд. После восстановления связи все накопленные сообщения уйдут в Graylog.
Мониторьте сам Graylog. Встроенный health check доступен по адресу http://graylog-server:9000/api/system/lbstatus. Он возвращает ALIVE или DEAD в зависимости от состояния Elasticsearch и MongoDB. Настройте проверку этого эндпоинта в вашей системе мониторинга.
Регулярно обновляйте Docker-образы: docker-compose pull && docker-compose up -d. Перед обновлением делайте бэкап томов MongoDB и Elasticsearch. Управляйте дисковым пространством Elasticsearch через политики ротации индексов: в Graylog перейдите в System → Indices, выберите индекс-сет и настройте максимальное количество индексов или срок хранения в днях. Для дисковой телеметрии обычно достаточно 30 дней хранения.
Построенная система интегрируется в общий конвейер наблюдаемости. Если вы планируете расширить мониторинг на метрики и алертинг по аномалиям, обратитесь к нашему руководству по мониторингу и алертингу на основе логов - там разобраны готовые конфигурации Watcher и LogQL для Elasticsearch и Grafana Loki.