Когда логи Docker переполняют диск: кейс-стади и решение
Автор: Javohir Abdullayev · · Сервер и DevOps

Введение: Неожиданный сбой на сервере
Представьте: в выходной день поздно ночью поступает тревожное сообщение от клиента или системы мониторинга. Сайт недоступен, API возвращает ошибку 500 или 502, а база данных не принимает запросы. Вы подключаетесь к VPS по SSH и первое, что видите: No space left on device. Диск заполнен на 100%.
На сервере работали всего лишь одно веб-приложение на Django, контейнеры с PostgreSQL и Celery. Резкого наплыва пользователей не было, а тяжелые медиафайлы хранятся во внешнем сервисе S3. Что же заполнило 40 ГБ дискового пространства за несколько недель? В этой статье мы разберем реальный кейс, первопричину этой проблемы и постоянное архитектурное решение, предотвращающее ее повторение.
1. Диагностика: Кто съел весь диск?
В такой ситуации первым делом необходимо выяснить, какая директория занимает больше всего места. Проверим состояние диска в консоли сервера:
df -hВ выводе команды видно, что раздел /dev/vda1 занят на 100%. Теперь найдем главного виновника, проверив размер папок, начиная с корневой директории:
sudo du -sh /* 2>/dev/null | sort -hВ ходе проверки выяснилось, что каталог /var/lib/docker занимает целых 32 ГБ. Заглянем глубже внутрь директории Docker:
sudo du -sh /var/lib/docker/* 2>/dev/null | sort -hРезультат поражает: папка /var/lib/docker/containers/ заняла практически все свободное место. Файл [container-id]-json.log внутри каждого контейнера разросся до 10–15 ГБ.
2. Корень проблемы: Почему Docker так делает?
Docker автоматически перехватывает все сообщения, отправляемые процессами внутри контейнера в потоки stdout и stderr. По умолчанию Docker использует драйвер json-file, в котором не установлены никакие ограничения по объему.
Если в вашем приложении, например на Django или Celery, каждый HTTP-запрос, SQL-запрос или ошибка подробно выводятся в консоль, эти сообщения непрерывно записываются в один файл. Если контейнер не перезапускается месяцами, лог-файл бесконечно разрастается и съедает всю память сервера. В результате сервер не может создавать временные файлы, база данных останавливает транзакции, и вся инфраструктура выходит из строя.
3. Первая помощь: Уменьшение логов без остановки сервера
В такой ситуации многие совершают ошибку, удаляя файл лога командой rm. Этого делать нельзя! Если просто удалить открытый файл, процесс Docker продолжит удерживать его файловый дескриптор, и Linux не освободит место на диске. Файл исчезнет, но диск по-прежнему останется заполненным на 100%.
Правильный способ — обнулить размер файла без его удаления (truncate):
sudo truncate -s 0 /var/lib/docker/containers/*/*-json.logЭта команда за секунду очистит логи всех контейнеров, и сервер сразу же оживет. Сервисы возобновят работу, однако это лишь временное решение. Проблему нужно искоренить раз и навсегда.
4. Постоянное решение: Настройка ротации логов
Чтобы проблема не повторилась, необходимо установить для Docker строгое ограничение на размер логов. Это можно сделать двумя способами.
Вариант А: Глобальная настройка для всего сервера (рекомендуется)
Для применения правил ко всем новым контейнерам на сервере перейдем к конфигурационному файлу Docker:
sudo nano /etc/docker/daemon.jsonЕсли файл не существует, создадим его и внесем следующие параметры:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "20m",
"max-file": "3"
}
}Что делает эта настройка? Когда лог контейнера превышает 20 мегабайт, Docker ротирует его в новый файл. Хранится не более 3 старых файлов. Таким образом, один контейнер никогда не займет на сервере более 60 мегабайт логов. Сохраняем настройки и перезапускаем службу Docker:
sudo systemctl restart dockerВариант Б: Только для конкретных контейнеров (docker-compose.yml)
Если у вас нет прав на изменение глобальных настроек или вы хотите задать индивидуальные лимиты для каждого сервиса, можно добавить блок logging для каждой службы прямо в файле docker-compose.yml:
services:
web:
image: my-django-app:latest
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
celery_worker:
image: my-django-app:latest
logging:
driver: "json-file"
options:
max-size: "30m"
max-file: "5"5. Проактивные выводы и лучшие практики
Главные выводы из этого кейс-стади:
- Не доверяйте дефолтным настройкам на проде: Docker по умолчанию не ограничивает логи. Возьмите за правило настраивать
daemon.jsonпри конфигурировании любого нового VPS-сервера. - Правильно разделяйте уровни логирования: Убедитесь, что в продакшн-окружении установлено
DEBUG=False. Вывод лишних SQL-запросов в консоль напрасно тратит ресурсы сервера. - Настройте мониторинг диска: Настройте простой Bash-скрипт с оповещениями в Telegram или по email, либо используйте Grafana/Prometheus при заполнении диска на 80–85%. Предотвратить инцидент до его наступления — лучшая стратегия.
Теги: #Docker #DevOps #Server Sozlash #Linux #Case Study