Мастер-класс по логированию в Linux: архитектура, инструменты и лучшие практики для DevOps и SRE
Это перевод оригинальной статьи Linux Logging Masterclass: Architecture, Tools, and Best Practices for DevOps and SRE.
Перевод сделан специально для телеграм-канала Мониторим ИТ. Подписывайтесь! Там еще больше полезных постов о мониторинге.
Глубокое погружение в принципы логирования Linux на производственном уровне для DevOps-инженеров, SRE-специалистов и инженеров платформ, работающих в Kubernetes, облаке и регулируемых средах.
1. Введение: почему логирование — это не опция, а необходимость
В любой боевой системе наблюдаемость определяется тремя основными элементами: метрики, трейсы и логи. Метрики указывают на наличие проблемы. Трейсы показывают, где именно в цепочке вызовов произошла ошибка. Логи объясняют причину.
Логирование — это старейшая и наиболее распространенная форма системной телеметрии, и тем не менее она остается одной из самых неправильно понимаемых. Инженеры перегружают систему логами, недогружают, логируют не то, что нужно, не централизуют их или полностью игнорируют ретеншн — до тех пор, пока инцидент в 3 часа ночи не заставит столкнуться с переполненным /var/log или отсутствием логов за нужный период.
В современных распределенных системах — кластерах Kubernetes, микросервисах, serverless-функциях — логирование стало значительно сложнее. Один пользовательский запрос может затрагивать десятки подов на нескольких нодах и в разных пространствах имен. Без структурированного, коррелированного и централизованного логирования восстановить последовательность событий практически невозможно.
В сфере финансовых технологий и регулируемых сред логирование — это не просто удобство для инженеров, а требование комплаенса. PCI-DSS, PSD2, GDPR и CESOP — все эти стандарты обязывают вести аудит-трейлы, логи доступа и соблюдать политику хранения данных. Последствия отсутствия логов при регуляторной проверке могут быть крайне серьёзными.
Это руководство охватывает полный стек логирования: от кольцевого буфера ядра и systemd-journald на нижнем уровне, через rsyslog и syslog-ng в середине, до Fluent Bit, Loki и Grafana на верхнем уровне. Каждый раздел ориентирован на использование в производственной среде.
2. Обзор архитектуры логирования Linux
Иерархия логирования
Система логирования в Linux представляет собой многоуровневую систему. Понимание каждого уровня помогает избежать неправильной диагностики во время инцидентов.
┌─────────────────────────────────────────┐
│ Central Logging Platform │
│ (Loki / Elasticsearch / CloudWatch) │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ Log Shipper / Aggregator │
│ (Fluent Bit / Fluentd / Logstash) │
└──────────────────┬──────────────────────┘
│
┌──────────────────▼──────────────────────┐
│ Syslog Daemon Layer │
│ (rsyslog / syslog-ng) │
└────────┬─────────────────────┬──────────┘
│ │
┌────────▼──────┐ ┌─────────▼──────────┐
│ systemd- │ │ /var/log files │
│ journald │ │ (flat files) │
└────────┬──────┘ └────────────────────┘
│
┌────────▼──────────────────────────────────┐
│ Applications / Services / Kernel │
│ (stdout/stderr, syslog(), /dev/kmsg) │
└────────────────────────────────────────────┘Логирование ядра
Ядро записывает сообщения в кольцевой буфер, доступный через /dev/kmsg. Команда dmesg читает этот буфер. Сообщения включают обнаружение оборудования, инициализацию драйверов, события OOM killer и ошибки файловой системы. В системах с systemd journald перехватывает сообщения ядра и делает их доступными через journalctl -k.
dmesg -T | grep -i error dmesg -T | grep -i "oom" journalctl -k --since "1 hour ago"
Логирование пользовательского пространства
Приложения логируют через несколько механизмов:
- Системный вызов syslog() — классический интерфейс POSIX; в современных системах маршрутизация осуществляется через journald.
- stdout/stderr — перехватываются менеджером сервисов (systemd или средой выполнения контейнеров).
- Прямая запись в файл — приложения записывают напрямую в файл
/var/log/app/. - Библиотеки структурированного логирования — запись JSON в stdout (распространено в микросервисах на Go, Python и Java).
Протокол syslog
Протокол syslog (RFC 5424) определяет facility (кто логирует: kern, auth, daemon, user и т.д.) и severity (уровень важности: emergency, alert, critical, error, warning, notice, info, debug). Эта комбинация формирует приоритет сообщения.
Уровни серьёзности и их значения:
- emerg (0) — система неработоспособна
- alert (1) — требуется немедленное действие
- crit (2) — критические состояния
- err (3) — ошибки
- warning (4) — предупреждения
- notice (5) — нормальные, но важные события
- info (6) — информационные сообщения
- debug (7) — отладочные сообщения
3. Подробный разбор systemd-journald
Как работает journald
systemd-journald — основной демон сбора логов в современных Linux-системах (RHEL 7+, Ubuntu 16.04+, Debian 8+). Он заменяет традиционный syslog как первый получатель логов.
/dev/kmsg— сообщения ядра/dev/log— сокет syslog (устаревший, для совместимости)stdout/stderrсервисов, управляемых systemd- Нативный протокол журнала через
/run/systemd/journal/ - Подсистема аудита
Двоичный формат журнала
В отличие от текстовых syslog-файлов, journald хранит логи в двоичном структурированном формате:
- Volatile (в режиме реального времени):
/run/log/journal/— исчезает после перезагрузки - Persistent
/var/log/journal/: — сохраняется после перезагрузки
Каждый файл журнала включает в себя прямое и обратное запечатывание (с помощью --seal) для обнаружения попыток несанкционированного доступа и поддерживает индексированный поиск по юниту, идентификатору процесса, временной метке и идентификатору сообщения.
Для включения постоянного хранения создайте директорию:
mkdir -p /var/log/journal systemd-tmpfiles --create --prefix /var/log/journal systemctl restart systemd-journald
Основные команды journalctl
# Follow logs in real time (like tail -f) journalctl -f
# Show all logs from the last hour journalctl --since "1 hour ago" # Show logs for a specific service journalctl -u nginx.service journalctl -u nginx.service --since "2024-01-15 10:00:00" --until "2024-01-15 11:00:00" # Show kernel messages only journalctl -k # Show verbose context with explanations for errors journalctl -xe # Filter by priority (0=emerg to 7=debug) journalctl -p err # errors and above journalctl -p warning..err # Filter by PID journalctl _PID=1234 # Output formats journalctl -u nginx -o json-pretty journalctl -u nginx -o short-iso # Disk usage journalctl --disk-usage # Vacuum old logs journalctl --vacuum-time=7d journalctl --vacuum-size=500M
Конфигурация journald
[Journal] Storage=persistent Compress=yes SystemMaxUse=2G SystemKeepFree=500M SystemMaxFileSize=100M MaxRetentionSec=30day RateLimitInterval=30s RateLimitBurst=10000 ForwardToSyslog=yes
SystemMaxUse— жёсткий лимит на использование дискового пространства журналомRateLimitBurst— максимальное количество сообщений за интервалRateLimitIntervalдля одного сервиса; критично для сервисов с большим количеством сообщений.ForwardToSyslog=yes— передаёт (мостит) логи из journald в rsyslog для пересылки
4. rsyslog: глубокий разбор
Архитектура
rsyslog — это высокопроизводительный демон syslog, который обрабатывает маршрутизацию, фильтрацию, преобразование и пересылку логов. В большинстве дистрибутивов он работает совместно с journald, принимая перенаправленные сообщения и записывая их в файлы в /var/log/ или удаленные места назначения.
rsyslog обрабатывает сообщения через конвейер:
Input → Parser → Rulesets (filters + actions) → Output
Структура конфигурации
/etc/rsyslog.conf # Main config /etc/rsyslog.d/*.conf # Drop-in configs (loaded alphabetically)
# Load modules
module(load="imuxsock") # Local syslog socket
module(load="imjournal" # Read from journald
StateFile="imjournal.state")# Global settings $WorkDirectory /var/spool/rsyslog $ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat # Local log files auth,authpriv.* /var/log/auth.log *.*;auth,authpriv.none /var/log/syslog kern.* /var/log/kern.log *.emerg :omusrmsg:* # Include drop-ins $IncludeConfig /etc/rsyslog.d/*.conf
Удалённая пересылка
# UDP forwarding (fire and forget, lower overhead) *.* @logserver.example.com:514
# TCP forwarding (reliable, buffered)
*.* @@logserver.example.com:514
# TCP with TLS
*.* action(type="omfwd"
target="logserver.example.com"
port="6514"
protocol="tcp"
StreamDriver="gtls"
StreamDriverMode="1"
StreamDriverAuthMode="x509/name")UDP против TCP для пересылки логов:
UDP (один @) имеет низкие накладные расходы, но может терять сообщения при высокой нагрузке или сбоях сети. TCP (двойной @@) буферизует и повторно передает данные, что делает его подходящим для обеспечения соответствия нормативным требованиям и ведения журналов аудита. Для высоконагруженных производственных систем используется очередь:
*.* action(type="omfwd"
target="logserver.example.com"
port="514"
protocol="tcp"
queue.type="LinkedList"
queue.size="10000"
queue.dequeueBatchSize="100"
queue.filename="fwdRule"
queue.maxDiskSpace="1g"
queue.saveOnShutdown="on"
action.resumeRetryCount="-1")Структурированный вывод с использованием шаблонов
rsyslog может выводить данные в формате JSON для конечных потребителей:
template(name="JSONFormat" type="string"
string="{\"time\":\"%timereported:::date-rfc3339%\",\"host\":\"%HOSTNAME%\",\"severity\":\"%syslogseverity-text%\",\"facility\":\"%syslogfacility-text%\",\"program\":\"%programname%\",\"pid\":\"%procid%\",\"message\":\"%msg:::json%\"}\n")*.* action(type="omfile" file="/var/log/json/all.log" template="JSONFormat")
5. syslog-ng против rsyslog
syslog-ng придерживается иной философии проектирования: он использует декларативный язык конфигурации, основанный на источниках, фильтрах и получателях, а не гибридный подход, основанный на правилах, как в rsyslog.
Когда следует выбирать rsyslog:
- В RHEL/CentOS, Ubuntu, Debian это стандартная практика, хорошо документированная.
- Сложные правила маршрутизации с наборами правил
- подходит для высокой нагрузки на одном узле
- Интеграция с imjournal для обеспечения связи с journald
Когда следует выбирать syslog-ng:
- Приоритетом является ясность конфигурации (читаемый синтаксис).
- Активное использование парсеров (CSV, JSON, Apache и т. д.)
- Сложная корреляция и переписывание сообщений
- Премиум enterprise-функции (store-box и др.)
Аналог syslog-ng для удаленной пересылки:
source s_local {
system();
internal();
};destination d_remote {
network("logserver.example.com"
port(514)
transport("tcp"));
};
log {
source(s_local);
destination(d_remote);
};Для большинства команд, управляющих Linux-инфраструктурой, rsyslog является практичным выбором по умолчанию, если только опыт команды или специфические требования к парсингу не склоняют в пользу syslog-ng.
6. Файлы логов и их расположение
Стандартные пути логов
Путь — Содержимое
/var/log/syslog — Общие системные сообщения (Debian/Ubuntu)
/var/log/messages — Общие системные сообщения (RHEL/CentOS)
/var/log/auth.log — События аутентификации (Debian/Ubuntu)
/var/log/secure — События аутентификации (RHEL/CentOS)
/var/log/kern.log — Сообщения ядра
/var/log/dmesg — Сообщения ядра при загрузке
/var/log/apt/ — Управление пакетами (Debian)
/var/log/yum.log — Управление пакетами (RHEL)
/var/log/nginx/ — Логи доступа и ошибок Nginx
/var/log/apache2/ — Логи доступа и ошибок Apache
/var/log/mysql/ — Лог ошибок MySQL
/var/log/postgresql/ — Логи PostgreSQL
/var/log/audit/audit.log — Демон аудита Linux
Практики логирования приложений
Современные приложения должны писать в stdout и stderr, а не в файлы. Это соответствует принципам Twelve-Factor App и именно его ожидают Kubernetes, Docker и systemd. Инфраструктура логирования (journald, среда выполнения контейнеров) занимается сбором, ротацией и пересылкой.
Когда прямая запись в файл неизбежна (устаревшие приложения, базы данных), необходимо обеспечить следующее:
- Права доступа к директории логов ограничены (только пользователь приложения)
- Настройка logrotate (см. раздел 7) (см. раздел 7).
- Приложение обрабатывает сигнал SIGHUP для повторного открытия лог-файла (или используйте
copytruncate).
7. Ротация логов с помощью logrotate
Без ротации логов каталог /var/log заполняет корневую файловую систему. На загруженном веб-сервере логи доступа могут разрастаться до гигабайт в день.
Конфигурация
Система logrotate запускается ежедневно с помощью cron или systemd timer в /etc/cron.daily/logrotate или logrotate.timer.
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
nginx -s reopen
endscript
}Option — Effect
daily/weekly/monthly — частота ротации
rotate N — хранить N ротированных файлов
compress — сжимать старые файлы (gzip)
delaycompress — пропустить сжатие самого последнего ротированного файла (позволяет приложениям завершить запись)
missingok — не выдавать ошибку, если лог отсутствует
notifempty — пропустить ротацию, если лог пустой
copytruncate — копировать и затем обрезать (для приложений, не поддерживающих SIGHUP)
postrotate — скрипт, выполняемый после ротации (например, перезапуск nginx)
dateext — использовать дату в имени ротированного файла вместо чисел
Тестирование logrotate
# Dry run logrotate -d /etc/logrotate.d/nginx
# Force rotation now logrotate -f /etc/logrotate.d/nginx
systemd-journald Rotation
journald имеет собственную встроенную ротацию, управляемую через journald.conf. Для сред, использующих только systemd и не имеющих rsyslog, убедитесь, что SystemMaxUse настроен, чтобы предотвратить неограниченный рост.
8. Централизованная архитектура логирования
Система логирования на одном хосте ненадежна и не масштабируема. Централизованное логирование решает следующие проблемы:
- Единый интерфейс для отладки мультихостовых и мультисервисных систем
- Корреляция между сервисами и узлами
- Долгосрочное хранение независимо от жизненного цикла хоста
- Требования комплаенса и аудита
Архитектурные паттерны
Паттерн 1: лёгкий (малый масштаб)
Linux hosts → rsyslog TCP → Central syslog server → Files
Паттерн 2: современный observability стек
Linux hosts → Fluent Bit → Loki → Grafana
Паттерн 3: стек Enterprise ELK
Linux hosts → Fluent Bit → Kafka → Logstash → Elasticsearch → Kibana
Паттерн 4: высоконагруженная регулируемая среда
Linux hosts → Fluent Bit (per node) → Kafka (durable buffer) →
Logstash (parse/enrich) → Elasticsearch (hot-warm-cold) → Kibana
↓
Cold storage (S3/GCS)В регулируемых средах Kafka как буфер между отправителями и индексатором имеет важное значение. Если Elasticsearch уходит на обслуживание и становится недоступным, Kafka сохраняет сообщения. Без него вы теряете данные логов во время простоя индексатора.
Fluent Bit
Fluent Bit — это легковесный инструмент для отправки логов, предпочитаемый в Kubernetes и средах с ограниченными ресурсами. Написан на языке C и потребляет примерно 450 килобайт оперативной памяти в состоянии простоя. Он работает как DaemonSet в Kubernetes или как systemd-сервис на Linux-хостах.
# /etc/fluent-bit/fluent-bit.conf
[SERVICE]
Flush 5
Daemon Off
Log_Level info
Parsers_File parsers.conf[INPUT]
Name systemd
Tag host.*
Systemd_Filter _SYSTEMD_UNIT=nginx.service
DB /var/log/flb_systemd.db
Read_From_Tail On
[FILTER]
Name record_modifier
Match host.*
Record hostname ${HOSTNAME}
Record environment production
[OUTPUT]
Name loki
Match host.*
Host loki.monitoring.svc.cluster.local
Port 3100
Labels job=fluentbit,host=${HOSTNAME}
line_format jsonLogstash — это мощный ETL-слой: выполняет парсинг, обогащение и маршрутизацию логов. Он используется тогда, когда необходимы сложные трансформации, такие как grok парсинг неструктурированных логов, GeoIP обогащение, нормализация полей или маршрутизация в несколько выходов.
input {
kafka {
bootstrap_servers => "kafka:9092"
topics => ["logs"]
codec => json
}
}filter {
if [kubernetes][namespace] == "payments" {
mutate {
add_field => { "compliance_scope" => "pci" }
}
}
if [message] =~ /ERROR/ {
mutate { add_tag => ["error"] }
}
}
output {
elasticsearch {
hosts => ["elasticsearch:9200"]
index => "logs-%{+YYYY.MM.dd}"
}
}9. Логирование в Kubernetes
Модель логирования Kubernetes
В Kubernetes нет встроенной централизованной системы логирования. Официальная модель: контейнеры записывают данные в stdout/stderr, контейнерный runtime захватывает эти потоки, и дальнейшая обработка является вашей ответственностью.
На каждой ноде Kubernetes логи контейнеров находятся по пути:
/var/log/containers/<pod>_<namespace>_<container>-<id>.log
/var/log/pods/<namespace>_<pod>_<uid>/<container>/<n>.log
Команды логирования kubectl
# Current logs kubectl logs <pod> -n <namespace>
# Follow kubectl logs -f <pod> -n <namespace> # Previous container instance (after crash) kubectl logs <pod> --previous -n <namespace> # Multi-container pod kubectl logs <pod> -c <container> -n <namespace> # All pods matching a label kubectl logs -l app=nginx -n production --prefix # With timestamps kubectl logs <pod> --timestamps=true
Архитектура логирования на уровне ноды
Container → container runtime (containerd/CRI-O) → /var/log/pods/...
↓
Fluent Bit DaemonSet
↓
Central log systemИнтеграция journald зависит от runtime контейнеров. При использовании cgroups от systemd, containerd может перенаправлять запросы в journald:
journalctl -u containerd CONTAINER_NAME=nginx
Стек логирования Kubernetes: Fluent Bit + Loki
Рекомендуемый для использования в производственной среде лёгкий стек для Kubernetes:
# fluent-bit-daemonset.yaml (simplified)
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluent-bit
namespace: logging
spec:
selector:
matchLabels:
app: fluent-bit
template:
spec:
serviceAccountName: fluent-bit
containers:
- name: fluent-bit
image: cr.fluentbit.io/fluent/fluent-bit:3.0
volumeMounts:
- name: varlog
mountPath: /var/log
- name: config
mountPath: /fluent-bit/etc
volumes:
- name: varlog
hostPath:
path: /var/log
- name: config
configMap:
name: fluent-bit-configLoki — это горизонтально масштабируемая система агрегации логов, разработанная по принципу Prometheus, но для логов. Она индексирует только метки (а не полный текст), что делает её гораздо дешевле Elasticsearch для хранения исключительно логов.
# Loki labels strategy for Kubernetes
labels:
namespace: "{{ .kubernetes.namespace }}"
pod: "{{ .kubernetes.pod_name }}"
container: "{{ .kubernetes.container_name }}"
node: "{{ .kubernetes.host }}"Критически важно: поддерживайте низкую кардинальность меток Loki.
Не используйте идентификаторы подов или запросов в качестве меток. Их необходимо хранить внутри логов. Высокая кардинальность меток ухудшает производительность Loki.
Проблемы логирования в Kubernetes
- Ротация логов на узлах: kubelet по умолчанию ротирует контейнерные логи (10MB / 5 файлов). Fluent Bit DB отслеживает позицию и сохраняет результат ротации.
- Жизненный цикл pod: когда pod удаляется, его логи удаляются с ноды. Логи должны быть отправлены до удаления pod.
- CrashLoopBackOff: Используйте флаг
--previousи отправляйте логи до завершения процесса, чтобы избежать потери контекста сбоя. - Контейнеры-сайдкары: Некоторые команды внедряют сайдкар, который считывает файлы логов приложения и записывает их в stdout. Это работает, но увеличивает нагрузку на ресурсы.
10. Облачное логирование
AWS CloudWatch Logs
CloudWatch Logs является нативным решением AWS. Агент CloudWatch собирает данные из следующих источников:
// /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json
{
"logs": {
"logs_collected": {
"files": {
"collect_list": [
{
"file_path": "/var/log/nginx/access.log",
"log_group_name": "/ec2/nginx/access",
"log_stream_name": "{instance_id}",
"timestamp_format": "%d/%b/%Y:%H:%M:%S %z"
}
]
},
"journald": {
"collect_list": [
{
"log_group_name": "/ec2/system",
"log_stream_name": "{instance_id}/journald"
}
]
}
}
}
}Для Kubernetes в EKS Fluent Bit отправляет данные напрямую в CloudWatch:
[OUTPUT]
Name cloudwatch_logs
Match kube.*
region eu-west-1
log_group_name /eks/cluster/application
log_stream_prefix ${HOST_NAME}-
auto_create_group trueGCP Cloud Logging
Google Cloud Logging (ранее Stackdriver) использует Ops Agent на GCE, а интеграция логирования в GKE выполняется автоматически. Для пользовательских конфигураций:
logging:
receivers:
nginx_access:
type: files
include_paths:
- /var/log/nginx/access.log
processors:
nginx_parser:
type: parse_nginx_combined
pipelines:
nginx_pipeline:
receivers: [nginx_access]
processors: [nginx_parser]Azure Monitor
Azure Monitor Logs (Log Analytics) использует Azure Monitor Agent (AMA), который заменяет устаревший Log Analytics Agent (MMA). Настройка выполняется через Data Collection Rules (DCR):
{
"dataSources": {
"syslog": [
{
"streams": ["Microsoft-Syslog"],
"facilityNames": ["auth", "authpriv", "daemon"],
"logLevels": ["Warning", "Error", "Critical"],
"name": "syslogSource"
}
]
}
}11. Отладка и troubleshooting через логи
Диагностика сбоя сервиса
# Step 1: What's the service status? systemctl status nginx
# Step 2: Get full journal context journalctl -u nginx -xe --since "10 minutes ago" # Step 3: Check last 100 lines journalctl -u nginx -n 100 --no-pager # Step 4: Check for dependency failures journalctl -b -p err
Сбои аутентификации SSH
# Failed logins journalctl -u ssh --since today | grep "Failed password"
# Successful logins
journalctl -u ssh --since today | grep "Accepted"
# On systems with auth.log:
grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn | head -20События OOM ядра
# OOM killer events journalctl -k | grep -i "oom\|killed process\|out of memory"
# Memory pressure before OOM dmesg -T | grep -A5 "oom_kill"
Отладка ошибок Nginx 502/503
# Combine nginx error log with upstream logs
journalctl -u nginx --since "15 minutes ago" -o json | \
python3 -c "
import sys, json
for line in sys.stdin:
e = json.loads(line)
msg = e.get('MESSAGE','')
if 'upstream' in msg or 'error' in msg.lower():
print(e['__REALTIME_TIMESTAMP'], msg)
"Корреляция логов между сервисами
В среде микросервисов используйте идентификатор корреляции (идентификатор трассировки), внедряемый на уровне API-шлюза и передаваемый через все вызовы сервисов. При отладке:
# Search for a specific request ID across all logs
grep "req-abc123" /var/log/*/access.log
# Or with Loki:
{namespace="production"} |= "req-abc123"12. Security и compliance логирование
auditd: фреймворк аудита ядра
auditd перехватывает системные вызовы, значимые для безопасности, на уровне ядра — до любой фильтрации на уровне приложений. Это необходимо для соответствия требованиям PCI-DSS, SOX и CESOP.
# Install apt install auditd audispd-plugins # Debian/Ubuntu dnf install audit # RHEL
# Enable systemctl enable --now auditd
Правила аудита в /etc/audit/rules.d/:
# Monitor privileged command execution -a always,exit -F arch=b64 -S execve -F euid=0 -k root_commands
# Monitor file access to sensitive files -w /etc/passwd -p wa -k identity -w /etc/shadow -p wa -k identity -w /etc/sudoers -p wa -k sudoers # Monitor network configuration changes -a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale # Monitor successful/failed login attempts -w /var/log/faillog -p wa -k logins -w /var/log/lastlog -p wa -k logins # Monitor sudo usage -w /usr/bin/sudo -p x -k sudo_usage
# All events for a specific user ausearch -ua 1001 --start today
# All file writes to /etc ausearch -f /etc --success yes # Failed login attempts ausearch -m USER_AUTH --success no --start today # Generate a summary report aureport --summary aureport --failed
Анализ логов аутентификации
# Monitor for brute force attempts (>10 failures from same IP)
awk '/Failed password/{print $11}' /var/log/auth.log | \
sort | uniq -c | sort -rn | awk '$1>10{print $2, $1, "attempts"}'# Account lockouts grep "pam_unix.*authentication failure" /var/log/auth.log # sudo escalations grep "sudo:" /var/log/auth.log | grep "COMMAND"
Специфика FinTech и Compliance
В регулируемых средах (PSD2, CESOP, PCI-DSS) требования к логированию включают:
- Tamper-evident storage: использование запечатывания journald (--seal) или хранилищ с однократной записью (S3 Object Lock, WORM-диски)
- Retention: PCI-DSS требует хранения минимум 1 год (3 месяца в онлайн-режиме, 9 месяцев в архиве).
- Access logging: каждый доступ к данным держателей карт должен логироваться с указанием пользователя, времени, действия и исходного IP-адреса.
- Privileged access monitoring: вся активность с правами root/sudo должна фиксироваться и анализироваться.
- Log integrity verification: регулярная проверка хэшей архивных логов.
- Separation of duties: данные логов должны быть недоступны пользователям, за которыми ведётся наблюдение.
Пример конфигурации rsyslog для финансовых систем, ориентированной на соблюдение нормативных требований:
# Auth events to tamper-evident remote store (TCP with TLS)
auth.* action(type="omfwd"
target="siem.compliance.internal"
port="6514"
protocol="tcp"
StreamDriver="gtls"
StreamDriverMode="1"
queue.type="LinkedList"
queue.filename="complianceFwd"
queue.saveOnShutdown="on"
action.resumeRetryCount="-1")# Local copy for immediate access auth.* /var/log/auth.log
13. Производительность и оптимизация
Ограничение скорости (Rate Limiting)
Неправильно работающий сервис может генерировать миллионы строк логов в секунду, перегружая journald и заполняя диск. Ограничение скорости в journald:
# /etc/systemd/journald.conf RateLimitInterval=30s RateLimitBurst=10000
Если сервис превышает 10 000 сообщений за 30 секунд, journald отбрасывает дальнейшие сообщения до сброса интервала. В этом случае вы увидите следующее:
Suppressed N messages from unit nginx.service
module(load="omprog")
if $programname == 'noisy-app' then {
action(type="omfile" file="/dev/null")
stop
}Оптимизация дискового ввода-вывода
- Асинхронная запись: rsyslog по умолчанию использует асинхронный ввод-вывод; не отключайте его.
- Сжатие journald: оставьте
Compress=yes; записи журнала хорошо сжимаются (снижение на 70-80%). - Отдельный раздел для логов: монтируйте
/var/logна отдельный раздел или LVM-том, чтобы избежать переполнения корневой файловой системы - tmpfs для временных логов: Если вам нужны логи только для отладки в реальном времени (нет необходимости в постоянном хранении), используйте
/run/log/journal/(временный режим).
Настройка производительности journald
[Journal] Storage=persistent Compress=yes SystemMaxUse=4G # Absolute cap SystemKeepFree=1G # Always keep this free on disk SystemMaxFileSize=200M # Max size per journal file MaxFileSec=1month # Rotate files older than this
Проверьте текущую загрузку диска и выполните автоматическую очистку:
journalctl --disk-usage journalctl --verify journalctl --vacuum-size=2G journalctl --vacuum-time=30d
Настройка буферизации Fluent Bit
Для высоконагруженных сред настройте буферизацию памяти и файловой системы Fluent Bit:
[SERVICE]
Flush 1
storage.path /var/log/flb-storage/
storage.sync normal
storage.checksum off
storage.max_chunks_up 128[INPUT]
Name tail
storage.type filesystem # Persist to disk if output unavailable
Mem_Buf_Limit 50MB
Buffer_Max_Size 5MB14. Передовые методы
1. Лучшие практики
Без исключений. Анализ логов с одного хоста допустим для разработки, но никогда для производственной среды. У вас может возникнуть инцидент в 3 часа ночи, когда вам понадобятся логи с 12 хостов одновременно.
2. Используйте структурированное логирование (JSON).
Неструктурированные логи легко читаются человеком, но плохо обрабатываются машинами. JSON-логи позволяют фильтрацию по полям, агрегацию и настройку алертов.
{"time":"2024-01-15T10:23:45Z","level":"ERROR","service":"payment-api","trace_id":"abc123","user_id":9821,"message":"Payment gateway timeout","duration_ms":5000,"gateway":"stripe"}С помощью структурированных логов можно выполнять следующие запросы: {service="payment-api"} | json | duration_ms > 3000
3. Никогда не логируйте секреты
PAN-номера, пароли, API-ключи, токены, идентификаторы сессий — всё это не должно попадать в логи. Реализуйте очистку логов:
- На уровне приложения (маскирование перед записью в лог)
- На уровне отправителя (
Lua-фильтр Fluent Bit илиmutateв Logstash) - Регулярно проводите аудит (поиск по шаблонам вроде номеров карт в образцах логов).
-- Fluent Bit Lua filter to redact card numbers
function redact_pci(tag, timestamp, record)
if record["message"] then
record["message"] = string.gsub(record["message"], "%d%d%d%d%s?%d%d%d%d%s?%d%d%d%d%s?%d%d%d%d", "****-****-****-****")
end
return 1, timestamp, record
end4. Добавление согласованных метаданных
Каждая строка лога должна содержать: hostname, имя сервиса, окружение (production/staging), версию и correlation/trace ID. Это обязательное требование в распределенных системах.
5. Мониторинг объёма логов
Объем логов — это сигнал. Всплеск объема логов часто предшествует инциденту или сопровождает его. Настройте оповещения:
- Loki:
rate({job="myapp"}[5m]) > 1000— если скорость логов превышает 1000 в минуту - Elasticsearch: мониторинг скорости индексации документов
6. Тестирование хранения и восстановления логов
Ежеквартально: необходимо подтверждать, что вы действительно можете получить логи возрастом 90 дней. Логи для комплаенса, которые невозможно восстановить, считаются нарушением требований комплаенса.
7. Разделение логов приложения и безопасности
Необходимо направлять события аутентификации, audit события и логи привилегированных команд в отдельное хранилище с более высоким сроком хранения и защитой от изменения. Не следует смешивать их с логами отладки приложений.
8. Документирование схемы логов
Для каждого сервиса необходимо поддерживать документ схемы логов.
Он должен описывать: какие поля отправляются, какие значения допустимы и что означает уровень severity в вашем контексте. Это значительно повышает эффективность во время инцидентов и при внедрении новых клиентов.
15. Современный стек логирования: journald + Fluent Bit + Loki + Grafana
Этот стек является практическим выбором для команд, использующих Kubernetes и уже имеющих инфраструктуру Grafana.
Он является open source, лёгким и глубоко интегрированным.
┌─────────────┐ ┌──────────────┐ ┌──────────┐ ┌─────────┐ │ systemd │ │ Fluent Bit │ │ Loki │ │ Grafana │ │ journald │───▶│ DaemonSet │───▶│ (ingest) │───▶│(Explore)│ │ │ │ │ │ │ │ │ │ containers │ │ per node │ │ S3/GCS │ │ Alerts │ └─────────────┘ └──────────────┘ └──────────┘ └─────────┘
Преимущества по сравнению с ELK
- Стоимость: Loki индексирует только labels, полный текст ищется во время запроса. Хранение данных стоит в 10–20 раз дешевле, чем Elasticsearch при аналогичной ретенции.
- Эксплуатационные издержки: отсутствие необходимости в настройке JVM tuning, shard management, сложной координации кластера.
- Нативная интеграция с Grafana: один и тот же инструмент используется для метрик (Prometheus) и логов (Loki).
- LogQL: Мощный язык запросов, аналогичный PromQL, знакомый любому пользователю Prometheus.
Примеры запросов Loki (LogQL):
# All errors from production payment service
{namespace="production", app="payment-api"} |= "ERROR"# JSON parsing and field filtering
{namespace="production"} | json | level="error" | duration_ms > 1000
# Error rate over time
rate({namespace="production"} |= "ERROR" [5m])
# Top 10 slowest requests
{app="api"} | json | duration_ms > 0 | line_format "{{.duration_ms}}" | unwrap duration_ms | topk(10, sum by (path) (avg_over_time([1h])))16. Практическая production конфигурация: один Linux сервер
Полный рабочий пример: один Linux сервер отправляет systemd journal в Loki через Fluent Bit.
Шаг 1: Установка Fluent Bit
curl https://raw.githubusercontent.com/fluent/fluent-bit/master/install.sh | sh systemctl enable fluent-bit
Шаг 2: Настройка Fluent Bit
# /etc/fluent-bit/fluent-bit.conf
[SERVICE]
Flush 5
Daemon Off
Log_Level info
Parsers_File parsers.conf
storage.path /var/log/flb-storage/[INPUT]
Name systemd
Tag systemd.*
DB /var/log/flb_journal.db
Read_From_Tail On
Strip_Underscores On
[INPUT]
Name tail
Path /var/log/nginx/access.log
Tag nginx.access
DB /var/log/flb_nginx.db
Parser nginx
[FILTER]
Name record_modifier
Match *
Record hostname ${HOSTNAME}
Record env production
[FILTER]
Name lua
Match *
script /etc/fluent-bit/redact.lua
call redact_pci
[OUTPUT]
Name loki
Match *
Host loki.internal
Port 3100
Labels job=fluent-bit,host=${HOSTNAME}
line_format json
auto_kubernetes_labels onШаг 3: Парсеры
# /etc/fluent-bit/parsers.conf
[PARSER]
Name nginx
Format regex
Regex ^(?<remote>[^ ]*) [^ ]* (?<user>[^ ]*) \[(?<time>[^\]]*)\] "(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?" (?<code>[^ ]*) (?<size>[^ ]*)(?: "(?<referer>[^\"]*)" "(?<agent>[^\"]*)")?$
Time_Key time
Time_Format %d/%b/%Y:%H:%M:%S %zШаг 4: Настройка Loki (минимальная)
# /etc/loki/loki.yaml auth_enabled: false
server:
http_listen_port: 3100
ingester:
wal:
dir: /var/loki/wal
lifecycler:
ring:
replication_factor: 1
schema_config:
configs:
- from: 2024-01-01
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
storage_config:
tsdb_shipper:
active_index_directory: /var/loki/index
cache_location: /var/loki/cache
filesystem:
directory: /var/loki/chunks
limits_config:
retention_period: 30dsystemctl start fluent-bit loki # Check Fluent Bit is reading journal journalctl -u fluent-bit -f # Verify Loki is receiving curl http://localhost:3100/ready curl http://localhost:3100/loki/api/v1/labels
17. Частые проблемы и решения
Проблема: отсутствуют логи за временной интервал
Симптомы: Не удается найти логи за определенный период.
journalctl --list-boots journalctl --verify journalctl --disk-usage
- Временное хранилище: journald в volatile режиме теряет логи после перезагрузки. Включите persistent storage:
mkdir /var/log/journal && systemctl restart systemd-journald - Ограничение скорости: проверить сообщения suppression:
journalctl | grep "Suppressed" - Fluent Bit position DB: если Fluent Bit упал, база может быть повреждена. Удалите его и перезапустите (возможен повторный сбор части логов).
- Ротация логов удаляет файлы: вход tail в Fluent Bit с использованием DB сохраняет позицию при ротации; без этого ротация файлов может привести к пропуску строк.
Проблема: логи не ротируются
# Test config logrotate -d /etc/logrotate.d/myapp
# Force rotation logrotate -f /etc/logrotate.conf # Check cron/timer systemctl status logrotate.timer
Частая причина: неправильные права на файл или ошибка postrotate скрипта (проверьте код завершения).
Проблема: /var/log заполнен
# Find largest consumers du -sh /var/log/* | sort -rh | head -20
# Check journald journalctl --disk-usage # Emergency cleanup journalctl --vacuum-size=500M # Trim journal to 500MB journalctl --vacuum-time=3d # Remove entries older than 3 days # Find any rotated but uncompressed logs find /var/log -name "*.log.*" ! -name "*.gz" -size +100M gzip /var/log/bigapp/app.log.1
Профилактика: добавьте оповещение о заполнения диска при достижении 80% использования раздела /var/log.
Проблема: journald потребляет слишком много дискового пространства.
journalctl --disk-usage # Expected: < configured SystemMaxUse value
# If over limit, journald should auto-vacuum; if not: journalctl --vacuum-size=2G # Permanently fix cat >> /etc/systemd/journald.conf << EOF SystemMaxUse=2G SystemKeepFree=500M EOF systemctl restart systemd-journald
Проблема: Fluent Bit не отправляет логи в Loki
# Check Fluent Bit logs journalctl -u fluent-bit -n 100
# Manually push a test log
curl -H "Content-Type: application/json" \
-X POST http://loki.internal:3100/loki/api/v1/push \
--data '{"streams":[{"stream":{"job":"test"},"values":[["'$(date +%s%N)'","test message"]]}]}'Проблема: высокая кардинальность ломает Loki
Симптомы: производительность запросов в Loki снижается, приём данных замедляется, возникают ошибки ограничения потоков.
# Check number of unique streams
count(count by(__stream_shard__)(rate({job="myapp"}[5m])))Исправление: Уменьшить разнообразие меток. Никогда не используйте идентификаторы запросов, идентификаторы пользователей или метки времени в качестве меток Loki. Они должны находиться в теле лога.
18. Заключение
Логирование в Linux — это не формальность, а операционная инфраструктура, столь же важная, как сеть или хранилище. Переход от локального journald к полностью централизованной, структурированной и коррелированной системе логирования — это разница между работой вслепую и реальной наблюдаемостью.
Современный стек логирования — journald, собирающий всё локально, Fluent Bit, эффективно передающий данные на уровне узла, Loki, экономично хранящий данные с индексированием по меткам, и Grafana, предоставляющая единые дашборды и оповещения — даёт наблюдаемость уровня production без тяжеловесности полноценного ELK-кластера.
Для FinTech и регулируемых сред логирование — это часть комплаенса. Потерянные логи — это нарушения аудита. Инвестиции в централизованное хранение, неизменяемые (tamper-evident) хранилища, корректные политики хранения и регулярную проверку восстановления логов — это не опция, а стоимость работы в регулируемой среде.
- Централизуйте или смиритесь с отсутствием мониторинга — распределенные логи, к которым нельзя обращаться с запросами, не являются наблюдаемостью.
- Структурированное логирование — JSON повсюду, с самого начала; модернизация — мучительный процесс.
- В логах никаких секретов: внедрите очистку на нескольких уровнях.
- Проверьте срок хранения данных — логи, которые вы не можете восстановить, не учитываются комплаенсом.
- Контролируйте объём логов — это сигнал; всплески предшествуют инцидентам.
Освоив эти основы и внедрив описанные практики, логирование превращается из проблемы в инструмент, дающий реальную управляемость системой.
Подписывайтесь на телеграм-канал Мониторим ИТ, там еще больше полезной информации о мониторинге!