Docker logs и journald: выбор драйвера логирования
Когда контейнер падает, логи — первое, что нужно увидеть. docker logs выглядит просто, но под капотом работает разные драйверы логирования, и выбор влияет на то, как хранятся, вращаются и доступны логи. Вот что стоит знать перед тем, как доверять дефолту.
Как работает docker logs
Команда docker logs <container> читает поток stdout/stderr контейнера и выдаёт его в терминал. За этим стоит драйвер логирования — компонент, который определяет, куда именно пишутся данные. По умолчанию это json-file: каждый контейнер получает JSON-файл на хосте, в который записываются все строки вывода.
docker logs не читает логи изнутри контейнера напрямую — он обращается к драйверу, который уже хранит эти данные в своём формате и месте.
Драйвер настраивается на уровне демона Docker или отдельного контейнера. Выбор влияет на вращение файлов, доступ к логам из journalctl, интеграцию с централизованными системами сбора.
Драйвер json-file (по умолчанию)
json-file — встроенный драйвер без зависимостей. Каждый контейнер создаёт файл вида /var/lib/docker/containers/<container-id>/<container-id>-json.log. Формат — JSON-линии: каждая строка содержит log, stream (stdout или stderr), time.
Вращение контролируется двумя флагами:
| Флаг | Описание |
|---|---|
max-size | Максимальный размер одного файла лога (например, 10m) |
max-file | Количество хранимых ротированных файлов |
Без этих флагов файлы растут без ограничений. На продакшене это прямой путь к заполнению диска.
Если max-size и max-file не заданы явно, Docker не ограничивает размер логов. На хосте с множеством контейнеров это выльется в неожиданный дефицит места.
Читать логи можно через docker logs, а также напрямую по пути на хосте — но второй способ не рекомендуется, так как файлы могут быть заняты демоном.
Драйвер journald
journald отправляет логи контейнеров в системный журнал systemd. Это значит, что логи доступны через journalctl, поддерживаются все механизмы вращения и сжатия journald, и нет отдельных JSON-файлов, разрастающихся на диске.
Для работы нужен systemd и пакет systemd-journal-remote (в некоторых дистрибутивах). Контейнер должен запускаться с указанием драйвера:
Флаг tag задаёт идентификатор в journald — без него будет пустая строка, и найти нужный контейнер будет сложно. Шаблон {{.Name}} подставляет имя контейнера.
Используйте tag={{.Name}} или tag={{.ID}}, чтобы логи из journald были сразу привязаны к конкретному контейнеру. Без тега фильтрация по CONTAINER_NAME не работает.
Чтение логов:
Точнее — через фильтры journald:
Реальная фильтрация зависит от того, какие метаданные Docker передаёт в journald. Проверьте journalctl -o verbose для конкретного контейнера, чтобы увидеть доступные поля.
Сравнение json-file и journald
| Параметр | json-file | journald |
|---|---|---|
| Место хранения | /var/lib/docker/containers/... | /var/log/journal/ |
| Вращение | Через --log-opt | Через journald.conf |
| Поиск | docker logs --since, grep | journalctl --grep, --since |
| Зависимости | Нет | systemd |
| Централизация | Через fluentd, gelf, awslogs | Через journalctl --remote или forward |
| Сжатие | Нет (ручное) | Да, настраивается в journald.conf |
| Доступ без Docker | Прямой доступ к файлам | Только через journalctl |
journald не поддерживает все log-opt, доступные для json-file. Например, max-size и max-file не работают — вращение контролируется настройками самого journald (SystemMaxUse, SystemMaxFileSize и т.д.).
Настройка драйвера в daemon.json
Глобальная настройка делается в /etc/docker/daemon.json:
После изменения перезапустите Docker:
Изменение драйвера в daemon.json влияет на все новые контейнеры. Уже запущенные контейнеры продолжат использовать свой текущий драйвер до перезапуска.
Для контейнера можно переопределить через --log-driver и --log-opt при запуске — это имеет приоритет над настройками демона.
Если нужно проверить текущий драйвер конкретного контейнера:
Практические рекомендации
Для локальной разработки json-file с заданными max-size и max-file — достаточен и прост в использовании. Для продакшена с десятками контейнеров на одном хосте journald предпочтительнее: единое пространство поиска, встроенное сжатие, интеграция с systemd и мониторингом.
Если вы уже используете systemd для оркестрации контейнеров (через systemd unit-файлы или Podman), journald — естественный выбор. Логи контейнеров и сервисов окажутся в одном месте.
Если нужна централизованная сборка — оба драйвера поддерживают forward-логов через промежуточные драйверы (fluentd, gelf, splunk). Но journald добавляет дополнительный этап: сначала в journald, потом forwarder. Для простых случаев прямой json-file + fluentd может быть короче пути.
Проверяйте дисковое пространство регулярно, независимо от драйвера. journalctl --disk-usage и du -sh /var/lib/docker/containers/*/ — минимальный набор для мониторинга.