Новинка Виртуальный VDS сервер в Нидерландах от 390р
Выберите продукт

Docker на Linux VDS: что занимает /var/lib/docker и как безопасно очистить место

Если Docker на VDS внезапно съел диск, не спешите удалять каталог вручную. Разберём, где искать расход места в /var/lib/docker, как читать docker system df и что чистить без риска для данных.
Docker на Linux VDS: что занимает /var/lib/docker и как безопасно очистить место

Docker удобен тем, что быстро поднимает окружения, изолирует приложения и предсказуемо разворачивает сервисы на Linux VDS. Но у этой модели есть обратная сторона: данные контейнеров, слои образов, кэш сборок и логи постепенно растут в одном месте — чаще всего в каталоге /var/lib/docker. В какой-то момент на сервере заканчивается место, база перестаёт писать, деплой падает, а команда df -h показывает тревожные 100%.

Главное правило: не удаляйте файлы внутри /var/lib/docker вручную, если точно не понимаете, что делаете. Docker ведёт собственную базу метаданных, связывает контейнеры со слоями overlay2, volumes и сетями. Удаление «тяжёлой папки» через rm может привести к неработающим контейнерам, потерянным данным или состоянию, когда демон Docker больше не стартует.

Ниже — практичный план диагностики и уборки: как понять, что именно занимает диск, как использовать docker system df, когда безопасен prune, чем отличаются images, volumes и container logs, а также как настроить профилактику, чтобы проблема не возвращалась через неделю.

Что лежит в /var/lib/docker

Каталог /var/lib/docker — это рабочее хранилище Docker Engine. Конкретная структура зависит от версии Docker, storage driver и настроек, но на типичном Linux VDS вы увидите примерно такие подкаталоги:

  • overlay2 — слои образов и файловые изменения контейнеров при storage driver overlay2;
  • containers — метаданные контейнеров и часто их JSON-логи;
  • volumes — Docker volumes, где обычно лежат постоянные данные приложений;
  • image — метаданные образов;
  • buildkit — кэш сборок BuildKit;
  • network — состояние сетей Docker;
  • tmp — временные файлы.

Если диск забит Docker, почти всегда виноват один из четырёх источников: старые images, неиспользуемые volumes, разросшиеся container logs или кэш сборок.

Важно отличать «занимает место» от «можно удалить». Старый образ, который больше не используется контейнером, обычно можно удалить. А volume с данными PostgreSQL или uploads сайта — это уже рабочие данные, и удаление такого volume равносильно удалению базы или пользовательских файлов.

Быстрая диагностика: сколько занял Docker

Начинайте не с du, а с общей картины по файловой системе. Так вы поймёте, действительно ли проблема в Docker, или место заняли журналы системы, бэкапы, дампы баз, временные файлы веб-приложения.

df -h
sudo du -xhd1 /var | sort -h
sudo du -xhd1 /var/lib | sort -h
sudo du -xhd1 /var/lib/docker | sort -h

Ключ -x в du полезен на серверах, где есть отдельные mount point: он не даёт команде уходить на другие файловые системы. Если /var/lib/docker явно самый большой каталог, переходите к инструментам Docker.

Базовая команда для оценки хранилища Docker:

docker system df

Более подробный вывод:

docker system df -v

В результате вы увидите категории Images, Containers, Local Volumes и Build Cache. Колонка SIZE показывает общий размер, а RECLAIMABLE — сколько Docker считает потенциально освобождаемым. Это не всегда означает «удаляйте всё немедленно», но это хороший ориентир.

Схема основных источников расхода места в хранилище Docker

Как читать docker system df без самообмана

Вывод docker system df иногда удивляет: du показывает десятки гигабайт в /var/lib/docker, а Docker говорит, что reclaimable намного меньше. Это нормально. Файловая система overlay использует слои: один и тот же слой может быть общим для нескольких images и containers, а часть данных относится к активным контейнерам.

Разберём категории:

  • Images — скачанные и собранные образы. Один образ может использоваться несколькими контейнерами. Удалять можно те, которые не нужны и не используются.
  • Containers — остановленные и запущенные контейнеры, включая writable layer. Если приложение пишет данные внутрь контейнера, а не в volume, размер может быстро расти.
  • Local Volumes — постоянные тома. Здесь часто лежат базы данных, пользовательские загрузки, файлы CMS, очереди, индексы поиска.
  • Build Cache — кэш Docker BuildKit. Он ускоряет сборки, но на CI-серверах и dev-стендах может занимать очень много.

Команда docker system df -v помогает увидеть, какие images и volumes выглядят крупными. Но перед удалением volume всегда выясняйте, кто его использует и что внутри.

overlay2: почему он большой и почему его нельзя чистить rm

Каталог overlay2 часто становится самым крупным внутри /var/lib/docker. Это не «мусорная папка», а основа работы контейнерной файловой системы. Внутри лежат read-only слои образов и writable слои контейнеров. Docker связывает их через свои метаданные, поэтому ручное удаление отдельных директорий внутри overlay2 почти всегда плохая идея.

Проверить используемый storage driver можно так:

docker info --format '{{.Driver}}'

Если вывод — overlay2, это стандартный и обычно правильный вариант для современных Linux-серверов. Большой размер overlay2 означает одно из следующих:

  • на сервере много старых образов;
  • контейнеры пишут временные или постоянные данные внутрь своего слоя;
  • есть остановленные контейнеры с большим writable layer;
  • накопился build cache;
  • приложение пишет логи не только в stdout, но и в файлы внутри контейнера.

Чтобы найти контейнеры с большим writable layer, используйте:

docker ps -a --size

Если у контейнера размер writable layer измеряется гигабайтами, это сигнал: данные пишутся не туда. В production лучше выносить постоянные данные в volumes или bind mounts, а временные директории ограничивать и чистить средствами приложения.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Безопасная очистка images

Images занимают место после деплоев, экспериментов, локальных сборок и обновлений. На сервере может оставаться много старых тегов, dangling-слоёв и образов, которые уже не используются ни одним контейнером.

Посмотреть список образов:

docker images

Посмотреть dangling images — слои без тега:

docker images -f dangling=true

Удалить только dangling images обычно безопаснее всего:

docker image prune

Удалить все images, которые не используются контейнерами:

docker image prune -a

Вот здесь нужна осторожность. Команда docker image prune -a не удалит образ, который прямо используется существующим контейнером, но может удалить старые версии, нужные для быстрого rollback. Если у вас деплой построен так, что откат выполняется запуском старого образа с локального диска, после такой очистки откат потребует повторного скачивания или сборки.

Для более контролируемой уборки можно удалять конкретные образы:

docker rmi image_name:tag
docker rmi image_id

Хорошая практика для production: хранить образы в registry, тегировать релизы понятными immutable-тегами и не рассчитывать, что старый образ всегда останется на VDS. Тогда локальная очистка становится менее рискованной.

Volumes: где чаще всего лежат настоящие данные

Docker volumes — самая опасная зона для бездумного prune. В volume может лежать база PostgreSQL, каталог wp-content/uploads, файлы пользователей, состояние брокера очередей, индексы Elasticsearch или MinIO data directory. Если удалить такой volume, Docker не спросит у приложения, был ли это production.

Список volumes:

docker volume ls

Подробности по конкретному volume:

docker volume inspect volume_name

Понять, какие контейнеры используют volume, можно через inspect контейнеров:

docker ps -a --format '{{.Names}}'
docker inspect container_name --format '{{json .Mounts}}'

Если установлен jq, вывод удобнее читать так:

docker inspect container_name | jq '.[0].Mounts'

Неиспользуемые volumes Docker показывает как dangling:

docker volume ls -f dangling=true

Удалить все volumes, которые не используются ни одним контейнером:

docker volume prune

Команда выглядит безобидно, но в реальной эксплуатации бывают нюансы. Например, вы временно остановили контейнер базы, удалили сам контейнер при пересоздании compose-проекта, а volume остался dangling. Для Docker это «неиспользуемый volume», а для вас — единственная копия данных. Поэтому перед docker volume prune обязательно проверяйте имена volumes, compose-проекты и наличие актуального бэкапа.

Если нужно оценить размер volumes вручную:

sudo du -xhd1 /var/lib/docker/volumes | sort -h

А содержимое конкретного volume можно посмотреть через его mountpoint:

docker volume inspect volume_name --format '{{.Mountpoint}}'
sudo du -xhd1 /var/lib/docker/volumes/volume_name/_data | sort -h

Для named volumes путь обычно находится внутри /var/lib/docker/volumes. Для bind mounts данные могут лежать где угодно: например, в /srv/app/data, /opt/project или домашнем каталоге пользователя.

Container logs: тихий пожиратель диска

Очень частая причина переполнения /var/lib/docker — container logs. По умолчанию Docker часто использует logging driver json-file. Логи контейнера пишутся в JSON-файл внутри /var/lib/docker/containers. Если приложение активно пишет stdout/stderr, файл может вырасти до десятков гигабайт.

Проверить текущий logging driver:

docker info --format '{{.LoggingDriver}}'

Найти самые большие файлы логов контейнеров:

sudo find /var/lib/docker/containers -name '*-json.log' -printf '%s %p\n' | sort -n | tail -20

Если нужно сопоставить контейнер с файлом, посмотрите ID контейнера:

docker ps -a --no-trunc

Просмотр логов через Docker:

docker logs --tail 200 container_name
docker logs --since 1h container_name

Если лог уже огромный и нужно срочно освободить место, корректнее не удалять файл, а обнулить его. Сначала определите путь:

docker inspect container_name --format '{{.LogPath}}'

Затем обнулите файл:

sudo truncate -s 0 /var/lib/docker/containers/container_id/container_id-json.log

Замените путь на тот, который показала команда docker inspect. Не удаляйте лог-файл через rm: процесс может продолжить писать в удалённый inode, и место не освободится до перезапуска контейнера или Docker.

Чтобы проблема не повторялась, настройте ротацию логов Docker. Для демона Docker создайте или отредактируйте /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "5"
  }
}

После изменения конфигурации перезапустите Docker:

sudo systemctl restart docker

Важный нюанс: настройки логирования применяются к новым контейнерам. Уже созданные контейнеры обычно нужно пересоздать, чтобы они получили новые параметры.

В Docker Compose можно задать ротацию на уровне сервиса:

services:
  app:
    image: example/app:latest
    logging:
      driver: json-file
      options:
        max-size: "50m"
        max-file: "5"

После изменения compose-файла контейнер нужно пересоздать:

docker compose up -d --force-recreate

Build cache: полезен, пока не съел весь диск

На серверах, где выполняются сборки Docker images, быстро растёт Build Cache. Это особенно заметно в CI/CD: каждый pipeline скачивает зависимости, собирает слои, сохраняет промежуточные результаты. Кэш ускоряет сборку, но без лимитов превращается в отдельное хранилище мусора.

Посмотреть использование BuildKit-кэша:

docker builder du

Очистить неиспользуемый build cache:

docker builder prune

Более агрессивная очистка:

docker builder prune -a

Можно ограничить очистку по возрасту:

docker builder prune --filter until=168h

Такой вариант удалит кэш старше 168 часов, то есть примерно недели. Для production-сервера, где сборки редки, это обычно разумнее, чем полная очистка после каждого деплоя. Для CI-сервера политику стоит подбирать по балансу между скоростью сборки и стоимостью диска.

docker system prune: когда можно, а когда опасно

docker system prune — удобная команда комплексной уборки. Но именно из-за удобства она часто становится причиной неприятных сюрпризов. Сначала посмотрите, что вообще есть на сервере:

docker ps -a
docker images
docker volume ls
docker network ls
docker system df -v

Базовая очистка:

docker system prune

Она удаляет остановленные контейнеры, неиспользуемые networks, dangling images и часть build cache. Volumes по умолчанию не удаляются, и это хорошо.

Агрессивная очистка:

docker system prune -a

Она дополнительно удаляет все images, которые не используются контейнерами. Это освобождает больше места, но может убрать образы для rollback.

Самый опасный вариант:

docker system prune -a --volumes

Эта команда дополнительно удаляет неиспользуемые volumes. На тестовом стенде это может быть нормально. На production без проверки и бэкапа — плохая идея.

Если вы не уверены, что volume не содержит ценных данных, не включайте --volumes в автоматическую очистку.

Более безопасная стратегия — чистить категории отдельно: сначала logs и dangling images, затем build cache по возрасту, и только после ручной проверки — volumes.

Пошаговый runbook: Docker занял весь диск

Когда место уже закончилось, действовать нужно спокойно. Цель — быстро освободить немного пространства, восстановить работу сервисов и только потом разбираться глубже.

Шаг 1. Проверить диск и inode

df -h
df -ih

Иногда проблема не в гигабайтах, а в inode: слишком много мелких файлов. Для Docker это встречается реже, чем для кэшей приложений, но проверка занимает секунды.

Шаг 2. Найти крупные зоны внутри Docker

sudo du -xhd1 /var/lib/docker | sort -h
docker system df -v

Если самым крупным оказался containers, почти наверняка выросли container logs. Если overlay2 — смотрите images, writable layers и build cache. Если volumes — не удаляйте ничего, пока не поймёте назначение томов.

Шаг 3. Срочно обнулить разросшийся лог

docker inspect container_name --format '{{.LogPath}}'
sudo truncate -s 0 /path/from/logpath

Это часто освобождает место сразу и без остановки контейнера. После этого настройте ротацию логов, иначе через несколько часов ситуация повторится.

Шаг 4. Удалить очевидный мусор

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

docker container prune удаляет остановленные контейнеры. Перед запуском проверьте, нет ли среди них контейнера, который вы специально держите остановленным для анализа или rollback.

Шаг 5. Проверить volumes вручную

docker volume ls -f dangling=true
sudo du -xhd1 /var/lib/docker/volumes | sort -h

Если найден огромный dangling volume, выясните его происхождение. Часто имя содержит префикс compose-проекта. Проверьте старые compose-файлы, документацию проекта и бэкапы. Удаляйте volume только после подтверждения, что данные не нужны.

Пошаговый runbook для диагностики переполненного диска Docker

Почему контейнеры начинают писать гигабайты внутрь себя

У Docker есть важная архитектурная особенность: всё, что приложение пишет не в volume и не в bind mount, оказывается в writable layer контейнера. Этот слой живёт в overlay2 и удаляется вместе с контейнером. Для временных файлов это допустимо, но для постоянных данных — опасно.

Типичные причины роста writable layer:

  • приложение пишет файловые логи в /var/log внутри контейнера;
  • загрузки пользователей сохраняются в каталог приложения, но этот каталог не подключён как volume;
  • кэш фреймворка, npm, pip, composer или thumbnails генерируется внутри контейнера;
  • база данных запущена без volume для data directory;
  • в контейнере выполняются периодические задачи, создающие дампы и архивы.

Проверить размер контейнеров можно командой:

docker ps -a --size

Если вы видите большой размер у работающего контейнера приложения, разберите его файловую систему:

docker exec -it container_name sh
du -xhd1 / | sort -h

В минимальных образах может не быть du или shell. Тогда лучше временно использовать debug-контейнер с подключением нужного volume или пересобрать образ с диагностическими инструментами для staging. В production не стоит хаотично устанавливать пакеты внутрь контейнера: изменения потеряются при пересоздании, а образ станет непредсказуемым.

Настройка лимитов логов на уровне Docker daemon

Ротация логов — обязательная настройка для одиночного Docker-хоста на VDS. Без неё даже корректное приложение может забить диск при ошибке: например, если backend попал в цикл исключений и пишет stack trace несколько раз в секунду.

Проверьте, есть ли файл /etc/docker/daemon.json:

sudo test -f /etc/docker/daemon.json && sudo cat /etc/docker/daemon.json

Минимальная конфигурация с ограничением размера логов:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "20m",
    "max-file": "10"
  }
}

Так каждый контейнер сможет хранить до десяти файлов по 20 МБ, то есть примерно 200 МБ логов. Для небольшого Linux VDS это уже лучше, чем бесконечный рост. Для шумных сервисов выбирайте лимиты осознанно: слишком маленькое окно логов усложнит расследование инцидентов.

После изменения проверьте JSON и перезапустите Docker:

sudo dockerd --validate --config-file /etc/docker/daemon.json
sudo systemctl restart docker

Если команда валидации недоступна в вашей версии, используйте проверку через python3:

python3 -m json.tool /etc/docker/daemon.json

После перезапуска пересоздайте контейнеры, для которых должны примениться новые настройки. Для compose-проекта:

docker compose up -d --force-recreate

Если контейнеры обслуживают публичный сайт за Nginx, следите не только за Docker-логами, но и за кэшем веб-сервера. Например, при раздаче изображений полезно заранее продумать правила хранения и инвалидации — похожий подход разобран в материале про WebP и AVIF в Nginx с map и cache.

Особенности путей и systemd в разных дистрибутивах

Сами команды Docker в Debian, Ubuntu, AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux и Fedora обычно одинаковые. Отличия чаще касаются установки пакетов, расположения drop-in файлов systemd и наличия SELinux в RHEL-based системах.

Debian и Ubuntu

Проверить сервис Docker и логи systemd:

systemctl status docker
journalctl -u docker -n 200 --no-pager

Основной конфигурационный файл Docker daemon тот же:

/etc/docker/daemon.json

AlmaLinux, Rocky Linux, CentOS Stream, Oracle Linux и Fedora

Команды Docker такие же, но на RHEL-based системах чаще включён SELinux. Если вы переносите Docker data-root или используете bind mounts, неправильный SELinux-контекст может привести к ошибкам доступа. Для диагностики смотрите audit-журнал:

sudo ausearch -m avc -ts recent
sudo journalctl -t setroubleshoot --no-pager

Не отключайте SELinux только потому, что контейнер не видит каталог. Обычно лучше назначить корректный контекст или использовать поддерживаемые параметры монтирования. После переноса данных Docker проверяйте не только права Unix, но и политики безопасности.

FastFox VDS
Облачный VDS-сервер
Виртуальные серверы с быстрым запуском и гибкой конфигурацией от 390₽ / мес
Доступные локации
Россия Нидерланды

Что делать, если /var/lib/docker не помещается на системном диске

Иногда очистка помогает ненадолго: проект растёт, images и volumes объективно занимают много места. В этом случае лучше не бороться с симптомами, а перенести Docker data-root на отдельный диск или увеличить размер VDS-диска. Отдельный раздел под Docker удобен тем, что переполнение контейнерного хранилища не сразу ломает всю систему, SSH, пакетный менеджер и системные журналы.

Текущий Docker root dir:

docker info --format '{{.DockerRootDir}}'

Если вы планируете перенос, общий безопасный порядок такой:

  1. сделать бэкап важных volumes и compose-файлов;
  2. остановить контейнеры;
  3. остановить Docker;
  4. скопировать данные с сохранением прав, владельцев и xattrs;
  5. указать новый data-root в /etc/docker/daemon.json;
  6. запустить Docker и проверить контейнеры;
  7. удалять старый каталог только после проверки.

Пример настройки data-root:

{
  "data-root": "/srv/docker",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "5"
  }
}

Копирование можно выполнить через rsync после остановки Docker:

sudo systemctl stop docker
sudo rsync -aHAX /var/lib/docker/ /srv/docker/
sudo systemctl start docker

Перед удалением старых данных проверьте:

docker info --format '{{.DockerRootDir}}'
docker ps
docker system df

Не спешите удалять /var/lib/docker сразу. Лучше оставить его на короткое время под другим именем, если позволяет место, или иметь полный бэкап. При переносе на RHEL-based системах дополнительно учитывайте SELinux-контексты.

Автоматическая очистка: что можно поставить в cron или systemd timer

Автоматизация полезна, но только для безопасных операций. Не стоит каждую ночь запускать docker system prune -a --volumes на production. Это похоже на уборку склада бульдозером: свободное место появится, но вместе с ним могут исчезнуть важные данные.

Относительно безопасный набор для регулярной уборки:

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

Volumes лучше чистить вручную или по строгому регламенту, где есть бэкап и понятные имена. Например, можно договориться, что временные volumes имеют префикс tmp_, а production volumes — префикс проекта и окружения. Тогда вероятность ошибки ниже.

Для контроля места добавьте простой мониторинг. Минимум — alert по занятости файловой системы и inode. Лучше — отдельные метрики по Docker root dir, логам контейнеров и volumes. Даже простая проверка раз в час даст время отреагировать до того, как база данных начнёт падать с ошибкой No space left on device.

Чек-лист безопасной уборки Docker на Linux VDS

  • Проверьте df -h и df -ih, чтобы понять, закончились блоки или inode.
  • Сравните du по /var/lib/docker с выводом docker system df -v.
  • Не удаляйте вручную каталоги внутри overlay2, containers и volumes.
  • Для логов используйте truncate, а затем настройте max-size и max-file.
  • Сначала чистите dangling images и старый build cache.
  • Перед docker image prune -a убедитесь, что rollback не зависит от локальных старых images.
  • Перед docker volume prune проверьте назначение каждого volume и наличие бэкапа.
  • Следите за контейнерами с большим writable layer через docker ps -a --size.
  • Для растущих проектов рассмотрите отдельный диск или перенос data-root.
  • Настройте мониторинг свободного места, чтобы не узнавать о проблеме от пользователей.

Итоги

/var/lib/docker растёт не сам по себе: место занимают images, volumes, container logs, writable layers в overlay2 и build cache. Правильный подход — сначала измерить, затем понять назначение данных и только после этого удалять. Команды docker system df, docker ps -a --size, docker volume inspect и проверка логов дают почти всю нужную картину.

Для быстрой уборки обычно достаточно обнулить разросшийся JSON-log, выполнить docker image prune и почистить старый build cache. Для долгосрочного порядка настройте ротацию логов, храните данные в понятных volumes, не пишите постоянные файлы внутрь контейнера и заведите мониторинг диска. Тогда Docker на Linux VDS останется удобным инструментом, а не внезапным источником ночных аварий.

Поделиться статьей

Вам будет интересно

MySQL и MariaDB на VDS: bind-address, TLS/SSL и firewall для безопасного удалённого доступа OpenAI Статья написана AI (GPT 5)

MySQL и MariaDB на VDS: bind-address, TLS/SSL и firewall для безопасного удалённого доступа

Разбираем практический сценарий: база MySQL или MariaDB стоит на VDS, а подключаться к ней нужно с другого сервера. Покажем, как н ...
systemd credentials на Linux VDS: как уйти от .env с правами 644 OpenAI Статья написана AI (GPT 5)

systemd credentials на Linux VDS: как уйти от .env с правами 644

Файл .env с правами 644 удобен, но опасен: секреты читаются лишними пользователями, попадают в бэкапы и иногда оказываются в веб-к ...
Nginx maintenance mode на VDS: 503, Retry-After, whitelist и health checks OpenAI Статья написана AI (GPT 5)

Nginx maintenance mode на VDS: 503, Retry-After, whitelist и health checks

Разбираем безопасный режим обслуживания в Nginx для VDS: как включать 503 без поломки SSL-обновлений, пропускать админов по whitel ...