# bind mount - монтирование каталога в другое место _Файловая система · LinuxLab Knowledge Base_ **TL;DR:** bind mount - `mount --bind `. Делает каталог (или файл) видимым по второму пути. Не копия, не symlink - те же inode'ы через VFS. Базовый кирпич chroot'ов, контейнеров и systemd-sandbox. ## Что это и как отличается от symlink Bind mount делает один и тот же набор inode'ов доступным через два пути. Не дублирование данных, не link на уровне ФС - это операция на уровне VFS-ядра. ```bash sudo mount --bind /var/log /home/serge/logs ls /var/log/syslog ls /home/serge/logs/syslog # тот же файл, тот же inode ``` Чем отличается от [symbolic-link](/kb/symbolic-link.md): | Свойство | symlink | bind mount | |-----------------------|-------------------------------|-------------------------------------| | Что это | inode-указатель в FS | VFS-маунт | | После reboot | сохраняется | пропадает (нужен fstab) | | `chroot` видит | сломанный, если цель снаружи | работает, цель уже «внутри» | | `realpath` | резолвит | НЕ резолвит (виден как target-путь) | | Нужны права root | нет | ДА (mount(2)) | | Можно read-only | нет | да (`-o ro`) | Главная сила bind mount: внутри [chroot](/kb/chroot.md) или [namespaces](/kb/namespaces.md) видно только реальный путь - symlink на путь снаружи был бы сломан. ## Базовое использование ```bash # 1. Каталог в каталог sudo mount --bind /var/log /mnt/logs # 2. Файл поверх файла (мощный приём) sudo mount --bind /tmp/my-fake-resolv.conf /etc/resolv.conf # → теперь /etc/resolv.conf указывает на наш файл, оригинал жив # 3. Размонтировать sudo umount /mnt/logs ``` Подмена через bind файла поверх файла - частая фича в контейнерах и hot-fix'ах: «не править оригинал, наложить bind на лету». ## Read-only bind - двухшаговый Опция `-o ro` на самом mount'е **игнорируется** ядром при первом bind. Нужно отдельным шагом сделать remount: ```bash sudo mount --bind /opt/data /srv/ro-data sudo mount -o remount,ro,bind /srv/ro-data # вот теперь действительно RO ``` Или одной командой через `--mkdir` + `-o`: ```bash sudo mount --bind -o ro /opt/data /srv/ro-data # на util-linux >= 2.27 работает напрямую ``` Проверить: ```bash findmnt /srv/ro-data # TARGET SOURCE FSTYPE OPTIONS # /srv/ro-data /dev/sda1[/opt/data] ext4 ro,relatime ``` Колонка SOURCE с `[/...]` в скобках - признак bind mount'а. ## --bind vs --rbind ```bash sudo mount --bind / /mnt/host # bind: НЕ перенесёт submounts sudo mount --rbind / /mnt/host # rbind: рекурсивно с /proc, /sys, /dev и т.д. ``` `--rbind` критичен когда исходный каталог содержит вложенные точки монтирования (классический пример - bind-mount всей корневой ФС для chroot'а). Без `r` ты получишь пустые `/proc`, `/sys`, `/dev` внутри. ## Mount propagation - про что это Когда внутри bind-mount'а делают новый mount - должен ли он быть виден снаружи? Это управляется флагом propagation: | Флаг | Поведение | |----------------|-----------------------------------------------------------------| | `shared` | новые mounts видны в обе стороны (default на systemd-системах) | | `slave` | mounts из master видны у нас, но не наоборот | | `private` | mounts невидимы в обе стороны | | `unbindable` | вообще нельзя bind'ить | Установка: ```bash sudo mount --make-private /srv/jail sudo mount --make-rslave / # рекурсивно для всего дерева ``` Зачем это знать - Docker и systemd активно играют propagation'ом. Если у тебя в /etc/fstab что-то с `bind` и оно ведёт себя странно при reboot - смотри `findmnt -o TARGET,PROPAGATION`. Пример: `mount --bind /` для chroot'а сделает то же propagation что у `/`. Если потом размонтировать что-то внутри chroot'а - это размонтируется и снаружи (если propagation = shared). Не очевидно. Решение: `--make-rprivate` на bind-копии. ## fstab - постоянный bind ``` # /etc/fstab /var/log /home/serge/logs none bind 0 0 /opt/data /srv/ro-data none bind,ro 0 0 /home /chroot/home none rbind 0 0 /tmp/conf /etc/myapp.conf none bind 0 0 ``` Тип ФС - `none` (не относится к bind'у). Опции через `bind` или `rbind`. Чтобы systemd-fstab-generator подхватил без reboot: ```bash sudo systemctl daemon-reload sudo mount -a ``` ## Применение на практике ### chroot и rescue ```bash for fs in proc sys dev dev/pts run; do sudo mount --bind /$fs /mnt/$fs done sudo chroot /mnt ``` Без bind'ов /proc и /dev многие команды внутри [chroot](/kb/chroot.md) упадут. ### Перенос данных без смены пути Допустим `/var/lib/postgres` забивает корневую ФС, нужно перенести на отдельный диск без правки конфига Postgres'а: ```bash sudo systemctl stop postgresql sudo rsync -aHAX /var/lib/postgres/ /data/postgres/ sudo mv /var/lib/postgres /var/lib/postgres.old sudo mkdir /var/lib/postgres echo '/data/postgres /var/lib/postgres none bind 0 0' | sudo tee -a /etc/fstab sudo mount -a sudo systemctl start postgresql ``` Postgres продолжает читать `/var/lib/postgres`, но физически данные на `/data`. ### Read-only слой в контейнере ```bash sudo mount --bind /etc /run/jail/etc sudo mount -o remount,ro,bind /run/jail/etc ``` ### systemd PrivateTmp Когда сервис имеет `PrivateTmp=yes`, systemd под капотом делает bind+namespace: создаёт пустой каталог и bind-монтирует его поверх `/tmp` для этого сервиса. Сервис не видит `/tmp` хоста. ## Ограничения 1. **Файл нельзя bind'нуть на каталог и наоборот.** Только файл-в-файл, каталог-в-каталог. 2. **Цель должна существовать.** Файл - пустой создать, каталог - `mkdir`. 3. **`umount` снимает только bind**, оригинал остаётся: ```bash sudo umount /mnt/logs # /var/log жив ``` 4. **`du` посчитает дважды** если оба пути попадут в обход: ```bash du -sh /var/log /mnt/logs # суммарно как 2× размер ``` ## Дебаг ```bash findmnt --types=none # все bind/rbind монты findmnt -o TARGET,SOURCE,OPTIONS,PROPAGATION /srv/jail cat /proc/self/mountinfo # сырой дамп всех mount'ов mount | grep bind # старая школа ``` Bind-маунты в `mountinfo` имеют формат `[/sub/path]` в SOURCE - именно отсюда findmnt и узнаёт что это bind. ## Команды ```bash sudo mount --bind /var/log /mnt/logs ``` Сделать каталог видимым по второму пути - те же inode'ы, не копия ```bash sudo mount -o remount,ro,bind /srv/ro-data ``` Сделать существующий bind read-only - отдельным remount-шагом, иначе ro игнорируется ```bash sudo mount --rbind / /mnt/host ``` Рекурсивный bind корня со всеми submount'ами /proc, /sys, /dev - для chroot'ов ```bash findmnt --types=none ``` Список всех bind-mount'ов на хосте - все они с типом none ```bash sudo mount --make-rprivate /mnt/jail ``` Изолировать propagation внутри chroot'а - иначе umount внутри утянет систему ## См. также - [mount и /etc/fstab - подключение ФС](/kb/mount-and-fstab.md) - [chroot - изоляция процесса в каталог](/kb/chroot.md) - [Linux namespaces](/kb/namespaces.md) - [tmpfs и overlayfs - RAM-disk и слои](/kb/tmpfs-overlayfs.md) - [Symbolic link](/kb/symbolic-link.md)