# Docker storage drivers - overlay2, btrfs, zfs _Контейнеры (бонус) · LinuxLab Knowledge Base_ **TL;DR:** Storage driver - как Docker хранит image-layers и контейнер-changes на диске. overlay2 default (overlayfs над ext4/xfs), btrfs/zfs через subvolumes/snapshots, fuse-overlayfs для rootless. ## Зачем разные drivers Image-слои, read-only. Контейнер пишет, нужен writable layer поверх. Старые ФС не могли это сделать эффективно, поэтому Docker поддерживал несколько **storage drivers**, каждый со своим подходом. Сегодня **overlay2** покрывает 95% случаев, но знать остальные стоит, встретится в legacy и в прод-сценариях с особыми требованиями. Где живёт всё это: ``` /var/lib/docker/ ├── overlay2/ ← если driver = overlay2 │ ├── / │ │ ├── diff/ ← файлы конкретного слоя │ │ ├── lower ← список нижних слоёв │ │ └── work/ ← рабочая директория overlayfs ├── containers/ └── image/ ``` Какой driver сейчас: ```bash docker info | grep -i storage # Storage Driver: overlay2 # Backing Filesystem: extfs ``` ## overlay2, default Использует [[tmpfs-overlayfs|overlayfs]] из ядра. Image-слои read-only `lower`, container-changes, `upper`. Плюсы: - **В ядре**, без userspace-overhead - **Page cache shared** между контейнерами с одним base image - **Быстрый startup**, overlay-mount копеечный Минусы: - **Inode usage растёт быстро**, copy-up at write копирует целые файлы. Большие файлы с маленькими правками = двойной расход - **Не любит много слоёв**, kernel-limit на nested overlay около 128 Backing filesystem: ext4, [xfs](/kb/xfs.md) (с `ftype=1`), [btrfs](/kb/btrfs.md), [ext4](/kb/ext4.md), [[tmpfs-overlayfs|tmpfs]] (для rootless через user-namespace). Для XFS обязательно при mkfs: ```bash mkfs.xfs -f -n ftype=1 /dev/sdb1 ``` Иначе overlay2 откажется работать (`d_type` отсутствует). ## btrfs, native CoW Использует [[btrfs|btrfs]] subvolumes и snapshots: - Каждый слой, subvolume - Container layer, snapshot последнего image-subvolume - Записи внутри контейнера, copy-on-write на уровне ФС Плюсы: - Снапшот за O(1) - Дедупликация на уровне FS-блоков - `btrfs scrub` находит bit rot Минусы: - Вся `/var/lib/docker` должна быть **на btrfs** - Btrfs не любит near-full ФС - На high-write workload фрагментация бьёт перформанс - В 2026 не дефолт нигде, нишевый выбор ```bash # daemon.json { "storage-driver": "btrfs" } ``` ## zfs, enterprise CoW Аналогично btrfs, но через ZFS: - Каждый слой, zfs filesystem - Container, clone последнего слоя - Внутри, `zfs send/receive` для миграции Плюсы: - ZFS-grade reliability (ARC, scrubs, raid-z) - Дедупликация (если включена) - Snapshots дёшевы Минусы: - **ZFS не в mainline kernel**, нужен ZoL (zfs-on-Linux), CDDL+GPL лицензионные дрязги - RAM-голодный (ARC ест free-memory) - Production-стек редкий, в основном TrueNAS / Solaris-наследники Для контейнеров, обычно перебор, кроме особых случаев (storage-server). ## devicemapper, legacy Создаёт thin-pool на блочных устройствах, каждый layer, отдельный thin LV. Раньше дефолт на RHEL 7. **Deprecated**, удалён из Docker 23+ (2023). Не используй. ## vfs, fallback Просто **рекурсивно копирует** файлы между layers. Никакой CoW. - Огромный disk usage - Очень медленный pull - Работает на любой ФС Дефолт rootless-Docker без user-namespaces overlay-permissions. Для prod, никогда. ## fuse-overlayfs, rootless В rootless-Docker/Podman обычный overlayfs не работает (нужен CAP_SYS_ADMIN для mount). FUSE-version делает то же в userspace: ```bash # Podman rootless по умолчанию podman info | grep -i graphdriver # graphDriverName: overlay # ... mountopt: nodev,fsync=0 ``` Современные ядра 5.11+ имеют **rootless-overlayfs** через user-namespaces, и `overlay` работает без FUSE, быстрее. Но FUSE нужен для старых ядер. ## Сравнение | Driver | Backing | CoW level | Рекомендация | |--------|---------|-----------|---------------| | **overlay2** | ext4/xfs/btrfs | overlayfs (file) | default, 95% случаев | | **btrfs** | btrfs | btrfs subvol/snapshot (block) | если уже есть btrfs | | **zfs** | zfs | zfs clone (block) | enterprise NAS | | **devicemapper** | thin pool | LVM thin (block) | **deprecated** | | **vfs** | любая | none (full copy) | тестовый/fallback | | **fuse-overlayfs** | любая | userspace overlay | rootless legacy | ## Performance: large-write проблема overlay2 Overlay2 делает **copy-up на write**: при первой записи в файл из read-only layer весь файл копируется в writable layer. Если файл 10 GB и меняется 1 байт, копия 10 GB. Для БД и VM-images это убийственно. Решения: - **Volume / bind-mount** для data-directory: ```bash docker run -v /var/lib/postgres-data:/var/lib/postgresql/data postgres ``` Volume лежит вне overlay, без copy-up. - **chattr +C** на host-директорию если backing, btrfs ([[btrfs|см.]]) - **tmpfs для эфемерных каталогов**: ```bash docker run --tmpfs /tmp:size=100M ... ``` ## Storage size limits По умолчанию контейнер может занять весь диск (до full-FS). Лимит: ```bash docker run --storage-opt size=10G ... ``` Работает только на storage drivers с native quota: - **overlay2 + xfs+pquota**, да - **btrfs**, да через subvolume quota - **devicemapper**, да (thin pool) - **overlay2 + ext4**, **нет** Альтернатива: docker-compose с `storage_opt:` или k8s `ephemeral-storage` requests/limits. ## Очистка disk usage ```bash docker system df # сколько занято docker image prune # неиспользуемые images docker container prune # остановленные docker volume prune # unmounted volumes docker builder prune # build cache docker system prune -a --volumes # ВСЁ (опасно, удалит images) # Точечно: какие layers и их размер du -sh /var/lib/docker/overlay2/* | sort -h | tail ``` Большой `/var/lib/docker/overlay2/`, норма для CI-runner'ов; prune раз в день, must. ## Когда что-то пошло не так - **`failed to register layer: ApplyLayer exit status 1`**, обычно backing FS не поддерживает overlay (vfat) или место кончилось. - **`device or resource busy` при docker rm**, overlay-mount держится. `docker stop` сначала, или kill процессов из контейнера через `docker top`. - **`d_type is not supported`** на XFS, сделан без `ftype=1`. Только пересоздать ФС с правильным mkfs. - **`No space left on device`** при свободных GB, кончились inode на ext4 (`df -i`). Overlay создаёт **много** мелких файлов. Пересоздать с `mkfs.ext4 -i 4096`. - **Очень медленный pull**, много мелких слоёв (`docker history` покажет 50+). При build объединяй RUN-команды. - **`/var/lib/docker` распух непомерно**, старые dangling images, container exit'ed но не удалены, build-cache. `docker system df`, потом prune. - **Контейнерный write на shared volume "пропадает"**, другой контейнер на той же volume записал поверх. Volume, не overlay, последний writer wins. ## Альтернативные runtime'ы и их storage - **podman**, подобные drivers (overlay, vfs); rootless = `overlay` через user-NS - **containerd** имеет свой "snapshotter" subsystem: native, overlayfs, btrfs, devmapper. Стандарт для k8s. - **CRI-O**, overlay (default) или vfs ## Команды ```bash docker info | grep -A5 'Storage Driver' ``` Какой storage driver и backing FS - первое что проверять ```bash docker system df ``` Сводка по disk usage Docker'а - images/containers/volumes/cache ```bash du -sh /var/lib/docker/overlay2/* | sort -h | tail ``` Топ-10 самых жирных layer-директорий - где течёт место ```bash docker image prune -a ``` Удалить ВСЕ unused images, не только dangling - аккуратно в проде ```bash docker run --storage-opt size=5G --runtime=runc ubuntu ``` Лимит на writable layer - работает на xfs+pquota / btrfs / devmapper ```bash xfs_quota -x -c 'report' /var/lib/docker ``` Quotas для overlay2 на xfs - кто сколько занимает ```bash stat -c '%T' -f /var/lib/docker ``` Тип ФС в /var/lib/docker - совместимость со storage driver ## См. также - [tmpfs и overlayfs - RAM-disk и слои](/kb/tmpfs-overlayfs.md) - [btrfs - copy-on-write, subvolumes и снапшоты](/kb/btrfs.md) - [XFS - extents и параллельный I/O](/kb/xfs.md) - [cgroups v2 - unified hierarchy, PSI, eBPF control](/kb/cgroups-v2-deep.md) - [OCI spec - стандарт контейнеров](/kb/oci-spec.md)