truncate -s 0 "$(docker inspect --format '{{.LogPath}}' api)" очищает лог работающего контейнера и освобождает место сразу, без перезапуска. rm здесь применять нельзя: демон продолжает писать в удалённый файл, место не возвращается, а docker logs не работает до перезапуска контейнера.
1. Сначала понять, сколько занял docker
$ clai сколько места занимает docker→ docker system dfTYPE TOTAL ACTIVE SIZE RECLAIMABLEImages 48 14 28.88GB 20GB (69%)Containers 17 10 4.631MB 513.8kB (11%)Local Volumes 38 7 6.349GB 4.084GB (64%)Build Cache 181 0 0B 0B
Логов в этой таблице не видно вообще — строка Containers считает только слой записи. Если df показывает забитый диск, а docker system df спокоен, виноваты логи.
2. Найти контейнер, который пишет больше всех
$ clai покажи размер лог-файла каждого контейнера, по убыванию→ docker ps -q | xargs docker inspect --format '{{.LogPath}} {{.Name}}' | while read -r p n; do printf '%s\t%s\n' "$(du -h "$p" | cut -f1)" "${n#/}"; done | LC_ALL=C sort -rh | head -36.1M api3.2M worker1.9M cache
LogPath — единственный надёжный способ узнать путь: у rootful и rootless установки он разный. LC_ALL=C не украшение: в локали, где разделитель дробной части запятая, sort -h ставит 844K выше 6.1M.
3. Обрезать лог живого контейнера
$ clai очисти лог контейнера api не останавливая его→ truncate -s 0 "$(docker inspect --format '{{.LogPath}}' api)"
Контейнер продолжает писать в тот же файловый дескриптор, поток не рвётся, место возвращается немедленно. Это та самая команда, которая нужна во время инцидента.
4. Ловушка: rm вместо truncate
$ clai удали лог-файл контейнера api→ rm "$(docker inspect --format '{{.LogPath}}' api)"⚠ CAUTION — после этого docker logs не работает до перезапуска контейнера
docker logs отвечает Error grabbing logs: open …-json.log: no such file or directory, и файл сам не появляется. Демон держит удалённый файл открытым, поэтому место тоже не освобождается — вывод потерян, а проблема осталась.
5. Чтобы это не повторилось
$ clai запусти контейнер с ротацией лога по 10 мегабайт и тремя файлами→ docker run -d --log-opt max-size=10m --log-opt max-file=3 --name api alpine sleep 600
Размер одного файла, умноженный на их число, и есть потолок — здесь 30 МБ. Ставьте его каждому болтливому контейнеру.
6. Проверить, есть ли лимит у работающего контейнера
$ clai покажи настройки логирования контейнера api→ docker inspect -f '{{json .HostConfig.LogConfig}}' api{"Type":"json-file","Config":{"max-file":"3","max-size":"10m"}}
Пустой "Config":{} означает, что лимита нет вовсе и файл будет расти, пока не кончится диск. Именно так выглядит контейнер, запущенный без этих опционов.
Gotchas
- Обрезка освобождает только активный файл. Контейнер с
max-size=1m --log-opt max-file=2написал 20000 строк, иdocker logsпоказывал их все. После обрезки активного файла осталось 10122 строки — остальное лежит в повёрнутом…-json.log.1. Повёрнутые файлы удаляют, активный обрезают. - daemon.json не действует на существующие контейнеры.
log-optsв/etc/docker/daemon.jsonчитается при создании контейнера. Работающие живут со старыми настройками, пока их не пересоздать. sort -hзависит от локали. В русской или немецкой локали6.1Mне разбирается как число, и самый жирный лог уезжает в середину списка. ПередsortнуженLC_ALL=C.
Related questions
Почему docker system df не показывает логи? Он считает образы, слои записи контейнеров, тома и кеш сборки. Json-логи лежат рядом, в каталоге контейнера, и в эту таблицу не попадают.
Как ограничить логи сразу всем контейнерам? Прописать "log-driver": "json-file" и "log-opts": {"max-size": "10m", "max-file": "3"} в /etc/docker/daemon.json, перезапустить демон и пересоздать контейнеры.
Можно ли вообще не писать логи на диск? Да, --log-driver none отключает сбор, но тогда docker logs не покажет ничего. Компромисс — драйвер local, у него ротация включена по умолчанию.
See also
- Освободить место, занятое Docker
- df показывает полный диск, du — пустой
- journalctl: логи одного сервиса
CliAI превращает формулировку выше в точную команду и помечает вариант с rm меткой CAUTION до запуска. Поставить одной строкой.