
Логи Docker: stdout, logging driver и безопасная ротация
Настраиваем журналы контейнеров без переполнения диска: выбираем logging driver, задаём max-size и max-file, читаем события и проверяем новые контейнеры.
Содержание
Контейнер может работать исправно и одновременно заполнять диск журналом. Docker получает обычный вывод программы из двух потоков: stdout для сообщений о работе и stderr для ошибок. Затем logging driver — выбранный механизм хранения журналов — записывает эти строки на диск или передаёт внешней системе. Ротация ограничивает размер и число старых файлов, чтобы журнал не занял всё свободное место.
Как не дать журналу заполнить диск
Пишите оперативные события приложения в stdout и stderr, выясните фактический logging driver и задайте ему пределы ротации. Для одного Compose-сервиса удобно настроить logging.driver: local и строковые параметры max-size и max-file. Не редактируйте внутренние файлы Docker вручную и помните: изменение default daemon не переносится на уже созданные контейнеры.
Разделите журналы по назначению
В стандартные потоки полезно отправлять события, необходимые для эксплуатации:
- запуск и корректную остановку;
- ошибки запросов и фоновых задач;
- идентификатор запроса или операции;
- длительность и итог без чувствительных данных;
- предупреждения о приближении к внутренним лимитам.
Не записывайте пароли, токены, session cookies, полные строки подключения и тела запросов по умолчанию. Журнал не становится безопасным только потому, что находится внутри Docker host.
Аудит, метрики и трассировки решают отдельные задачи. docker logs удобен для оперативной диагностики одного экземпляра, но не является долгосрочным централизованным хранилищем с поиском и политикой доступа.
Узнайте, где Docker хранит журнал
Первая команда выполняется на хосте с Docker и показывает механизм журналирования, который получат новые контейнеры по умолчанию:
docker info --format 'default={{.LoggingDriver}}'
Следующая команда проверяет уже созданный контейнер example-app. Она выводит сохранённый при его создании драйвер и параметры:
docker inspect example-app \
--format 'driver={{.HostConfig.LogConfig.Type}} options={{json .HostConfig.LogConfig.Config}}'
Контейнер сохраняет параметры, с которыми был создан. Поэтому его driver может отличаться от текущего default.
Проверьте журнал без бесконечного вывода:
docker logs --tail 100 --timestamps example-app
docker logs --since 15m example-app
docker logs --follow --tail 50 example-app
Ctrl+C завершает только просмотр --follow. Если строки отсутствуют, убедитесь, что приложение действительно пишет в stdout/stderr и выбранный driver поддерживает чтение командой docker logs.
Настройте ротацию для Compose-сервиса
Driver local хранит журналы в оптимизированном внутреннем формате и по умолчанию использует ротацию и сжатие. Явные значения делают намерение проекта заметным:
services:
web:
image: example/web:tested
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
Числа приведены как пример, а не универсальная норма. Оцените обычный поток строк, время расследования и свободное место. Слишком маленькое окно сотрёт причину редкой ошибки до того, как вы её заметите.
Проверьте и примените конфигурацию:
docker compose config
docker compose up -d --force-recreate web
docker compose ps web
docker inspect "$(docker compose ps -q web)" \
--format '{{json .HostConfig.LogConfig}}'
--force-recreate прерывает старый экземпляр, поэтому на рабочем сервисе планируйте окно или используйте безопасный способ замены, поддерживаемый вашей архитектурой.
Если нужен json-file
json-file часто является default driver. Без max-size его файл может расти без ротации. Для отдельного контейнера:
docker run -d --name log-demo \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=3 \
alpine:3.22 sh -c 'while :; do date -u; sleep 5; done'
Параметр max-file работает только вместе с max-size. В daemon.json значения options должны быть строками:
{
"log-driver": "local",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
Глобальное изменение затрагивает все будущие контейнеры и требует обслуживания daemon. Перед ним проверьте существующий /etc/docker/daemon.json, валидность JSON и совместимость других настроек. Не заменяйте файл целиком фрагментом из статьи.
После изменения default потребуется контролируемый restart Docker по инструкции вашей ОС, а затем пересоздание контейнеров. Простая перезагрузка daemon не меняет LogConfig уже созданных экземпляров.
Не работайте с внутренним файлом напрямую
Для json-file Docker хранит журналы в каталоге данных daemon. Не открывайте эти файлы на запись, не обрезайте их через shell и не настраивайте внешний logrotate поверх них. Их форматом и жизненным циклом управляет Docker.
Если диск уже заполнен, сначала сохраните диагностику:
docker system df
docker ps --size
sudo du -x -h /var/lib/docker 2>/dev/null | sort -h | tail
Последняя команда требует прав и используется только для оценки каталогов, не для удаления. Выясните источник роста, настройте ограничение и пересоздайте конкретный контейнер. Массовая очистка может удалить нужные образы, кеши и volumes, но не исправит причину непрерывного потока.
Пишите по одному событию в строке
Одна строка должна описывать одно событие. Структурированный JSON удобен, если последующий сборщик умеет его разбирать, но не вкладывайте JSON-строку в несколько дополнительных оболочек. Полезные поля:
- стабильное имя события;
- уровень;
- UTC timestamp, если его не добавляет транспорт;
- request ID или job ID;
- длительность;
- безопасный итог операции.
Не используйте уровень error для штатных ответов клиента и не печатайте stack trace на каждую ожидаемую ошибку валидации. Иначе важные события теряются в шуме, а ротация происходит быстрее.
Проверка после изменения
- Сгенерируйте несколько безопасных тестовых событий.
- Убедитесь, что
docker logs --tailих показывает. - Проверьте
HostConfig.LogConfigнового контейнера. - Наблюдайте расход диска в течение типичной нагрузки.
- Проверьте, что алерт о свободном месте приходит раньше критического заполнения.
- Убедитесь, что секреты не попадают в обычный и ошибочный путь.
Для отката верните предыдущий блок logging, проверьте docker compose config и пересоздайте только сервис. Старые внутренние файлы не конвертируются в новый формат автоматически.
Команды чтения и фильтрации разобраны в статье о docker logs и inspect. Ограничение самого процесса рассматривается в материале о CPU и памяти, а полный стек удобно описывать через Compose.
Источники
Самопроверка
Проверьте, что материал усвоен
Ответьте на все вопросы. Результат сохранится только в этом браузере и будет учтён в статистике прочитанных материалов.
Разбираем коротко
Частые вопросы
Почему docker logs не показывает журнал контейнера?
Команда зависит от выбранного logging driver и его поддержки чтения. Также приложение могло писать в собственный файл вместо stdout и stderr. Сначала проверьте LogConfig контейнера.
Применится ли новый logging driver к уже работающим контейнерам?
Нет. Изменение настройки daemon влияет на вновь создаваемые контейнеры. Существующие экземпляры нужно контролируемо пересоздать и проверить после изменения.
Можно ли читать файлы json-file напрямую из каталога Docker?
Не следует. Docker предупреждает, что этими файлами управляет daemon; внешнее изменение может нарушить работу logging system. Используйте docker logs или поддерживаемый сборщик.


