Короткий ответ
Пока df -h /var/lib/docker 100%, не гадайте. Разложите /var/lib/docker на overlay2 (слои образов и контейнеров), volumes (app_data), buildkit cache, containers//-json.log. Каждый класс чистится своим инструментом. docker system prune -a не отвечает на вопрос «где гигабайты» и может снести теги, которые просто сейчас не запущены.
Сначала карта du, потом точечно: логи — json-file, висячие образы — dangling, безопасная чистка — prune. Volume app_data не удалять.
Симптомы и как отличить
df -h /100%,duпоказывает/var/lib/docker;Cannot start container ... no space left;- journal dockerd overlay2 ENOSPC, иногда daemon не стартует;
- inode 100% при свободных гигабайтах — мелкие слои/кэш.
| Каталог | Что это | Можно ли сносить вслепую |
|---|---|---|
| overlay2 | образы+rw слой | нет, только через docker rmi/prune |
| volumes/app_data | данные | нет |
| buildkit | кэш сборки | да, осторожно |
| containers//-json.log | логи | ротация, не rm на живом без политики |
Возможные причины
- json.log без max-size.
- Десятки старых тегов
app/web:2023*после CI. - Build cache после частых
compose build. - Рост
app_data(это бизнес-данные, не «мусор Docker»). - Dangling
<none>после пересборок. - Зависшие
overlaymount, du двойной счёт — реже, но пугает. - Редко:
tmpdockerd / leftover extract.
Диагностика
Хост host.example.
1. df и inode
df -hT / /var/lib/docker
df -i / /var/lib/docker
sudo du -xhd1 /var/lib/docker | sort -h2. Взгляд API
docker system df
docker system df -v | head -n 80
docker volume ls
docker volume inspect app_data --format '{{.Mountpoint}}'
sudo du -sh "$(docker volume inspect app_data --format '{{.Mountpoint}}')"Если app_data — 80% диска, это не overlay. Чистить prune бессмысленно, нужен бэкап/архив данных.
3. Логи vs слои
sudo du -sh /var/lib/docker/containers/*/*-json.log 2>/dev/null | sort -h | tail
sudo du -sh /var/lib/docker/overlay2 /var/lib/docker/image /var/lib/docker/buildkit /var/lib/docker/volumes4. Кто держит удаленные файлы
sudo lsof +L1 | grep docker | headУдалённый json.log, который процесс держит, место не отдаст.
Решение
Сценарий A. Карта показала json.log
Ротация и truncate по статье логов. Кратко, если контейнер жив:
Не rm файла лога под работающим docker-proxy/containerd без понимания. Лучше truncate после настройки max-size и recreate.
Сценарий B. overlay2 = образы
Список:
docker images --format '{{.Repository}}:{{.Tag}} {{.ID}} {{.Size}}' | sortУдаляйте конкретные старые теги, не -a. Остановленный прод-стек сначала compose up, иначе prune -a снимет его образы.
docker image rm registry.example:5000/app/web:1.2.0Dangling отдельно.
Сценарий C. build cache
docker builder du
docker builder prune --filter until=168hБез --all, пока не уверены. --all сносит и ненулевой кэш.
Сценарий D. Вырос app_data
Это не «закончился диск из‑за Docker как платформы». Бэкап, расширение LV, чистка данных приложения. Резерв volume до любых экспериментов.
Сценарий E. Демон уже не стартует из‑за ENOSPC
Освободите хостовое (journal, apt cache, старые ядра), не overlay руками. Затем start docker и вернитесь к system df.
sudo journalctl --vacuum-size=100M
sudo apt-get clean
sudo systemctl start dockerdocker system df делит «Images / Containers / Local Volumes / Build Cache». Админы смотрят только Images и запускают prune, хотя 90% — Local Volumes = app_data. Сверьте du Mountpoint тома с этой строкой. Если совпадает — это данные бизнеса: расширение LV, архив, политика retention в приложении, не overlay.
Rw-слой контейнера (docker ps -s колонка SIZE virtual vs writable) растёт, когда приложение пишет в /var/log внутри образа, а не в volume. Тогда overlay2 пухнет, json.log может быть маленьким. Лечение: направить логи в stdout или в app_data, recreate. Не rm файлов в /var/lib/docker/overlay2/<id> — сломаете diff.
На LVM thin или ZFS quota том /var/lib/docker может показать df 100% при свободном пуле — смотрите lvs/zfs list. Thin pool 100% даёт те же ENOSPC в overlay. Это уже хранилище хоста. Перед расширением — бэкап volume. После расширения xfs_growfs/resize2fs по вашей ФС, затем start docker, если он упал.
Inode: миллионы мелких слоёв от CI на том же диске, что прод. Вынесите build на runner. df -i в мониторинг рядом с df -h.
Как проверить, что проблема устранена
df -h / /var/lib/docker
docker system df
docker compose -f /opt/app/compose.yaml psЗапас ≥20% или ваш порог мониторинга. Стек app Running. Новые контейнеры создаются без ENOSPC. inode не 100%.
Если не помогло
- df 100%, du меньше: snapshot LVM/ZFS, или deleted-but-open.
- Заполняется снова за час — логи или утечка в
app_data/layer rw (контейнер пишет не в volume). overlay2огромный при маломdocker images: rw-слой контейнера.docker ps -s.- Несколько data-root: смотрите
docker info | grep Root. - Thin pool (если не overlay) — иная процедура, не эта статья.
Профилактика
- Алерт 80% на том docker.
- Глобальная ротация json-file.
- Политика тегов в CI (храним N релизов).
docker builder pruneпо cron сuntil.- Данные только в named volumes, не в rw-слой.
FAQ
Чем overlay отличается от volume в du?
overlay — файловая система образа и верхний слой контейнера. volume — отдельные каталоги, переживают recreate. Путать их опасно при чистке.
Можно ли сжать overlay?
Нет утилитой defrag. Только удаление неиспользуемых слоёв через rmi/prune.
prune без -a безопаснее?
docker system prune без -a не трогает tagged unused images. Всё равно спросит и не трогает используемые тома; prune -a --volumes — уже данные. См. безопасную чистку.
Почему после rmi df не упал?
Слой общий с другим тегом. docker system df после.
Вынести /var/lib/docker на другой диск?
Да, через stop docker, rsync, смена data-root или mount. Окно, бэкап app_data. Не symlink «на живую».