Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean

в 8:17, , рубрики: digital ocean, initramfs, виртуализация, Настройка Linux, облако, Серверное администрирование, системное администрирование

К примеру, Digital Ocean не предоставляет возможности загрузить свой образ виртуалки, более того, так же нельзя подключить ISO-образ для установки (правда, есть KVM — и на том спасибо).
Поэтому придётся пойти хитрым путём и делать всё через ssh. Основная идея — на новой виртуалке отмонтировать корневую файловую систему, залить файлы/образ от старой, обновить настройки grub, обновить настройки сети и fstab, перезагрузить.
Самое неочевидное в первом шаге. Можно отмонтировать / и на живой системе, это реально, хоть и муторно. Гораздо проще добавить ssh сервер и пару утилит в initramdisk и сделать всё оттуда, т.к. на этом этапе загрузки ОС корневая система еще не примонтирована.
Собственно, вся статья — это демонстрация утилиты для включения ssh сервера в ramdisk + два разобранных примера.
Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 1

Перенос сервера Debian из Xen-а c паравиртуализацией на Digital Ocean.

Важно чтобы на DigitalOcean виртуалка была с возможностью менять ядро с самой виртуалки (В панели управления DigitalOcean, во вкладке Kernel должно быть написано что меняйте ядро внутри хоста).
Источник на Xen:
Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 2
Там стоит nginx с такой вот демо страницей
Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 3

Шаг 1. Подготовка сервера-источника к переносу

Можно ничего не подготавливать, просто выключить сервер-источник и отдавать файлы/образ из гипервизора, но это не интересно и, к тому же, источник вполне может быть не на виртуалке, а на голом железе. Поэтому, первым шагом мы перемонтируем корневую файловую систему (и, соответственно, так же подключенные ФC, если есть) в read-only. Перемонтировать в read-only гораздо проще чем отмонтировать целиком — достаточно просто прибивать демоны, которые могут что-то писать.

/etc/init.d/nginx stop
apt-get install lsof rsync
lsof /

Смотрим что осталось. Нам интересны строчки где колонка FD заканчивается на w или u
Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 4
Ага, остался rsyslog

kill 6288
mount -o remount,ro /

Если получилось — то хорошо, если нет — то дальше искать кто держит файлы открытыми на запись. Как правило, достаточно выключить все дополнительно установленные демоны + syslog.

Шаг 2. Отмонтирование корневой ФС на сервере-получателе

Получателем у нас будет Ubuntu 16.04. В теории абсолютно не важно что на получателе будет стоять до переноса, т.к. это всё перезатрётся, просто утилита для автоматизации настройки initramdisk работают с ubuntu/debian.
Итак, свежесозданная ubuntu 16.04 на DigitalOcean:

apt-get install git dropbear
git clone https://github.com/roginvs/early-ssh
cd early-ssh
./build_deb.sh
dpkg -i early-ssh*.deb
sed -ie 's/DISABLED=1/DISABLED=0/' /etc/early-ssh/early-ssh.conf  # Enable
update-initramfs -u
reboot

Пингуем IP адрес получателя и следим на TTL. Как только TLL в ответах поменяется — это значит что initramdisk загрузился и ждёт подключений. По умолчанию он долго ждать не будет, если через 15 секунд никто не подключился то загрузка пойдёт дальше.
Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 5
Подключаемся по ssh и получаем shell. В моём случае авторизация у root-а по ключу, но будет работает и по паролю, даже если в sshd_config стоит 'PermitRootLogin without-password' (потому как в initramdisk стоит dropbear, а не sshd).
Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 6
Собственно, один раздел.

Шаг 3. Перенос данных

Можно перенести все данные либо через dd (естественно если размер диска получателя не меньше чем источника), либо через rsync. dd будет предпочтительней если на файловой системе мало свободного места либо ну очень много мелких файлов.

Вариант с dd по ssh:

dd if=/dev/xvda2 bs=65536 | ssh root@198.199.127.149 'dd of=/dev/vda1 bs=65536'

Вариант с dd без шифрования, но с компрессией:

# На получателе
nc -q 1 -l 8000 | gzip -d | dd bs=65536 of=/dev/vda1
# На источнике
dd if=/dev/xvda2 bs=65536 | gzip | nc -q 1 198.199.127.149 8000

Из соседней консоли можно постоянно слать сигнал USR1 на dd чтобы видеть как идут дела:

while true; do kill -USR1 `pidof dd`; sleep 10; done

Вариант с rsync:

На получателе пересоздаём файловую систему и монтируем её:

mkfs.ext3 /dev/vda1
mkdir /mnt
mount /dev/vda1 /mnt

Файловая система ext3, а не ext4 только потому что на источнике ext3. Теперь с сервера-источника:

rsync -aAXv --one-file-system --progress / root@198.199.127.149:/mnt/

(Аккуратней со слешами в конце, они должны быть)

Шаг 4. Проверка ядра, проверка /etc/fstab, настройка сети, обновление настроек grub

На получателе монтируем свежескопированную ФС и делаем chroot туда:

mount /dev/vda1 /mnt
mount -o bind /dev/ /mnt/dev/
mount -o bind /proc/ /mnt/proc/
mount -o bind /sys/ /mnt/sys/
chroot /mnt
PATH=$PATH:/usr/sbin
bash

Проверяем что ядро установлено (это нужно если ОС источника была на xen с паравиртуализацией)

apt-cache search linux-image
apt-get install linux-image-3.16.0-4-amd64
dpkg-reconfigure linux-image-3.16.0-4-amd64

Обновляем настройки сети в /etc/network/interfaces

nano /etc/network/interfaces

Сама корневая фс в /etc/fstab (Устройство называется теперь vda1 + удалить своп)

nano /etc/fstab

Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 7

Ну и загрузчик:

apt-get install grub2
grub-install /dev/vda
update-grub2

Все, можно всё отмонтировать и перезагрузить:

exit # Из bash
exit # Из chroot
cd /
umount /mnt/dev
umount /mnt/proc
umount /mnt/sys
umount /mnt
reboot

После перезагрузки проверяем что веб-страница открывается с нового IP:
Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 8

Установка Windows Server 2012r2 на DigitalOcean

Шаг 1. Подготовка источника

С Windows у нас дела обстоят немного сложней, поэтому я сначала делал виртуалку в VmWare, и потом её переносил из гипервизора. При установке указывал что ОС будет Linux, драйвер диска Lsi SAS.
Установленный Windows сервер нужно приготовить к переносу:

Загрузка драйверов для KVM

Скачиваем fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso (https://pve.proxmox.com/wiki/Windows_VirtIO_Drivers), распаковываем, устанавливаем Tools и для каждого inf файла для нашей версии выполняем

PnPUtil -i -a <InfName>.inf

Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 9

Немного костыльной магии

Костыли это потому что по-хорошему это нужно делать через unattended.xml. Создаем файл c:firstrun.bat, и пишем туда следующее, попутно заменяя mac/ip/маску/шлюз/пароль тем, что у нас есть на виртуалке приёмнике:

@Echo Off
:: Mac is in Windows format (dashes)!
SET MAC=00-50-56-9E-B8-57
SET IP=192.168.2.85
SET MASK=255.255.255.0
SET GW=192.168.2.1
SET ADMINPW=QWEasd123

echo Started >> c:firstrun.log
date /T >> c:firstrun.log
time /T >> c:firstrun.log

ipconfig /all >> c:firstrun.log

echo "Start to search network interface" >> c:firstrun.log
:start_loop
  For /f "delims=, tokens=1,3 skip=1" %%a In ('getmac /V /FO CSV') Do ( 
    IF /I %%b == "%MAC%" (
      echo "Found card" >> firstrun.log
      echo %%a >> firstrun.log
      netsh interface ip set address %%a static %IP% %MASK% %GW% 10
      netsh interface ip add dns %%a 8.8.8.8
      goto :end_loop
    )
  )
  ping 127.0.0.1  
goto :start_loop
:end_loop

net user Administrator %ADMINPW%
reg add "HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlTerminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
NetSh Advfirewall set allprofiles state off

reg delete "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionSetupState" /v ImageState /f
reg add "HKEY_LOCAL_MACHINESYSTEMSetup" /v OOBEInProgress /t REG_DWORD /d 0 /f
reg add "HKEY_LOCAL_MACHINESYSTEMSetup" /v RestartSetup /t REG_DWORD /d 0 /f
reg add "HKEY_LOCAL_MACHINESYSTEMSetup" /v SetupPhase /t REG_DWORD /d 0 /f
reg add "HKEY_LOCAL_MACHINESYSTEMSetup" /v SetupType /t REG_DWORD /d 0 /f

reg delete "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun" /v DigitalOceanHack /f
echo "Ok, reboot" >> c:firstrun.log
shutdown -r -t 20

Далее в консоли добавляем этот скрипт на автозапуск и делаем sysprep в audit:

reg add "HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionRun" /v DigitalOceanHack /t REG_SZ /d "C:firstrun.bat" /f
%WINDIR%system32sysprepsysprep /generalize /audit /shutdown

Образ готов, при следующей загрузке он начнёт себя конфигурировать.

Шаг 2. Отмонтирование корневой ФС в источнике, переразметка партиций

Загружаемся в ramdisk как в предыдушем примере, двигаем корневую ФС, создаём новые разделы в начале диска, обновляем настроки grub:

e2fsck -f /dev/vda1
resize2fs /dev/vda1 25G
fdisk /dev/vda
 Command: d
 Command: n
 Select (default p): p
 Partition number: 1
 First sector: 2048
 Last sector: +716799       ### Такой же как в образе Windows = 716800 секторов минус 1
 Command: n
 Select (default p): p
 Partition number: 2
 First sector: 718848
 Last sector: +32833535   ### Точно так же значение из образа минус 1
 Command: n
 Select (default p): p
 Partition number: 3
 First sector: 73400320 ### Хочу взять 25Гб = 52428800 секторов с конца диска объемом 125829120 секторов. 
 Last sector: +52428799   # 25Гб в секторах - 1
 Command: t
 Partition number: 1
 Partition type: 7
 Command: t
 Partition number: 2
 Partition type: 7
 Command: a
 Partition number: 1
 Command: a
 Partition number: 3
 Command: w

Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 10
Первый раздел — загрузочный для Windows, 350Мб, второй — сама Windows, третий, соответственно, Linux. Откуда эти числа взялись — будет понятно на следующем шаге, пока что можно сначала сделать два раздела случайного размера (но чтобы последний сектор был не меньше размера образа Windows) и потом уже их пересоздать из Ubuntu когда будет скопирован образ на файловую систему Ubuntu. В конечном итоге важно чтобы разделы для Windows были на тех же местах и такого же размера, что и в образе-источнике.
Я оставил так много на корневую ФС потому как я буду временно туда класть vmdk файл. В теории можно сразу писать его через pipe на раздел.
Теперь копируем Ubuntu (она-то до сих пор лежит в начале диска), 25Гб с /dev/vda начиная с 2048 сектора в /dev/vda3:

dd if=/dev/vda bs=4096 skip=256 count=6553600 of=/dev/vda3

(skip и count в 8 раз уменьшенные потому как блок не 512, а 4096)
Обязательно обновляем настройки grub и правим /etc/fstab если нужно (/dev/vda1 заменить на /dev/vda3):

mkdir /mnt
mount /dev/vda3 /mnt
mount -o bind /dev/ /mnt/dev/
mount -o bind /proc/ /mnt/proc/
mount -o bind /sys/ /mnt/sys/
chroot /mnt
PATH=$PATH:/usr/sbin
grub-install /dev/vda
update-grub2
nano /etc/fstab
exit
cd /
umount /mnt/dev
umount /mnt/proc
umount /mnt/sys
umount /mnt
reboot

Шаг 3. Любым образом копируем vmdk файл на опять загрузившуюся убунту

Хорошо, если vmdk файл сразу представляет собой образ диска (если нет — то нужно сконвертировать в raw через «qemu-img convert -p -f vmdk original.vmdk -O raw converted.raw»)

fdisk Windows2012r2.vmdk

Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 11
Вот, собственно, откуда берутся значения для /dev/vda1 и /dev/vda2 для предыдущего шага.

Копируем Windows с образа в разделы:

dd bs=4096 skip=256 count=89600 if=Windows2012r2.vmdk of=/dev/vda1
dd bs=4096 skip=89856 count=4104192 if=Windows2012r2.vmdk of=/dev/vda2

(skip и count так же умешьненные в 8 раз)
Можно попытаться примонтировать /dev/vda1 и /dev/vda2 для того, чтобы проверить что всё ок, и, если нужно, поправить настройки в костыльном скрипте.

Обновляем grub, смотрим что он увидел Windows:

update-grub2

Теперь включаем Windows на следующую перезагрузку, это удобно если что-то пойдёт не так, то вернуться можно выключив и включив виртуалку:

grub-reboot 2
reboot

Т.к. образ подготовленный через sysprep + костыльный скрипт, то Windows захочет 2 раза перезагрузится с интервалом в несколько минут. Т.е. еще 2 раза придётся залогинится в ubuntu и запустить последние 2 команды.

Шаг 4. Загрузка Windows по-умолчанию

Вместо того, чтобы включать windows в дефаулт в grub лучше просто добавить в /etc/rc.local:

sleep 60 && grub-reboot 2 && reboot &

— если Windows перестанет загружаться, то можно успеть залогинится в Ubuntu и сделать «killall sleep».

После перезагрузок можно зайти по RDP:
Перенос образа виртуальной машины между облачными хостерами или устанавливаем Windows Server на Digital Ocean - 12

Ссылки:
Устанавливаем любой Linux дистрибутив на Digital Ocean

Автор: roginvs

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js