Короткий ответ

Чистка — по карте docker system df, не одной «магической» командой. Порядок: логи json-file, dangling images, build cache, точечный docker image rm старых тегов. Исключены: volume app_data, образы текущего и прошлого релиза. docker system prune -a и тем более docker system prune -a --volumes на проде проекта app запрещены без явного списка жертв и бэкапа.

Симптомы и как отличить

  • Нужно место, стек должен выжить;
  • уже кто-то запустил -a, compose pull качает часами;
  • volume ls не показывает app_data;
  • путают builder cache и volumes в du.
КомандаОбразы tagged unusedDanglingVolumes
image pruneнетданет
image prune -aдаданет
system pruneнетда + stopped containers + netнет
system prune -a --volumesдаданеиспользуемые тома

Возможные причины

  1. json.log — тогда не prune, ротация.
  2. CI образы — dangling.
  3. builder на том же хосте, что прод.
  4. Реальный рост app_data — чистка Docker не поможет, нужны данные/диск.
  5. Привычка cron -a.

Диагностика

df -h /var/lib/docker
docker system df
docker system df -v | head -n 60
docker compose -f /opt/app/compose.yaml ps -a
docker volume ls
docker volume inspect app_data --format '{{.Name}} inuse-check via ps'

Список «священных» тегов:

docker compose images
docker images | grep 'registry.example:5000/app'

Stopped контейнеры:

docker ps -a --filter status=exited

system prune удалит exited контейнеры, не тома (без --volumes). Обычно ок, если это не контейнер с анонимным volume, который вы ещё не переименовали.

Решение

Сценарий A. Безопасный минимум

docker image prune
docker builder prune --filter until=168h

Перечитайте system df. Часто этого хватает вместе с ротацией логов.

Сценарий B. Старые теги вручную

docker image rm registry.example:5000/app/web:1.0.9

Оставьте текущий и N-1.

Сценарий C. Exited мусор

docker container prune

Не трогает running. Проверьте, что не удаляете контейнер с уникальным анонимным томом без бэкапа.

Сценарий D. Когда volume prune допустим

Только после docker volume ls и явного allowlist. На хосте только appне запускайте volume prune. Если лабораторный хост:

docker volume ls
# удалить по имени мусорный том:
docker volume rm old_tmp_volume

Не prune оптом.

Сценарий E. Уже сделали prune -a --volumes

  1. Не пишите на диск поверх.
  2. Ищите /var/backups, снапшоты СХД, object storage.
  3. Registry ещё может отдать образы, данные тома — нет.
  4. Дальше IR, не повторный prune.

Cron docker system prune -af --volumes встречается в gist «очистка сервера». На host.example с остановленным на ночь app это удалит app_data как unused. Запретите -f в cron: интерактивное подтверждение хотя бы раз учит читать список. Для автоматизации — явные docker image rm по allowlist тегов старше N, никогда --volumes.

container prune удалит Exited migrate-контейнеры, это обычно ок. Не удалит running. Сети: unused app_default после down prune сети безвреден, up создаст снова. Образы tagged unused — ценность отката; их не отдавайте оптом.

Build cache на прод-хосте — сначала организационный долг. builder prune --filter until=168h безопаснее --all, который снесёт кэш сегодняшней ночной сборки, если вы всё ещё собираете здесь. После prune проверьте compose ps и volume inspect app_data.

Запись в журнал изменений: что удалили, сколько места, кто. Иначе через неделю «пропал образ отката» без следа. Связка с dangling и логами: чистите класс объектов, который показал du, не все классы сразу.

Как проверить, что проблема устранена

df -h /var/lib/docker
docker system df
docker compose -f /opt/app/compose.yaml ps
docker volume inspect app_data >/dev/null && echo app_data_ok
docker compose exec web ls /var/lib/app | head

Стек Running, том на месте, место освободилось за счёт images/cache/logs, не за счёт данных. Rollback-образ ещё docker images.

Если не помогло

  • df не упал: логи или app_data или deleted-open.
  • Стек не стартует: pull с registry.
  • volume is in use при rm — и правильно, не -f борьба.
  • BuildKit cache в другом DOCKER_BUILDKIT root.

Не используйте docker volume prune --filter label!=keep пока не разметите метки на app_data. Без меток фильтр всё равно опасен. На проде только явный volume ls и точечный rm чужого мусора. Перед rminspect и бэкап, если имя не очевидно тестовое. После чистки сравните df и compose ps, чтобы не принять удаление данных за успех.

Профилактика

  • Документ: разрешённые команды vs запрет -a/--volumes.
  • CI runner ≠ prod volume data.
  • Алерт df 80%.
  • Ротация логов глобально.
  • Имена томов явные app_data.

После любой чистки пройдите compose ps, health, df. Если освободилось меньше ожидания — вы чистили не тот класс (логи vs images). Не добавляйте сразу -a. Запишите в тикет список docker images до/после.

FAQ

system prune без флагов на проде?

Относительно мягкий: dangling + stopped containers + unused networks. Не трогает tagged images и volumes. Всё равно посмотрите ps -a до.

--filter until

Полезен для dangling/build. Не заменяет запрет -a.

Почему unused network удалять ок?

Да, app_default живой сети running стека prune не удалит. После down сеть может уйти — up создаст снова. Данных нет.

container prune vs compose rm

Смотрите имена app-*. Не чистите чужой стек на том же Engine.

Можно ли cron image prune?

Да, без -a, после часов. Не volume prune.