Снимки Btrfs для безопасного обновления Linux-сервера: subvolume, read-only snapshot и откат | AdminWiki

Снимки Btrfs для безопасного обновления Linux-сервера: subvolume, read-only snapshot и откат

11 сентября 2026 11 мин. чтения
Содержание статьи

Обновление ядра или systemd на рабочем сервере ломает загрузку чаще, чем ожидается: свежий initramfs собирается без модуля хранилища, сервис из нового пакета ждёт сокет, которого больше нет, зависимости тянут несовместимую библиотеку. Read-only снимок Btrfs, созданный за минуту до apt upgrade, возвращает машину в исходное состояние за 5-10 минут ручной работы.

Короткий ответ на главный вопрос: снимок фиксирует корневой subvolume целиком, вместе с /usr, /etc, /var и составом установленных пакетов, поэтому после отката сервер выглядит так, будто обновления не было. Схема целиком: убедиться, что корень на Btrfs, создать отдельный subvolume для снимков, сделать read-only snapshot, выгрузить его через btrfs send на внешний диск, обновиться, при сбое переключиться на снимок и пересобрать GRUB.

Зачем делать снимки Btrfs перед обновлением Linux-сервера

Btrfs построен на copy-on-write (CoW). Снимок subvolume в момент создания ссылается на те же экстенты, что и оригинал, поэтому копирования байтов не происходит. Снимок корня на 200 ГБ создаётся за доли секунды и в первый момент не занимает места вообще. Когда после обновления файл меняется, Btrfs пишет новые блоки, а старые остаются закреплёнными за снимком.

Отсюда практический вывод для дежурного админа: локальный откат обновления занимает меньше времени, чем переустановка одного пакета с зависимостями. Планирование окна обслуживания, коммуникацию с командой и общий порядок действий при релизах разбирают в отдельном руководстве по безопасному обновлению критических систем, здесь же разберём техническую часть до команд.

Чем read-only snapshot Btrfs отличается от обычного бэкапа

Снимок и резервная копия решают разные задачи, и путать их дорого.

  • Снимок живёт в той же файловой системе и защищает от ошибок обновления: сломанных зависимостей, неудачного ядра, испорченного конфига.
  • Резервная копия лежит на другом носителе и защищает от отказа диска, контроллера, ошибки файловой системы.
  • Read-only снимок создаётся с флагом -r, ядро вернёт ошибку read-only file system при попытке записи в него. Случайно испортить снимок командой из истории не получится.
  • Снимок занимает место только на разницу с оригиналом, бэкап копирует данные физически.

Правильная связка выглядит так: read-only снимок для быстрого локального отката, и btrfs send на внешний диск для восстановления с live-USB, если сам пул или загрузчик пострадали.

Когда снимок Btrfs не спасёт: ограничения подхода

Четыре сценария, в которых схема не сработает, лучше знать заранее.

  • Отказ диска или контроллера. Снимки в том же пуле исчезнут вместе с оригиналом, спасает только копия на другом носителе.
  • Повреждение метаданных Btrfs. Если btrfs check находит ошибки, переключение default subvolume не поможет, нужен live-USB и восстановление из send/receive-копии.
  • Поломка GRUB или загрузчика. Откат без пересборки grub.cfg оставит сервер с меню, указывающим на старое ядро в удалённом subvolume.
  • Переполнение пула. После обновления каждый изменённый файл оставляет в снимке уникальные блоки, и пять снимков корня на сервере с активными логами съедят десятки гигабайт.

Подготовка сервера: проверка Btrfs и создание subvolume

Шаги ниже выполняются один раз, дальше обновления будут занимать минуты вместо часов.

Проверка, что корень смонтирован на Btrfs

findmnt -no FSTYPE /
btrfs filesystem show
btrfs subvolume list /

Ожидаемый результат: первая команда печатает btrfs, вторая показывает устройства пула, метку и UUID, третья перечисляет subvolume с ID и путями. Если выводится ext4 или xfs, инструкция к этому серверу не подходит: либо миграция, либо снимки средствами LVM.

Создание и монтирование subvolume @ и @home

Раскладка ниже совпадает с той, что используют установщики Ubuntu, Debian, Fedora и openSUSE: top-level subvolume с ID 5 остаётся пустым контейнером, корень уезжает в @, пользовательские данные в @home, снимки в @snapshots.

mkfs.btrfs -L rootfs /dev/sda2
mount /dev/sda2 /mnt
btrfs subvolume create /mnt/@
btrfs subvolume create /mnt/@home
btrfs subvolume create /mnt/@snapshots
btrfs subvolume list /mnt
umount /mnt

Отдельный @snapshots нужен по важной причине: вложенные subvolume не попадают в снимок родителя. Снимки корня не будут раздувать сам снимок корня, а замена @ не утащит их за собой.

Строки для /etc/fstab:

UUID=ВАШ-UUID /          btrfs subvol=@,compress=zstd,noatime,space_cache=v2 0 0
UUID=ВАШ-UUID /home      btrfs subvol=@home,compress=zstd,noatime 0 0
UUID=ВАШ-UUID /snapshots btrfs subvol=@snapshots,compress=zstd,noatime 0 0

Проверка результата после перезагрузки:

findmnt -no SOURCE,FSTYPE,OPTIONS /
btrfs subvolume show /
btrfs subvolume show /snapshots

В выводе btrfs subvolume show для корня должно быть указано Path: @ и Flags без readonly.

Создание read-only snapshot Btrfs перед обновлением

Снимок делается строго до первого шага обновления, пока пакеты и ядро не тронуты.

Практическая команда создания read-only snapshot

uname -r
dpkg -l | wc -l
btrfs subvolume snapshot -r / /snapshots/root-$(date +%F-%H%M)

Флаг -r превращает снимок в read-only. Имя с датой и временем избавляет от ручного переименования, когда снимков станет десяток. Перед снимком полезно сохранить текущую версию ядра и количество пакетов: после отката эти значения должны совпасть.

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

btrfs subvolume list -r /
btrfs subvolume show /snapshots/root-2026-09-11-0930
btrfs filesystem usage /

В списке появится новый subvolume с тем же ID, что указан в выводе show. Поле Flags: readonly подтверждает, что снимок защищён от записи, строка Snapshot(s) of показывает родителя. Колонка used в filesystem usage сразу после создания почти не изменится, это нормально.

Резервное копирование снимков через Btrfs send/receive

Локальный снимок не переживёт смерть диска, поэтому копию выносим на внешний носитель.

Полный send/receive снимка на внешний диск

mkfs.btrfs -L backup /dev/sdb1
mount /dev/sdb1 /mnt/backup
btrfs send /snapshots/root-2026-09-11-0930 | btrfs receive /mnt/backup/

Отправлять можно только read-only subvolume, иначе btrfs send завершится ошибкой. После первой копии на приёмнике появится subvolume с тем же именем, пригодный для монтирования и восстановления.

Инкрементальный send/receive для экономии места и времени

btrfs send -p /snapshots/root-2026-09-10-0900 /snapshots/root-2026-09-11-0930 | btrfs receive /mnt/backup/
btrfs subvolume list -r /mnt/backup/

Ключ -p задаёт родительский снимок, и по сети или на диск уходят только изменённые блоки. Родитель обязан уже лежать на приёмнике, иначе btrfs receive ответит failed to receive subvolume. Для сервера с корнем на 40-60 ГБ инкремент после планового обновления обычно занимает сотни мегабайт вместо десятков гигабайт.

Если нужна полноценная стратегия с ротацией, дедупликацией и автотестами восстановления, смотрите руководство по резервному копированию сервера 2026 с rsync, Borg и Rclone: Btrfs-снимки хорошо закрывают быстрый локальный откат, а долговременное хранение удобнее строить на специализированных инструментах.

Обновление Linux-сервера и проверка после перезагрузки

Снимок лежит на диске, копия отправлена на внешний носитель. Теперь обновляемся.

apt update && apt full-upgrade -y
systemctl reboot

Для RHEL-производных вместо первых двух команд используется dnf upgrade -y. Порядок действий, типовые окна обслуживания и автоматизация через Ansible и CI/CD разобраны в практическом руководстве по обновлению информационных систем.

Чек-лист проверки после обновления

uname -r
systemctl list-units --state=failed
journalctl -p err -b --no-pager | tail -n 40
dmesg --level=err,warn | tail -n 30
findmnt -no TARGET,SOURCE,FSTYPE | grep btrfs
ss -tulpn | head -n 20

Если ядро сменилось и сервисы поднялись, а в journalctl нет ошибок уровня err, обновление прошло штатно. Появились failed-юниты, не поднимается сеть или база, переходим к откату: снимок даёт на это ровно то время, которое экономит локальная копия.

Откат обновления Linux с помощью снимка Btrfs

Если система не грузится, работаем с live-USB того же дистрибутива, что установлен на сервере.

Загрузка с live-USB и монтирование top-level subvolume

lsblk -f
mount /dev/sda2 /mnt -o subvolid=5
ls /mnt
btrfs subvolume list /mnt

Монтирование с subvolid=5 открывает top-level subvolume, в котором видны @, @home и snapshots. Дальше нужно выбрать целевой снимок, например snapshots/root-2026-09-11-0930.

Переключение default subvolume или замена @ снимком

Способ первый, через default subvolume:

btrfs subvolume list /mnt | grep root-2026-09-11
btrfs subvolume set-default 261 /mnt
umount /mnt && reboot

Способ работает, только если в fstab не задан параметр subvol= или subvolid=. Явное указание subvolume в fstab перекрывает default, и сервер снова загрузится со сломанного корня. Второй способ лишён этого ограничения:

cd /mnt
mv @ @broken-2026-09-11
btrfs subvolume snapshot /mnt/snapshots/root-2026-09-11-0930 /mnt/@

Снимок создаётся обычный, для записи, а испорченный @ остаётся в стороне до подтверждения, что система стабильна.

Обновление GRUB и перезагрузка после отката

mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
mount --bind /dev /mnt/dev
mount /dev/sda1 /mnt/boot/efi
chroot /mnt
grub-mkconfig -o /boot/grub/grub.cfg
update-initramfs -u -k all
exit
umount -R /mnt
reboot

Без пересборки grub.cfg и initramfs загрузчик продолжит искать ядро по старым путям и записям в меню. После перезагрузки проверяем findmnt /, uname -r, systemctl list-units --state=failed и сверяем версии пакетов с теми, что зафиксировали перед снимком.

Контроль свободного места при накоплении снимков Btrfs

Снимки делят экстенты с оригиналом, но после обновления каждый изменённый файл оставляет уникальные блоки. Без ротации пул заканчивается в самый неподходящий момент.

Как читать вывод btrfs filesystem usage и qgroup

btrfs filesystem usage /
btrfs qgroup show -reF /
Поле в выводеЧто показываетНа что смотреть
Device unallocatedМесто, не отданное под Data, Metadata и SystemБлизко к нулю: скоро упрутся в лимит метаданные
DataЗанято под данные, с разбивкой used и freeused растёт после каждого обновления, free падает
MetadataЗанято под дерево subvolume и метаданныеТысячи мелких файлов раздувают метаданные быстрее данных
Data ratioСтепень зеркалирования блоковДля single всегда 1.00, для RAID1 равен 2.00
qgroup exclusiveУникальные блоки конкретного снимкаПоказывает, сколько освободит удаление этого снимка

Удаление старых снимков без потери данных

btrfs subvolume list -s /
btrfs subvolume delete /snapshots/root-2026-09-01-0800

Read-only снимок удаляется без предварительного снятия флагов, отдельная команда для этого не нужна. Рабочая стратегия: держать на локальном диске 3-5 последних снимков корня, на внешнем носителе хранить один полный и цепочку инкрементов за 30 дней. Ротацию удобно повесить на systemd timer или cron той же командой btrfs subvolume delete. Освобождаются только уникальные блоки: если удаляемый снимок делит большинство экстентов с текущим корнем, места вернётся мало.

Диагностика ошибок при работе со снимками Btrfs

Типовые сообщения и их причины собраны в таблице, чтобы не искать смысл по форумам в момент инцидента.

Типовые ошибки и их решения

ОшибкаПричинаРешение
ERROR: cannot find real pathПуть указан от корня смонтированной системы, а не от точки монтирования top-levelСверьте путь с выводом btrfs subvolume list /mnt (live-USB)
ERROR: read-only file systemПопытка записи в снимок, созданный с флагом -rРаботайте с копией: btrfs subvolume snapshot /snapshots/root-X /mnt/@
ERROR: failed to receive subvolumeДля инкремента с -p на приёмнике нет родительского снимкаСначала выполните полный send, затем инкрементальный
ERROR: cannot delete: Device or resource busySubvolume смонтирован, например /snapshotsumount /snapshots или удаляйте снимки при загруженной системе через точку /
ERROR: not a subvolumeВ пути обычный каталог внутри subvolume, а не сам subvolumeДелайте снимок корня subvolume, а не вложенного каталога
BTRFS error: ENOSPC в метаданныхЗакончилось место под служебные деревьяУдалите старые снимки, проверьте Device unallocated, добавьте устройство

Команды диагностики состояния Btrfs

dmesg | grep -i btrfs
btrfs filesystem df /
btrfs device stats /
btrfs subvolume show /
journalctl -b -p err | grep -i btrfs
btrfs check --readonly /dev/sda2

btrfs check запускают только на размонтированной файловой системе, ключ --readonly безопасен и ничего не меняет, а --repair применяют последним шагом после копии данных. Команда btrfs device stats показывает счётчики ошибок чтения и записи по каждому устройству: ненулевые значения говорят о проблемах с диском или кабелем. Если journalctl выдаёт тысячи строк, разбор ускоряет прогон логов через API нейросетей: AiTunnel даёт единый доступ к GPT, Gemini и Claude с оплатой в рублях, но передавайте логи обезличенными.

Сравнение Btrfs snapshots с LVM и ZFS для отката обновлений

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

Когда выбрать Btrfs, а когда LVM или ZFS

КритерийBtrfs snapshotLVM snapshotZFS snapshot
Скорость созданияСекунды, размер данных не влияетСекунды, нужен свободный extent в volume groupСекунды, работает на уровне dataset
Расход местаТолько изменённые блоки, экстенты общиеCoW-том, под изменения резервируется местоОбщие блоки в пределах пула
ГранулярностьКорень и /home откатываются отдельноЛогический том целикомОтдельный dataset
Откат системыset-default или замена @lvconvert --merge с перезагрузкойzfs rollback dataset
Отправка на другой хостbtrfs send / receiveШтатного механизма нетzfs send / receive
Проверка целостностиКонтрольные суммы данных и метаданныхНетКонтрольные суммы и scrub

Btrfs выбирают, когда корень уже на этой файловой системе и нужен откат за минуты без дополнительных слоёв. LVM подходит для серверов на ext4 и XFS, где том уже создан: снимок тома снимается одной командой, но объём под изменения нужно резервировать заранее, иначе snapshot становится невалидным. ZFS даёт контрольные суммы, scrub и send/receive на уровне пула, подробности и типовые ошибки проектирования собраны в разборе ZFS и OpenZFS. Если сервер работает под TrueNAS, автоматизацию снимков и их ротацию удобно строить по практике резервного копирования на ZFS-снимках в TrueNAS.

Итоговый чек-лист безопасного обновления Linux-сервера с Btrfs

  1. Проверить файловую систему: findmnt -no FSTYPE /. Ожидается btrfs.
  2. Убедиться, что /snapshots смонтирован отдельным subvolume @snapshots.
  3. Зафиксировать uname -r и dpkg -l | wc -l до обновления.
  4. Создать read-only снимок: btrfs subvolume snapshot -r / /snapshots/root-$(date +%F-%H%M).
  5. Проверить снимок: btrfs subvolume list -r / и btrfs filesystem usage /.
  6. Выгрузить полный снимок через btrfs send, затем держать инкременты с ключом -p.
  7. Обновить пакеты и перезагрузиться.
  8. Проверить systemctl list-units --state=failed, journalctl -p err -b, uname -r, состояние сервисов и монтирований.
  9. При сбое загрузиться с live-USB, смонтировать subvolid=5, откатиться через set-default или замену @, пересобрать GRUB.
  10. После подтверждения стабильности удалить старые снимки командой btrfs subvolume delete.
# минимальный набор команд перед обновлением
findmnt -no FSTYPE /
uname -r
btrfs subvolume snapshot -r / /snapshots/root-$(date +%F-%H%M)
btrfs subvolume list -r /
btrfs filesystem usage /

Отрепетировать откат безопаснее на отдельном стенде, чем на боевом сервере: разверните VPS в Timeweb Cloud, повторите разметку с @ и @home, обновите ядро и прогоните полный цикл восстановления, включая chroot и grub-mkconfig. Один такой прогон на тестовой машине снимает большинство сомнений и заметно сокращает время простоя в реальный инцидент.

Поделиться:
Сохранить гайд? В закладки браузера