Переполненный диск из‑за логов контейнеров — один из самых частых «внезапных» инцидентов на серверах с Docker. Сценарий типовой: приложение начинает активно писать в stdout/stderr, Docker складывает всё в файл, ротации нет (или она настроена только в logrotate на хосте и не затрагивает контейнерные логи), и через несколько часов или дней вы ловите переполнение раздела, падение сервисов и ошибки записи в файловую систему.
Ниже — практическая инструкция: как устроены log driver в Docker, как включить json-file log rotation параметрами max-size и max-file, что меняется при переходе на journald и когда уместен fluentd. В конце — диагностика, безопасная уборка и чек-лист выбора.
Как Docker хранит логи и почему это приводит к переполнению диска
По умолчанию Docker использует драйвер логирования json-file. Это означает:
- всё, что контейнер пишет в stdout/stderr, Docker пишет в файлы на хосте;
- файлы лежат внутри каталога данных Docker (обычно
/var/lib/docker); - если ротация не включена, файл растёт без ограничений.
Ключевой момент: многие админы считают, что «у меня же есть logrotate». Но классические правила logrotate для /var/log не управляют логами Docker автоматически. В итоге контейнеры начинают «втихаря» раздувать /var/lib/docker, пока не упрётесь в 100%.
Где именно лежат логи при json-file
Файлы логов контейнера находятся по пути вида:
/var/lib/docker/containers/<container-id>/<container-id>-json.log
Если Docker‑директория на том же разделе, что и система или данные приложений, один «болтливый» контейнер способен положить весь узел.
Быстрая диагностика: кто съел место и сколько
Сначала подтверждаем, что проблема действительно в логах Docker, и оцениваем масштаб.
Проверить общий disk usage
df -h
Если / или /var близки к 100%, переходим к Docker.
Оценить общий размер Docker
docker system df
Команда покажет объёмы по образам, контейнерам, volumes и build cache. Но файлы логов json-file не всегда очевидны в этой сводке, поэтому дополнительно проверяем директорию контейнеров.
Найти самые большие файлы *-json.log
sudo du -ah /var/lib/docker/containers | sort -h | tail -n 30
Обычно сразу видно один или несколько файлов *-json.log на гигабайты.
Связать container-id с именем контейнера
docker ps --no-trunc
Либо точечно:
docker inspect --format '{{.Name}} {{.Id}}' <container-id>
Важно: если просто удалить файл лога, Docker может продолжать писать в «удалённый» inode, и место не освободится до перезапуска контейнера или демона. Поэтому «rm и всё» — частая причина, почему место так и не вернулось.

Правильное решение №1: json-file log rotation (max-size/max-file)
Если вам подходит хранение логов на диске и вы привыкли смотреть их через docker logs, самый простой и популярный вариант — включить ротацию для json-file.
Включить ротацию глобально в daemon.json
Откройте (или создайте) файл:
/etc/docker/daemon.json
Пример конфигурации:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Смысл параметров:
max-size— максимальный размер одного файла перед ротацией;max-file— сколько файлов хранить (старые будут удаляться).
Перезапустите Docker:
sudo systemctl restart docker
Учтите: глобальная настройка применяется к новым контейнерам. Уже запущенные продолжат работать со старыми параметрами, пока вы их не пересоздадите (или не смените драйвер через пересоздание сервиса в Compose/Swarm).
Настроить ротацию для конкретного контейнера
Если глобально менять политику нельзя, задайте опции на уровне контейнера:
docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=5 your-image
В Docker Compose это выглядит так (YAML):
services:
app:
image: your-image
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "5"
Практичные пресеты max-size/max-file
- большинство веб‑приложений:
max-size10–50m,max-file3–10; - «шумные» воркеры/очереди:
max-size50–200m,max-file2–5; - на время отладки: увеличивайте окно (обычно
max-file), но держите диск под мониторингом.
Что будет с docker logs
docker logs продолжит работать, но история ограничится тем, что поместилось в окно ротации. Это нормальный и полезный компромисс между «посмотреть хвост» и гарантировать живой диск.
Если у вас небольшой диск, заранее планируйте место под Docker-данные и логи. На VDS обычно проще выделить отдельный объём под /var/lib/docker и не ловить сюрпризы от «лог‑шторма».
Независимо от выбранного драйвера логирования, добавьте мониторинг заполнения файловых систем и алерты хотя бы на 80% и 90% — это почти всегда дешевле, чем аварийная уборка в разгар инцидента.
Правильное решение №2: journald как драйвер логирования
Если у вас Linux с systemd, часто разумнее отправлять контейнерные логи в journald. Тогда Docker не управляет файлами логов напрямую, а вы используете уже знакомые политики хранения журнала.
Плюсы journald
- централизованные лимиты (по размеру, времени, свободному месту);
- фильтрация через
journalctl, удобнее разбирать инциденты «на хосте»; - меньше риска, что один контейнер раздует один монолитный файл.
Минусы journald
- логи становятся «системными»: привычные пайплайны, которые читают файлы, могут не подойти;
- если journald не ограничен, проблема просто переедет в журнал.
Как включить journald в Docker
В /etc/docker/daemon.json:
{
"log-driver": "journald"
}
Перезапуск:
sudo systemctl restart docker
Базовый просмотр:
journalctl -u docker --no-pager -n 200
Также можно продолжать использовать docker logs, но поведение зависит от версии Docker и сборки.
Обязательная часть: лимиты journald
Проверьте параметры в /etc/systemd/journald.conf. На практике чаще всего нужны:
SystemMaxUse— верхний предел диска под журнал;SystemKeepFree— сколько места всегда оставлять свободным;MaxRetentionSec— ограничение по времени хранения;SystemMaxFileSize— максимальный размер сегмента.
После изменений перезапустите journald:
sudo systemctl restart systemd-journald

Правильное решение №3: fluentd для централизованного сбора
Когда контейнеров много, нужна единая политика и поиск по логам, обычно переходят к централизованному сбору. В Docker для этого часто используют fluentd как log driver.
Когда fluentd оправдан
- нужны поиск, алерты и дашборды по логам;
- нужно хранение дольше, чем позволяет локальный диск;
- нужно обогащение метаданными (имя контейнера, labels, node).
Риски и нюансы fluentd
- логирование зависит от доступности fluentd: при проблемах возможны задержки или потери (зависит от режима и буферов);
- нужно продумать backpressure и буферизацию, иначе «лог‑шторм» ударит по CPU/сети.
Минимальная настройка fluentd
Глобально в daemon.json (пример):
{
"log-driver": "fluentd",
"log-opts": {
"fluentd-address": "127.0.0.1:24224",
"tag": "docker.{{.Name}}"
}
}
Дальше на стороне fluentd настраиваются буферы, очереди и доставка в целевое хранилище.
Почему не стоит настраивать logrotate на *-json.log
Иногда пытаются написать правила logrotate для *-json.log. На практике это часто даёт нестабильный результат и неприятные эффекты:
- Docker держит файл открытым; переименование не гарантирует освобождение места;
copytruncateможет обрезать лог в момент записи, ломая JSON‑структуру;- при высокой нагрузке возможны гонки между Docker и logrotate.
Если вы остаетесь на json-file — включайте нативную ротацию max-size/max-file. Если нужна системная политика — используйте journald. Если нужен сбор «в одно место» — fluentd и корректная буферизация.
Если параллельно усиливаете безопасность контейнерного хоста, пригодится разбор: Docker, iptables и nftables: что происходит с правилами фаервола.
Что делать, если диск уже заполнен логами (аварийный план)
Когда места нет, цель — быстро вернуть возможность записи на диск, а затем внедрить постоянную политику.
1) Найти топ по объёму и определить виновника
sudo du -h /var/lib/docker/containers/*/*-json.log 2>/dev/null | sort -h | tail -n 20
2) Временно освободить место безопасно
Самый безопасный путь — пересоздать контейнер с включённой ротацией и (если нужно) временно снизить уровень логирования приложения. Если нужно «прямо сейчас» и контейнер можно перезапустить, можно обнулить файл (не удалять):
sudo truncate -s 0 /var/lib/docker/containers/<container-id>/<container-id>-json.log
Затем перезапустить контейнер:
docker restart <container-id>
После этого обязательно внедрите постоянное решение (ротация или смена драйвера), иначе инцидент повторится.
3) Проверить, не держатся ли удалённые файлы
Если ранее логи удалялись через rm, место могло не вернуться. Проверка:
sudo lsof +L1 | grep /var/lib/docker | head
Если видите строки с deleted и большим размером, помогает перезапуск соответствующего процесса (часто dockerd или конкретного контейнера).
Чек-лист: как выбрать log driver под вашу задачу
- Нужно просто и привычно, логи смотрим через docker logs →
json-file+max-size/max-file. - Нужны единые лимиты на хосте и «системный» подход →
journald+ настройкиjournald.conf. - Нужен централизованный сбор, поиск, долгий ретеншн →
fluentd(или аналог) + продуманная доставка и буферы.
Минимальный продовый стандарт для одного сервера
Если вы администрируете 1–несколько Docker‑хостов без полноценного лог‑стека, практичный минимум обычно такой:
- оставить
json-file, но включить ротацию:max-size10–50m иmax-file5–10; - держать
/var/lib/dockerна разделе с понятным запасом и мониторить заполнение; - добавить алерты по диску хотя бы на 80% и 90%;
- для особо шумных сервисов — снижать уровень логирования приложения и ограничивать спам по ошибкам.
На практике это закрывает главную боль: переполнение диска из‑за контейнерных логов перестаёт быть регулярной неожиданностью, а расход места становится прогнозируемым.
Если Docker‑хостов становится больше, чем «пара серверов», имеет смысл заранее продумать масштабирование: отдельные диски под данные, понятные лимиты и ресурсные резервы. В таких сценариях часто удобнее разворачивать окружения на VDS с предсказуемыми ресурсами и возможностью быстро увеличить объём.
Проверка после внедрения
После включения ротации или смены драйвера проверьте:
- что новые контейнеры действительно получили нужный log driver;
- что логи доступны инженерам (через
docker logsилиjournalctl); - что рост потребления диска стал ограниченным;
- что при перезапусках не теряются важные диагностические события (критичные события лучше отправлять отдельным каналом).
Проверить драйвер у контейнера можно так:
docker inspect --format '{{.HostConfig.LogConfig.Type}} {{json .HostConfig.LogConfig.Config}}' <container-name-or-id>
Если хотите, следующий шаг — подобрать значения max-size и max-file от расчёта: по средней скорости логирования, допустимому окну хранения и реальному размеру диска/раздела.


