Storage driver в Docker — это слой, который отвечает за то, как контейнеры хранят и «склеивают» слои образов (image layers) и записываемые данные (writable layer). В теории это «внутренняя кухня», но на практике от выбора драйвера зависит почти всё: скорость сборок, время запуска, риск внезапного inode exhaustion, предсказуемость docker disk usage и то, насколько адекватно у вас будут работать snapshot backups.
Ниже — практичный разбор трёх вариантов: overlay2 (дефолт на большинстве современных дистрибутивов), btrfs и zfs. Цель не «кто лучше», а «что реально ломается», как это диагностировать и что выбирать под ваш профиль нагрузки.
Быстрый контекст: что именно хранит Docker
У Docker есть два принципиально разных типа данных:
- Слои образов и writable layer контейнеров — то, что хранится внутри
data-root(обычно/var/lib/docker) и обслуживается storage driver’ом. - Volumes (тома) — чаще всего директории на хосте (или сетевое/кластерное хранилище), которые driver напрямую не «склеивает». Volumes обычно живут дольше контейнеров и именно там должны быть базы и любые персистентные данные.
Драйвер напрямую влияет на слои и writable layer. На volumes — косвенно: через общую I/O-нагрузку, фрагментацию, политику снапшотов на уровне ФС/пула и т.д.
Как понять, какой driver используется сейчас
Начните с фактов: текущий драйвер и параметры хранения видны в docker info.
docker info --format '{{.Driver}}'
docker info
Полезно также сразу проверить, где лежит data-root, и прикинуть «логические» объёмы по данным Docker:
docker info --format 'Root={{.DockerRootDir}} Driver={{.Driver}}'
docker system df
docker system df показывает оценку, но в историях «удалил — а место не вернулось» он может быть обманчивым: CoW, снапшоты и метаданные не всегда отражаются так, как ожидается.

overlay2: дефолт, простой путь и типовые грабли
overlay2 использует overlayfs в ядре Linux: нижние слои образа монтируются как read-only, поверх них — writable слой контейнера. При записи файла, который существует в нижнем слое, происходит copy-up (копирование в верхний слой). Это даёт хороший баланс простоты, скорости и совместимости.
Когда overlay2 обычно лучший выбор
- Нужно «просто работающий» Docker на ext4/xfs без экзотики.
- Контейнеры в основном читают слои, а активно пишут в volumes (это правильный паттерн для продакшена).
- Важна совместимость с окружениями CI/CD и типовыми образами.
Производительность overlay2: что важно помнить
overlay2 обычно быстрый на «среднем» профиле: много чтения слоёв и умеренная запись в writable layer. Но если приложение активно пишет в rootfs контейнера (логи, кэш, временные файлы), copy-up и churn по мелким файлам могут стать узким местом. Частые симптомы:
- рост задержек на
fsyncи мелких write; - увеличение числа промежуточных артефактов при частых rebuild образов;
- деградация на больших деревьях файлов, где постоянно меняются отдельные файлы.
Практический вывод: если приложение много пишет — выносите запись в volumes и включайте ротацию логов/кэшей. Это часто даёт больший эффект, чем замена драйвера.
inode exhaustion на overlay2: почему «место есть, а создать файл нельзя»
Один из самых неприятных сценариев — inode exhaustion. На ext4 можно упереться не в гигабайты, а в иноды: файловая система физически не может создать новый файл/директорию, даже если свободные блоки ещё есть.
Проверка — двумя командами:
df -h /var/lib/docker
df -i /var/lib/docker
Если df -i показывает 100% — Docker начинает «сыпаться» странными ошибками: от невозможности распаковать слой до падений приложений, которые создают временные файлы.
overlay2 сам по себе не «съедает иноды». Он лишь наследует ограничения базовой ФС, на которой лежит
data-root. Если Docker живёт на маленьком ext4-разделе — проблему вы увидите рано или поздно.
Типовые причины в продакшене:
- миллионы мелких файлов в слоях (например,
node_modules, pip-кэши, vendor-деревья); - сборки «внутри» Docker без чистки промежуточных артефактов;
- контейнер пишет логи/кэш в rootfs вместо volume.
docker disk usage с overlay2: почему «удалил, а место не вернулось»
Для overlay2 типичны ситуации, когда вы удалили контейнеры/образы, а место вернулось не сразу или не полностью. Частые причины:
- dangling-образы и build cache;
- остановленные контейнеры с writable layers;
- открытые файловые дескрипторы (процесс ещё держит удалённый файл);
- volumes не удаляются автоматически, если вы явно не просили.
Быстрая диагностика по деталям:
docker system df -v
docker ps -a
docker images
Если подозреваете «удалённые, но занятые» файлы — ищите процессы, которые держат дескрипторы на файловой системе Docker:
lsof +L1 | head
btrfs: нативные снапшоты и дешёвые клоны, но нужны дисциплина и мониторинг
btrfs использует возможности Btrfs (subvolume/snapshot, CoW на уровне блоков, reflink) и хранит слои как подтома и снапшоты. Самая сильная сторона — «родной» снапшотный подход: модель Docker-слоёв хорошо ложится на философию Btrfs.
Где btrfs выигрывает
- Снапшоты на уровне ФС: можно быстро фиксировать состояние
/var/lib/dockerили отдельных subvolume (особенно если вы осознанно разносите данные по томам). - Эффективные клоны и потенциальная экономия места за счёт CoW, когда данные похожи.
- Гибкость управления: subvolume, квоты (qgroups), компрессия (включать только понимая профиль нагрузки).
Производительность btrfs: что чаще всего идёт не так
У Btrfs репутация «то летает, то внезапно плохо» обычно объясняется не магией, а ошибками эксплуатации:
- маленький запас свободного места (Btrfs заметно хуже ведёт себя на «почти заполнено»);
- перекос по метаданным (внезапно кончаются метаданные раньше данных);
- write-amplification из-за CoW на горячих файлах (логи/БД внутри rootfs контейнера);
- отсутствие регулярного обслуживания, если нагрузка активно «грязнит» дерево.
Если выбираете btrfs ради снапшотов, проектируйте хранение так, чтобы «горячая запись» шла в volumes, а не в writable layer.
Почему «inode exhaustion» на btrfs выглядит иначе
На Btrfs нет классической ситуации «иноды предсозданы и закончились» как на ext4. Но вместо этого вы можете упереться в метаданные, фрагментацию и дефицит свободного пространства под аллокацию новых чанков — симптомы внешне похожи: создание файлов резко тормозит или начинает падать с ошибками места.
Поэтому для btrfs полезно мониторить не только df, но и реальное распределение данных/метаданных:
btrfs filesystem usage /var/lib/docker
btrfs filesystem df /var/lib/docker
zfs: предсказуемость, send/receive и «тяжёлый люкс» для Docker-хостов
zfs хранит слои как ZFS datasets/snapshots и опирается на CoW-механику ZFS. Его часто выбирают там, где важны: управляемые снапшоты, переносы данных между узлами и предсказуемое поведение под нагрузкой.
Сильные стороны zfs для Docker
- Снапшоты и репликация через send/receive: удобно переносить состояние Docker-хоста (или часть данных) на другой сервер.
- Контроль свойств dataset’ов: сжатие,
recordsize, квоты/резервации, ограничения. - Стабильность поведения под нагрузкой при достаточной RAM и нормально собранном пуле.
Производительность zfs: цена за возможности
ZFS обычно требует больше памяти и внимания к настройкам, чем overlay2 на ext4. Если памяти мало, а нагрузка I/O-интенсивная, деградация может проявиться из-за давления на ARC и накладных расходов. Две практичные рекомендации для продакшена:
- не экономить на RAM, особенно если на узле много контейнеров и активных слоёв;
- прогонять тесты именно вашего профиля (мелкие файлы, rebuild, интенсивная запись) до миграции.
Про «место не возвращается» на zfs
На ZFS чаще упираются не в иноды, а в нехватку места в пуле из-за CoW и снапшотов: вы удалили данные, но пока существуют снапшоты, старые блоки всё ещё заняты. Поэтому политика ретенции снапшотов — не опция, а обязательная часть эксплуатации.

Сравнение по реальным сценариям
1) CI/CD и частые сборки образов
Если вы много билдите образы на одном узле, решает не только драйвер, но и hygiene: BuildKit cache, чистка промежуточных слоёв, лимиты на логи, уменьшение числа файлов в слоях. В общем случае:
- overlay2 — самый простой и предсказуемый старт; чаще всего «достаточно быстро».
- btrfs — удобно со снапшотами/клонами, но чувствителен к заполнению и метаданным.
- zfs — хороший выбор, когда снапшоты/репликация встроены в процесс, но требует ресурсов.
Если вы упираетесь в производительность на виртуализации, полезно оценить CPU-архитектуру и профиль нагрузки на диски: часть «проблем Docker» на самом деле упирается в конкретную связку ядра, гипервизора и дисковой подсистемы. В тему: производительность PHP/Node на ARM VDS и что это меняет для продакшена.
2) Много мелких файлов (node_modules, vendor, кэш)
Это типичный путь к проблемам: растут метаданные, растёт docker disk usage, появляются задержки. На overlay2 можно упереться в inode exhaustion на ext4. На btrfs/zfs — в метаданные и деградацию операций с каталогами.
Практика, которая почти всегда окупается:
- использовать multi-stage сборки;
- чистить кэши пакетных менеджеров на этапе сборки;
- не тащить dev-зависимости в runtime-слой;
- выносить изменяемые данные (логи, tmp, загрузки) в volumes.
3) Бэкапы и «снапшотный» подход
Тема снапшотов часто становится решающей, но важно разделять два уровня:
- Снапшот всего Docker root — быстро, но восстановление может быть «грязным», если в момент снапшота шли активные записи в writable layers.
- Снапшоты volumes/данных приложений — чаще всего именно то, что действительно нужно (БД, загрузки, state).
Если вы хотите, чтобы снапшоты были первоклассной функцией, btrfs и zfs дают больше инструментов, чем overlay2 на ext4/xfs. Но ключевой момент один: снапшоты должны быть частью политики (расписание, retention, регулярный тест восстановления), иначе они превращаются в скрытого потребителя места.
Для практики восстановления полезно иметь стенд/песочницу под регулярные «проверки бэкапов»: как организовать CI-проверку бэкапов и восстановления.
Миграция storage driver: о чём часто забывают
Смена driver’а — это не «переключатель в конфиге». Данные слоёв не «переедут» автоматически между драйверами. Обычно миграция означает: сохранить нужные образы (через registry или export), остановить Docker, перенести или очистить /var/lib/docker, поднять заново и перетянуть образы.
Мини-чеклист перед любыми действиями:
- проверьте, где лежит
data-root, и какой объём реально занят (включая иноды/метаданные); - сделайте резервные копии критичных volumes (не только образов);
- убедитесь, что понимаете, куда приложение пишет данные: rootfs или volume;
- спланируйте окно работ и откат (особенно если это один узел без HA).
Что выбирать: практические рекомендации
Если вы не уверены — берите overlay2
Для большинства сайтов, API и типовых сервисов overlay2 на ext4/xfs — оптимум по простоте, поддержке и ожидаемому поведению. Основные риски (inode exhaustion и неожиданный disk usage) лечатся дисциплиной: аккуратные Dockerfile, перенос записи в volumes, мониторинг инодов и регулярная чистка кэшей.
Если вы разворачиваете Docker на новом сервере и хотите предсказуемые ресурсы под прод, обычно удобнее начинать с VDS: проще выделить отдельный диск или раздел под /var/lib/docker, настроить мониторинг и не спорить с соседями по I/O.
Если критичны снапшоты и быстрый rollback на уровне ФС — смотрите btrfs
btrfs хорошо ложится на модель «много версий, много слоёв, быстро откатиться». Но он требует запаса места, контроля метаданных и понимания, где именно у вас происходит запись. Под подход «нажал кнопку и забыл» btrfs часто не подходит.
Если нужен «storage-подход» с репликацией и квотами — zfs
zfs — выбор, когда важна инфраструктурная управляемость: снапшоты, переносы, квоты, предсказуемость. Цена — требования к RAM и необходимость аккуратно проектировать пул и политики снапшотов, иначе docker disk usage улетает незаметно.
Мини-FAQ: частые вопросы
Можно ли «ускорить» Docker сменой драйвера, не меняя приложение?
Иногда да, но чаще основной выигрыш даёт исправление паттернов записи: логи и кэши в volumes, ротация, чистка build cache, уменьшение числа файлов в слоях. Драйвер — второй шаг, когда вы уже поняли свой профиль нагрузки.
Какой самый опасный сюрприз у overlay2?
Классика — inode exhaustion на небольшом ext4-разделе под /var/lib/docker, особенно если вы билдите много образов и у вас миллионы мелких файлов в слоях.
Почему снапшоты иногда «съедают» всё место?
Потому что снапшот фиксирует старые блоки: вы удалили файл в «живой» системе, но пока существует снапшот, блоки остаются занятыми. Без политики ретенции снапшоты превращаются в невидимый архив, который растёт.
Итог
Если кратко: overlay2 — лучший дефолт и минимальный риск, btrfs — про удобные снапшоты и CoW при условии дисциплины, zfs — про инфраструктурный контроль и репликацию, но с более высокими требованиями к ресурсам и настройке. Начинайте с диагностики текущих проблем (I/O, inode exhaustion, docker disk usage), и только потом решайте, есть ли смысл менять driver, а не просто исправить хранение данных и процессы сборки.


