Почему контейнерные логи внезапно забивают диск
Частый сценарий: сервис внутри контейнера начинает активно писать в 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

Вариант 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-size10–50m иmax-file3–10.Помните, что лимит применяется на контейнер. Пример оценки: 40 контейнеров × 20m × 5 файлов = около 4 ГБ только под json-логи.
Если вам нужна история логов «на недели», не раздувайте лимиты бесконечно — лучше вывозить логи централизованно, а на хосте оставлять небольшое окно.
Вариант 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
Docker logs и Podman logs: что меняется при выборе драйвера
Команды docker logs и podman logs остаются привычной точкой входа для разработчика, но поведение зависит от драйвера:
С
json-fileвывод обычно быстрый и предсказуемый, но чтение гигантских логов может быть тяжёлым.С
journaldвы выигрываете в лимитах и фильтрации, но полезно заранее договориться о том, как искать нужные события (по времени, юниту, имени контейнера, меткам).В Podman rootless на systemd чаще проще жить с journald: модель «юнит +
journalctl» получается естественной.
Если хочется углубиться в безопасность контейнерной изоляции, полезно держать под рукой разбор про изоляцию контейнеров (gVisor и Firecracker): иногда рост логов становится симптомом проблем, которые лучше купировать на уровне архитектуры и ограничений.

Типовые анти-паттерны, из-за которых 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.
Чек-лист: безопасная настройка логирования контейнеров на одном сервере
Выберите стратегию:
json-fileсmax-size/max-fileилиjournaldс лимитами journald.Проверьте, что приложения пишут в stdout/stderr, а не только в файлы.
Оцените суммарный потолок логов: лимит на контейнер × количество контейнеров.
Добавьте мониторинг: свободное место, рост
/var/lib/docker, выводjournalctl --disk-usage.Заранее подготовьте команды для аварийной чистки (ниже) и процедуру пересоздания контейнеров.
Для сетевых проблем, которые часто провоцируют «бурю логов» (ретраи, 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-лимиты, и разметку диска под логи.


