Выберите продукт

Docker and Podman logging: json-file, logrotate and journald without disk full

Контейнерные логи легко забивают диск: json-file растёт без лимитов, logrotate может не освобождать место, journald копит больше ожидаемого. Разбираем диагностику, настройку max-size/max-file, лимиты journald и аварийные команды.
Docker and Podman logging: json-file, logrotate and journald without disk full

Почему контейнерные логи внезапно забивают диск

Частый сценарий: сервис внутри контейнера начинает активно писать в stdout/stderr (включили debug, посыпались ретраи к БД, приложение логирует каждую 404/500), и через несколько часов на хосте заканчивается место. Дальше по цепочке начинают падать базы, не создаются временные файлы, ломаются деплои — классический инцидент disk full.

Базовая механика простая: Docker/Podman забирают stdout/stderr контейнера и сохраняют на хосте. А вот куда именно и как ограничивается рост — зависит от выбранного драйвера логирования.

Ниже — три практических варианта, которые чаще всего встречаются на одиночных серверах и небольших продакшенах: Docker json-file с встроенной ротацией, logrotate для файловых логов в volume и journald как системный способ с лимитами хранения.

Быстрая диагностика: где лежат логи и кто «толстеет»

Docker: проверяем драйвер и путь к логам

Проверьте, какой драйвер включён у демона и у конкретного контейнера:

docker info --format '{{.LoggingDriver}}'
docker inspect -f '{{.HostConfig.LogConfig.Type}}' CONTAINER

Если это json-file, то логи обычно лежат по пути:

/var/lib/docker/containers/<container-id>/<container-id>-json.log

Оценить, кто самый «шумный» (осторожно на больших объёмах), можно так:

sudo find /var/lib/docker/containers -name '*-json.log' -printf '%s %p
' 2>/dev/null | sort -n | tail -20

Podman: где смотреть настройки и логи

Podman часто используется rootless и опирается на systemd. На практике вы встретите либо journald, либо файловое логирование типа k8s-file/json-file-подобного.

Посмотреть тип логирования у контейнера:

podman inspect --format '{{.HostConfig.LogConfig.Type}}' CONTAINER

Чтение логов «по-старому»:

podman logs --tail 50 CONTAINER

Если используется journald, для быстрой проверки можно начать с общего просмотра по podman (фильтры зависят от ОС и способа запуска):

journalctl -t podman --no-pager -n 50

Диагностика: проверка драйвера логирования Docker и поиск самых больших json логов

Вариант 1: Docker json-file — просто, но требует ограничений

json-file удобен тем, что работает «из коробки», а docker logs быстро показывает stdout/stderr. Главный минус — файл будет расти бесконечно, если вы не задали ротацию.

Для продакшена почти всегда достаточно включить встроенные ограничения по размеру (max-size) и количеству файлов (max-file). Это именно ротация Docker, не logrotate.

Глобально через daemon.json

Откройте конфиг демона Docker (обычно /etc/docker/daemon.json) и задайте параметры:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "5"
  }
}

Примените изменения:

sudo systemctl restart docker

Важно: изменения гарантированно применятся для новых контейнеров. Уже созданные контейнеры могут продолжить работать со старыми опциями — это типовой источник сюрпризов.

Точечно для контейнера и compose

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

docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=5 IMAGE

Для Docker Compose (показываю как текст):

logging:
  driver: json-file
  options:
    max-size: "10m"
    max-file: "5"

Как выбрать значения max-size/max-file

  • Для веб-приложений часто хватает max-size 10–50m и max-file 3–10.

  • Помните, что лимит применяется на контейнер. Пример оценки: 40 контейнеров × 20m × 5 файлов = около 4 ГБ только под json-логи.

  • Если вам нужна история логов «на недели», не раздувайте лимиты бесконечно — лучше вывозить логи централизованно, а на хосте оставлять небольшое окно.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Вариант 2: logrotate для контейнерных логов — когда он нужен и почему опасен для docker json

logrotate — привычный инструмент админа, но с docker json-логами есть нюанс: Docker держит файловый дескриптор открытым. Если вы просто переименуете/сожмёте лог, Docker может продолжить писать в старый inode, и место на диске не освободится, пока Docker не переоткроет файл.

Для Docker с json-file почти всегда правильнее включить встроенные max-size/max-file, чем «крутить» logrotate вокруг -json.log.

Когда logrotate уместен

  • Когда приложение пишет логи в файлы в volume (например, /srv/myapp/logs/app.log на хосте).

  • Когда приложение пишет в файл и умеет переоткрывать лог по сигналу; тогда можно делать ротацию без copytruncate (идеальный вариант, но зависит от приложения).

  • Когда «быстро и просто» важнее идеальной точности, можно применить copytruncate, понимая риск потери строк на границе ротации.

Пример logrotate для логов приложения в volume

Допустим, контейнер пишет в /srv/myapp/logs/app.log на хосте. Создайте правило в /etc/logrotate.d/myapp:

/srv/myapp/logs/*.log {
  daily
  rotate 14
  missingok
  notifempty
  compress
  delaycompress
  copytruncate
}

Если место на диске критично, дополнительно продумайте лимиты на уровне ФС (отдельный раздел под логи, квоты) — это часто надёжнее, чем надеяться на «правильное поведение» одного инструмента.

Вариант 3: journald — системный подход и дисциплина хранения

Когда Docker использует journald (или Podman изначально пишет в journald), логи попадают в systemd-journal. Плюсы: централизованное хранение, удобные фильтры, понятные лимиты по диску, интеграция с пересылкой. Минусы: бинарный формат (работать нужно через journalctl) и риск избыточной нагрузки по I/O при очень «шумных» контейнерах.

Переключаем Docker на journald

В /etc/docker/daemon.json укажите драйвер:

{
  "log-driver": "journald"
}

Перезапустите Docker:

sudo systemctl restart docker

Проверка:

docker info --format '{{.LoggingDriver}}'

Смотреть логи контейнера можно через привычный интерфейс:

docker logs --tail 50 CONTAINER

Но если нужны системные фильтры (по времени, по юниту, по полям), используйте journalctl. Для инфраструктуры на systemd это часто удобнее, особенно когда контейнеры запускаются как сервисы.

Как ограничить рост journald, чтобы не получить disk full

Ограничения задаются в /etc/systemd/journald.conf или drop-in файле в /etc/systemd/journald.conf.d/. Практически важные параметры:

  • SystemMaxUse — максимальный объём журналов на диске.

  • SystemKeepFree — сколько места journald должен оставлять свободным.

  • RuntimeMaxUse — лимит для volatile-журнала (если храните в tmpfs).

  • MaxRetentionSec — ограничение по времени хранения.

Пример «безопасного» ориентира (подберите под свой диск и профиль нагрузок):

[Journal]
SystemMaxUse=2G
SystemKeepFree=1G
MaxRetentionSec=7day

Применение:

sudo systemctl restart systemd-journald

Проверка текущего размера:

journalctl --disk-usage

Быстрый «вакуум» при инциденте:

sudo journalctl --vacuum-size=1G
sudo journalctl --vacuum-time=7d
Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Docker logs и Podman logs: что меняется при выборе драйвера

Команды docker logs и podman logs остаются привычной точкой входа для разработчика, но поведение зависит от драйвера:

  • С json-file вывод обычно быстрый и предсказуемый, но чтение гигантских логов может быть тяжёлым.

  • С journald вы выигрываете в лимитах и фильтрации, но полезно заранее договориться о том, как искать нужные события (по времени, юниту, имени контейнера, меткам).

  • В Podman rootless на systemd чаще проще жить с journald: модель «юнит + journalctl» получается естественной.

Если хочется углубиться в безопасность контейнерной изоляции, полезно держать под рукой разбор про изоляцию контейнеров (gVisor и Firecracker): иногда рост логов становится симптомом проблем, которые лучше купировать на уровне архитектуры и ограничений.

Настройка лимитов journald и проверка размера журналов командой journalctl

Типовые анти-паттерны, из-за которых max-size/max-file «не спасли»

1) Настроили daemon.json, но старые контейнеры продолжают раздувать логи

Опции логирования фиксируются при создании контейнера. Если вы поменяли конфиг демона, но контейнеры не пересоздали, они могут продолжать писать без ротации (или со старыми значениями). План: обновить compose/юниты и пересоздать контейнеры в окно обслуживания.

2) Логи идут не в stdout/stderr, а в файлы внутри контейнера

Тогда ни json-file, ни journald не помогут: Docker/Podman видят только stdout/stderr. Для файловых логов выносите директорию в volume и применяйте logrotate на хосте, либо настраивайте ротацию на уровне приложения (если иначе нельзя).

3) Агрессивное debug-логирование и отсутствие ограничителей

Если приложение способно выдать гигабайты логов за час, ротация — это предохранитель, но не лечение. На практике помогают:

  • уровни логирования и rate limiting (в приложении или библиотеке логирования);

  • отсечение бесконечных stacktrace и повторяющихся сообщений;

  • централизованный сбор логов с разумной политикой retention.

Чек-лист: безопасная настройка логирования контейнеров на одном сервере

  1. Выберите стратегию: json-file с max-size/max-file или journald с лимитами journald.

  2. Проверьте, что приложения пишут в stdout/stderr, а не только в файлы.

  3. Оцените суммарный потолок логов: лимит на контейнер × количество контейнеров.

  4. Добавьте мониторинг: свободное место, рост /var/lib/docker, вывод journalctl --disk-usage.

  5. Заранее подготовьте команды для аварийной чистки (ниже) и процедуру пересоздания контейнеров.

Для сетевых проблем, которые часто провоцируют «бурю логов» (ретраи, timeouts), пригодится шпаргалка про Docker и firewall (iptables/nftables): иногда корень инцидента именно в сетевых правилах, а не в логировании.

Команды на случай инцидента disk full из-за логов

Найти крупные docker json logs

sudo find /var/lib/docker/containers -name '*-json.log' -printf '%s %p
' 2>/dev/null | sort -n | tail -30

Экстренно обнулить конкретный файл (временная мера, причину не лечит):

sudo sh -c ': > /var/lib/docker/containers/<id>/<id>-json.log'

Почистить journald до заданного размера или времени

journalctl --disk-usage
sudo journalctl --vacuum-size=1G
sudo journalctl --vacuum-time=3d

Что выбрать: json-file или journald

Если нужен максимально простой вариант для одного сервера и привычный docker logs — оставляйте json-file, но обязательно задавайте max-size и max-file. Это закрывает большинство ситуаций «внезапно кончилось место».

Если инфраструктура сильно завязана на systemd, много rootless Podman, и важны дисциплина хранения и лимиты «по-умолчанию», чаще выигрывает journald с аккуратно настроенными параметрами в journald.conf.

logrotate оставьте для случаев, когда логи — это обычные файлы в volume (или на хосте) и вы контролируете ротацию как для любого другого сервиса.

Итог

Контейнерные логи — одна из самых частых причин неожиданного disk full. Настраивайте ротацию там, где она действительно работает: для Docker json-file — через max-size/max-file; для journald — через лимиты systemd-journal; для файловых логов в volume — через logrotate с пониманием компромиссов. Тогда docker logs и podman logs останутся удобными для дебага, а хост перестанет быть заложником бесконечных логов.

Если вы разворачиваете контейнеры на отдельном сервере, удобно держать сервисы на VDS, где вы контролируете и Docker, и systemd-лимиты, и разметку диска под логи.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: duplicate address detected, DAD failed IPv6 — причины и исправление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: duplicate address detected, DAD failed IPv6 — причины и исправление

Сообщения duplicate address detected и DAD failed в Debian/Ubuntu означают, что IPv6-адрес не прошёл проверку уникальности в локал ...
Debian/Ubuntu: как исправить swapoff: Device or resource busy при отключении swap OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить swapoff: Device or resource busy при отключении swap

Ошибка swapoff: Device or resource busy в Debian и Ubuntu обычно связана не с «битым» swap, а с нехваткой RAM, zram, автоподключен ...
Debian/Ubuntu: как исправить cloud-init status: error после first boot на VDS OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить cloud-init status: error после first boot на VDS

Если на Debian или Ubuntu после первого запуска или клонирования VDS вы видите cloud-init status: error, причина обычно в datasour ...