Перейти к содержимому

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Количество хранимых ротированных файлов

Без этих флагов файлы растут без ограничений. На продакшене это прямой путь к заполнению диска.

docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 nginx
Предупреждение

Если max-size и max-file не заданы явно, Docker не ограничивает размер логов. На хосте с множеством контейнеров это выльется в неожиданный дефицит места.

Читать логи можно через docker logs, а также напрямую по пути на хосте — но второй способ не рекомендуется, так как файлы могут быть заняты демоном.

Драйвер journald

journald отправляет логи контейнеров в системный журнал systemd. Это значит, что логи доступны через journalctl, поддерживаются все механизмы вращения и сжатия journald, и нет отдельных JSON-файлов, разрастающихся на диске.

Для работы нужен systemd и пакет systemd-journal-remote (в некоторых дистрибутивах). Контейнер должен запускаться с указанием драйвера:

docker run --log-driver journald --log-opt tag={{.Name}} nginx

Флаг tag задаёт идентификатор в journald — без него будет пустая строка, и найти нужный контейнер будет сложно. Шаблон {{.Name}} подставляет имя контейнера.

Подсказка

Используйте tag={{.Name}} или tag={{.ID}}, чтобы логи из journald были сразу привязаны к конкретному контейнеру. Без тега фильтрация по CONTAINER_NAME не работает.

Чтение логов:

journalctl -u docker --grep="nginx"
journalctl --user-console -t docker --since "1 hour ago"

Точнее — через фильтры journald:

journalctl -t docker -g "nginx" --since "2024-01-01"

Реальная фильтрация зависит от того, какие метаданные Docker передаёт в journald. Проверьте journalctl -o verbose для конкретного контейнера, чтобы увидеть доступные поля.

Сравнение json-file и journald

Параметрjson-filejournald
Место хранения/var/lib/docker/containers/.../var/log/journal/
ВращениеЧерез --log-optЧерез journald.conf
Поискdocker logs --since, grepjournalctl --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:

{
  "log-driver": "journald",
  "log-opts": {
    "tag": "{{.Name}}"
  }
}

После изменения перезапустите Docker:

sudo systemctl restart docker
Примечание

Изменение драйвера в daemon.json влияет на все новые контейнеры. Уже запущенные контейнеры продолжат использовать свой текущий драйвер до перезапуска.

Для контейнера можно переопределить через --log-driver и --log-opt при запуске — это имеет приоритет над настройками демона.

Если нужно проверить текущий драйвер конкретного контейнера:

docker inspect --format='{{.HostConfig.LogConfig.Type}}' <container>

Практические рекомендации

Для локальной разработки 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/*/ — минимальный набор для мониторинга.