Извлечение конкретной директории из бекапа Proxmox (*.vma.lzo) для VDS c FreeBSD

Задача:

Есть сервер с FreeBSD на борту и файловой системой UFS2. Регулярно делаются бекапы средствами самого Proxmox: делается копия диска из ceph хранилища, упаковывается в формат *.vma.lzo и отправляется через NFS в бекап-хранилище. Нужно восстановить содержимое одной из директории сервера с FreeBSD на определенную дату.

Решение:

Находим в хранилище бекапов и распаковываем архив с резервной копией

lzop -d vzdump-qemu-175-2016_08_13-10_52_18.vma.lzo

получаем файл vzdump-qemu-175-2016_08_13-10_52_18.vma

*.vma - проприетарный формат резервных копий в Proxmox, для его распаковки используем утилиту vma, идет в комплекте с Proxmox

vma extract vzdump-qemu-175-2016_08_13-10_52_18.vma ./extract

Внутри ./extract видим

root@proxmox:/home/tmp# ls -l ./extract
-rw-r--r--  1 root root 34359738368 Aug 16 09:07 disk-drive-virtio0.raw
-rw-r--r--  1 root root         403 Aug 16 08:54 qemu-server.conf
-rw-r--r--  1 root root         110 Aug 16 08:54 qemu-server.fw

disk-drive-virtio0.raw - наш файл образа в RAW формате

qemu-server.conf - конфигурация VDS на момент резервной копии (количество памяти, процессоров, смонтированные диски, опции)

qemu-server.fw - настройки сетевого экрана

Теперь понятно, зачем Proxmox ввели свой формат, чтобы вместе с образом диска передавать информацию и о конфигурации сервера.

Нас интересует файл disk-drive-virtio0.raw, смотрим его как блочное устройство через fdisk

root@proxmox:/home/tmp/extract# fdisk -l disk-drive-virtio0.raw

Disk disk-drive-virtio0.raw: 32 GiB, 34359738368 bytes, 67108864 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x90909090

Device                  Boot Start      End  Sectors Size Id Type
disk-drive-virtio0.raw1 *       63 67108607 67108545  32G a5 FreeBSD

Видим тип раздела "FreeBSD", нам нужно его примонтировать.

Создаем директории в которую будем монтировать и попробуем смонтировать "в лоб"

root@proxmox:/home/tmp/extract# mkdir ./mnt
root@proxmox:/home/tmp/extract# mount -o loop disk-drive-virtio0.raw ./mnt
mount: /dev/loop0 is write-protected, mounting read-only
mount: wrong fs type, bad option, bad superblock on /dev/loop0,
       missing codepage or helper program, or other error

       In some cases useful info is found in syslog - try
       dmesg | tail or so.

Говорит не может определить тип файловой системы. Оно понятно. Потому что файловая система у нас начинается не с самого начала нашего образа. Сперва идет загрузчик, а потому уже файловая система. При монтировании нам нужно "отступить" несколько байт чтобы попасть в начало файловой системы. Сколько? Смотрим вывод fdisk -l:

Размер сектора 512 байт

Нужный нам раздел начинается с 63 сектора

значит отступаем 512*63=32256 байт с начала образа (опция offset=32256)

root@proxmox:/home/tmp/extract#  mount -o loop,offset=32256 disk-drive-virtio0.raw ./mnt
mount: /dev/loop0 is write-protected, mounting read-only
mount: wrong fs type, bad option, bad superblock on /dev/loop0,
       missing codepage or helper program, or other error

       In some cases useful info is found in syslog - try
       dmesg | tail or so.

Опять неудача, на этот раз мы не указали явно тип файловой системы. Укажем:

root@proxmox:/home/tmp/extract# mount -t ufs -o loop,offset=32256,ufstype=ufs2 disk-drive-virtio0.raw ./mnt
mount: /dev/loop0 is write-protected, mounting read-only

Отлично. Раздел примонтирован, теперь можно скопировать нужную директорию (передать по ssh, или просто передать клиенту в архиве).

Обратите внимание на ключи. Мы указали и " -t ufs" и "ufstype=ufs2" - только при обоих ключах раздел примонтируется.

Так же видим что раздел смонтирован в read-only. Для нашей задачи (скопировать директорию) этого достаточно. Для поддержки read-write нужно пересобирать ядро Linux.

При монтировании необходимо заранее создавать папку mnt куда будет примонтирован диск для избежания ошибки "mount: ./mnt: mount point does not exist"