Перенос загрузочного физического раздела жесткого диска в виртуальную машину

Возникла необходимость перенести один старый физический сервер на новый в виртуальную машину. Почитал интернет. Все пишут, как перенести один физический раздел жёсткого диска в виртуалку, т.е. грубо говоря как создать из физического раздела жётского диска образ для виртуальной машины. Собственно, там и писать-то нечего, всё элементарно. А вот если вам нужно перести этот раздел вместе с загрузчиком, который прописан как обычно в MBR? Про это почему-то никто не пишет, а ведь тут-то как раз не всё так просто. Поэтому предлагаю вам свою статью, где описано как это сделать. Вы можете также использовать эту же технологию для создания образа жётского диска для виртуальной машины, в котором содержится не один раздел, а несколько.

Итак, предположим нам необходимо получить образ для виртуальной машины, содержащий данные физического раздела /dev/sda1. Загрузчик при этом у нас (как и у большинства) установлен в MBR. Немного усложним задачу. Машина рабочая, живая и всё надо делать "на лету". При этом у нас на этой же машине есть другой раздел, достаточного размера, чтобы вместить образ /dev/sda1, например точка монтирования /mnt у нас подмонтирована по NFS к тому серверу, где мы будем поднимать виртуалку.

Сперва мы делаем копию самого раздела, как советуют в многочисленных статьях в Интернете, находясь в каталоге /mnt командой dd:

dd if=/dev/sda1 of=./sda1.img bs=100M

Важное замечание! Поскольку мы работаем по живой системе, то будет происходить следующее: во время работы системы, данные на /dev/sda1 будут меняться. Это плохо! В идеале необходимо либо остановить всю активность программ, работающих с /dev/sda1, либо максимально снизить их активность. Как показала практика, если у вас, например, с разделом работают MySQL-сервер, exim и пишутся логи в /var, то сам каталог /var потом будет сломан! Поэтому, уж постарайтесь обеспечить наименьшую активность. Наиболее идеальным является случай, когда мы переносим зеркалированный раздел /dev/md0, который включает в себя /dev/sda1 и /dev/sdb1: тогда мы можем остановить ненадолго службы, отцепить половинку зеркала, запустить службы и продолжать уже работать с неактивной половинкой зеркала.

Итак. Образ получен. Но как я и говорил выше, из-за того, что мы снимали его с живой системы, файловая система в этом образе теперь содержит ошибки, которые необходимо исправить. Давайте сделаем это. Сперва привяжем наш файл к файлу устройства:

losetup -f ./sda1.img
losetup -a

Вторая команда покажет какое /dev/loop? устройство мы заняли. Допустим, это /dev/loop0. Привязку к устройству мы делаем потому, что в некоторых случаях команда fsck не будет исправлять повреждения найденные в файле, а на устройстве будет. Итак делаем собственно проверку с починкой:

fsck -y -f /dev/loop0

Вы увидите некоторое количество сообщений об ошибках и их исправлении. Один раз fsck у меня выдал сообщение о невозможности продолжения работы из-за исправления суперблока. Запустил повторно - отработало.

Итак, после проверки у нас в наличие корректный образ файловой системы раздела /dev/sda1. Отцепляем его от /dev/loop0 командой:

losetup -d /dev/loop0

Теперь встаёт главный вопрос, как быть с загрузчиком, который находится в MBR? Просто скопировать через dd сам MBR нельзя - мало того, что всё будет криво, так ещё и не будет работать, ведь на физическом диске разделов больше, чем 1. Я не буду вас утомлять сколько времени я потратил и что делал, чтобы достигнуть результата. Вот нужная последовательность действий:

1. Сперва нам всё-таки понадобится копия MBR. Сделаем её:

dd if=/dev/sda of=./mbr bs=512 count=1

Как известно, MBR - это первый 512 байт, расположенные в самом начале жёсткого диска. И вот эти 512 байт содержат и таблицу разделов и первую порцию кода загрузчика, без которой ничего грузиться не будет. Нам надо сделать так, чтобы код загрузчика у нас остался, а таблицу разделов зачистить. Делаем:

dd if=./mbr of=./mbr.1 bs=446 count=1

Это как раз код загрузчика. Далее:

dd if=/dev/zero of=./mbr.2 bs=64 count=1

Это у нас чистая таблица разделов, забитая нулями. Далее:

dd if=./mbr of=./mbr.3 bs=1 count=2 skip=510

Это последние два байта из MBR. Теперь склеиваем это всё в наш MBR с загрузчиком, но с чистой таблицей разделов:

cat mbr.1 mbr.2 mbr.3 >mbr.finish

2. Теперь нам нужна "подушка", т.е. фрагмент данных, который находится между MBR и началом раздела на физическом диске. Этот фрагмент забит нулями и используется для целей выравнивания информации на жёстком диске. Высчитать размер этого фрагмента очень просто.

# fdisk /dev/sda

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
         switch off the mode (command 'c') and change display units to
         sectors (command 'u').

Команда (m для справки): p

Диск /dev/sda: 251.0 ГБ, 250999111168 байт
255 heads, 63 sectors/track, 30515 cylinders
Units = цилиндры of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x48a348a2

Устр-во Загр     Начало       Конец       Блоки   Id  Система
/dev/sda1   *           1        1306    10485760   83  Linux
/dev/sda2            1306       14360   104857600   83  Linux
/dev/sda3           14360       14882     4194304   83  Linux
/dev/sda4           14883       30515   125572072+   5  Расширенный
/dev/sda5           14883       30515   125571072   83  Linux

Это как выглядит таблица разделов у меня. У вас будет нечто похожее. Размеры разделов указаны в циллиндрах (дорожках) и это нас категорически не устраивает. Переключаемся на секторы и выводим таблицу разделов снова:

Команда (m для справки): u
Изменение единиц измерения экрана/содержимого на секторы

Команда (m для справки): p

Диск /dev/sda: 251.0 ГБ, 250999111168 байт
255 heads, 63 sectors/track, 30515 cylinders, всего 490232639 секторов
Units = секторы of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x48a348a2

Устр-во Загр     Начало       Конец       Блоки   Id  Система
/dev/sda1   *          63    20971582    10485760   83  Linux
/dev/sda2        20971583   230686782   104857600   83  Linux
/dev/sda3       230686783   239075390     4194304   83  Linux
/dev/sda4       239079330   490223474   125572072+   5  Расширенный
/dev/sda5       239079393   490221536   125571072   83  Linux

Команда (m для справки): 

Мы видим с вами, что первый раздел начинается с 63-го сектора. Учитывыя, что размер сектора 512 байт, получаем: 63 * 512 = 32256. Именно столько байт нужно отступить от начала диска. Учитываем также, что 512 байт у нас занимает MBR и тогда: 32256-512 = 31744:

dd if=/dev/zero of=padding bs=31744 count=1

3. Всё готово к получению итогового образа:

cat mbr.finish padding sda1.img >hd.img

4. Это ещё не всё! Теперь в нашем образе жёсткого диска (уже диска, а не раздела) надо создать в таблице разделов запись, соответствующую первому разделу:

fdisk hd.img
Вы должны установить цилиндры.
Вы можете сделать это из меню дополнительных функций.

WARNING: DOS-compatible mode is deprecated. It's strongly recommended to
         switch off the mode (command 'c') and change display units to
         sectors (command 'u').

Команда (m для справки):

Не пугайтесь этой ругани, сделаем то, о чём нас просят. Для этого надо знать количество циллиндров (дорожек). Узнать можно очень просто - из тех же данных fdisk, которые он показывает для жёского диска (см. выше):

/dev/sda1   *           1        1306    10485760   83  Linux
т.е. 1306 дорожек. В fdisk'е переходим в режим эксперта и ставим нужное количество дорожек, затем возвращаемся в обычный режим:
Команда (m для справки): x

Команды эксперта (m для справки): c
Количество цилиндров (1-1048576): 1306

Команды эксперта (m для справки): r

Команда (m для справки): 

Теперь мы снова должны переключиться в режим секторов и создать раздел с точно такими же параметрами которые нам показал fdisk для физического диска (в секторах):

/dev/sda1   *          63    20971582    10485760   83  Linux

Итак:

Команда (m для справки): u
Изменение единиц измерения экрана/содержимого на секторы

Команда (m для справки): n
Действие команды
   e   расширенный
   p   основной раздел (1-4)
p
Номер раздела (1-4): 1
Первый сектор (63-20980889, по умолчанию 63): 
Используется значение по умолчанию 63
Last сектор, +секторы or +size{K,M,G} (63-20980889, по умолчанию 20980889): 20971582

Команда (m для справки): p

Диск hd.img: 0 МБ, 0 байт
255 heads, 63 sectors/track, 1306 cylinders, всего 0 секторов
Units = секторы of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x48a348a2

Устр-во Загр     Начало       Конец       Блоки   Id  Система
hd.img1              63    20971582    10485760   83  Linux

Команда (m для справки): w
Таблица разделов была изменена!

Синхронизируются диски.
Вот теперь у нас всё как у людей. Проверить можно по данным fdisk'а, которые он показывал для физического диска:
/dev/sda1   *          63    20971582    10485760   83  Linux

5. Но и это ещё не всё. Не забываем про то, что на физическом сервере и на виртуалке будут совершенно другие названия дисковых устройств и совсем другие настройки сети (возможно и какие-то другие изменения). Так что не худо бы поправить. А для этого, нам нужно смонтировать наш образ. Давайте сделаем это, уже на машине, где мы будем поднимать виртуалку. Например, там у нас hd.img лежит в /tmp. Создаём каталог /tmp/1, а далее способов тут два, либо снова через losetup, либо с указанием опции для mount. Показываю оба:

losetup -o 32256 -f hd.img
losetup -a
/dev/loop0: [0802]:4153364 (/tmp/hd.img)
mount /dev/loop0 1

второй способ

mount -o loop,offset=32256 hd.img 1

Как видите, в обоих случаях у нас задаётся смещение - тот самый размер подушки (32256), о котором говорилось ранее.

Теперь в каталоге /tmp/1 будет смонтированная файловая система из образа. Можете перейти туда и поправить /etc/fstab, настройки сети и прочее. После правок, размонтируйте и можно создавать виртуальную машину, указав в качестве образа диска наш готовый диск hd.img

Если всё сделали правильно, при запуске виртуальной машины вы увидите меню загрузчика и начнётся загрузка.


Ваш: Виктор Вислобоков