Перенос облака с Селектела на Vscale

Дисклеймер: всё нижеописанное использовать вдумчиво и под свою ответственность! Шпаргалка создана для личных целей, использовать исключительно в качестве инструкции «как делать не надо». Большинство команд восстановлено по памяти, но отражают суть дела. Статья не претендует на уникальность или адекватность, но метод рабочий.

Краткое содержание:

  • Изменяем размер корневой файловой системы на новой виртуалке
  • Переносим снапшот LVM со старой
  • Заставляем грузиться новое ядро со старой операционкой
  • Рихтуем до работоспособного состояния систему в целом


Поехали!

  1. Создаем виртуалку в vscale.io с похожей версией операционной системы. Например, вместо Debian 6 ставим минимальный возможный Debian 7. Диск выбираем из собственных предпочтений с расчетом «чтоб влезло». Как пользоваться панелью нового облачного хостера, можно найти в официальном блоге на Хабре
  2. Пересобираем на новой виртуалке initrd с выходом в консоль до монтирования разделов. Для этого делаем следующее:
      • Создаем папку и разворачиваем туда текущий initrd:
        mkdir ~/initrd; cd ~/initrd
        gunzip -c /boot/initrd.img-3.2.0-4-amd64 | cpio -i --make-directories
        65923 blocks
        ls -l
        total 44
        drwxr-xr-x 2 root root 4096 Aug 22 11:20 bin
        drwxr-xr-x 3 root root 4096 Aug 22 11:19 conf
        drwxr-xr-x 6 root root 4096 Aug 22 11:21 etc
        -rwxr-xr-x 1 root root 6797 Aug 22 11:19 init
        drwxr-xr-x 6 root root 4096 Aug 22 11:19 lib
        drwxr-xr-x 2 root root 4096 Aug 22 11:19 lib64
        drwxr-xr-x 2 root root 4096 Aug 22 11:19 run
        drwxr-xr-x 2 root root 4096 Aug 22 11:19 sbin
        drwxr-xr-x 7 root root 4096 Aug 22 11:21 scripts
        drwxr-xr-x 3 root root 4096 Aug 22 11:19 usr
      • Кладем необходимые библиотеки и бинарники для работы с файловой системой (нам нужен fdisk, resize2fs и e2fsck):
        ldd /sbin/fdisk 
        	linux-vdso.so.1 =>  (0x00007ffeeb96e000)
        	libblkid.so.1 => /lib/libblkid.so.1 (0x00007fe3ba493000)
        	libuuid.so.1 => /lib/libuuid.so.1 (0x00007fe3ba28f000)
        	libc.so.6 => /lib/libc.so.6 (0x00007fe3b9f2d000)
        	/lib64/ld-linux-x86-64.so.2 (0x00007fe3ba6b2000)
        ldd /sbin/resize2fs
        	linux-vdso.so.1 =>  (0x00007ffd497ee000)
        	libe2p.so.2 => /lib/libe2p.so.2 (0x00007f128b5b6000)
        	libext2fs.so.2 => /lib/libext2fs.so.2 (0x00007f128b388000)
        	libcom_err.so.2 => /lib/libcom_err.so.2 (0x00007f128b185000)
        	libc.so.6 => /lib/libc.so.6 (0x00007f128ae23000)
        	libpthread.so.0 => /lib/libpthread.so.0 (0x00007f128ac07000)
        	/lib64/ld-linux-x86-64.so.2 (0x00007f128b7bd000)
        ldd /sbin/e2fsck 
        	linux-vdso.so.1 =>  (0x00007fff949f7000)
        	libext2fs.so.2 => /lib/libext2fs.so.2 (0x00007f24ab49a000)
        	libcom_err.so.2 => /lib/libcom_err.so.2 (0x00007f24ab297000)
        	libblkid.so.1 => /lib/libblkid.so.1 (0x00007f24ab078000)
        	libuuid.so.1 => /lib/libuuid.so.1 (0x00007f24aae74000)
        	libe2p.so.2 => /lib/libe2p.so.2 (0x00007f24aac6d000)
        	libc.so.6 => /lib/libc.so.6 (0x00007f24aa90b000)
        	libpthread.so.0 => /lib/libpthread.so.0 (0x00007f24aa6ef000)
        	/lib64/ld-linux-x86-64.so.2 (0x00007f24ab6c8000)
        
        for i in libext2fs.so.2.4 libcom_err.so.2.1 libe2p.so.2.3; do cp -i /lib/x86_64-linux-gnu/$i lib/x86_64-linux-gnu/; done
        cd lib/x86_64-linux-gnu/
        ln -s libcom_err.so.2.1 libcom_err.so.2
        ln -s libext2fs.so.2.4 libext2fs.so.2
        ln -s libe2p.so.2.3 libe2p.so.2cd ~/initrd/
        cp /sbin/e2fsck ~/initrd/bin/
        cp /sbin/resize2fs ~/initrd/bin/
        cp /sbin/fdisk ~/initrd/bin/
      • Изменяем init скрипт в месте перед монтированием устройств в систему, для этого в файле scripts/local
        ...
            # FIXME This has no error checking
            # Mount root
            if [ "${FSTYPE}" != "unknown" ]; then
                    mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt}
            else
                    mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt}
            fi
        ...
        

        Делаем примерно так:

        #RESIZEROOTFS MODIFIED!!! DONT RUN MORE THAN ONCE
        _log_msg "Starting e2fsck"
        /bin/e2fsck -p -f -C 0 /dev/vda1 || true
        _log_msg "Starting shell"
        /bin/sh
        
        
            # FIXME This has no error checking
            # Mount root
            if [ "${FSTYPE}" != "unknown" ]; then
                    mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt}
            else
                    mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt}
            fi
      • Далее создаем файл etc/mtab, при отстутствии которого утилиты e2fsck и resize2fs отказываются работать
        touch ~/initrd/etc/mtab
      • Собираем патченный initrd назад
        cd ~/initrd/
        find ./ | cpio -H newc -o > /tmp/initrd.cpio
        64097 blocks
        gzip -c /tmp/initrd.cpio > /boot/initrd-resize.img
      • Теперь добавим в меню GRUB новую строчку для загрузки нашего initrd, для этого не будем хардкодить, а объявим его в файле /etc/grub.d/40_custom
        #!/bin/sh
        exec tail -n +3 $0
        # This file provides an easy way to add custom menu entries. Simply type the
        # menu entries you want to add after this comment. Be careful not to change
        # the 'exec tail' line above.
        menuentry 'Our resize initrd' --class debian --class gnu-linux --class gnu --class os {
            load_video
            insmod gzio
            insmod part_msdos
            insmod ext2
            set root='(hd0,msdos1)'
            search --no-floppy --fs-uuid --set=root 89839485-a3d7-4d72-b96d-aba559b16634
            echo	'Loading Linux 3.2.0-4-amd64 ...'
            linux	/boot/vmlinuz-3.2.0-4-amd64 root=UUID=660f79dc-c152-4e15-ad61-7075b42de609 ro quiet
            echo	'Loading initial ramdisk ...'
            initrd	/boot/initrd-resize.img
        }
        
      • Обновляем список GRUB и перезагружаемся в патченный inirtd (для выбора нужного пункта в меню GRUB используем панель хостера и кнопку «Открыть консоль»)
        update-grub
        reboot
  3. Пока мы искали как попасть в VNC-консоль в панели vscale, необходимый нам раздел уже был проверен автоматически скриптом, поэтому сразу уменьшаем файловую систему до 1ГБ (системе хватит, она занимает около 800МБ)
    resize2fs /dev/vda1 1G
  4. Затем с помощью fdisk отрезаем раздел и создаем новый под LVM, оба primary, первый +1G, второй — всё остальное пространство. Не забываем поставить флаг активности на первый раздел
  5. На всякий случай проверяем e2fsck и подгоняем файловую систему под размер первого раздела
  6. Перезагружаемся назад в обычную операционку, первый пункт меню
  7. Ставим пакет lvm2, создаем физический раздел, группу томов и наконец логический том под систему, которую будем переносить. Размер выбираем исходя из наших нужд
    apt-get install lvm2
    pvcreate /dev/vda2
    vgcreate vg0 /dev/vda2
    lvcreate -n old_system -L10G vg0
  8. Идем на старый сервер в Селектеле, выключаем там swap и используем освободившееся место на диске для создания снапшота корневой файловой системы. В большинстве случаев этого должно хватить. Если раздел был невообразимо огромен, колдуем с добавлением дополнительных дисков в панели хостера и используем их
    swapoff /dev/vg/swap
    lvremove /dev/vg/swap
    lvcreate --snapshot --name my_shot --size 1.9G /dev/vg/root
  9. Переносим наш снапшот системы в новую виртуалку
    dd if=/dev/vg/my_shot bs=4096 | ssh root@new_vscale -C 'dd of=/dev/vg1/old_system bs=4096'
  10. Если у нас отличаются ядра (3.1.0-1.2-xen на старом и 3.2.0-4-amd64 на новом, в моем случае), то маунтим перенесенный снапшот и переносим в раздел старой системы папку /lib/modules/3.2.0-4-amd64 с новой виртуалки. Иначе после ребута в старую систему с новым ядром ничего не заведется
  11. При отличии версий операционных систем может вылезти еще косяк с inittab, в 6 и 7 дебианах они отличаются вот этим местом (комментим и добавляем старое поведение, иначе после загрузки системы мы в нее не залогинимся)
    #new system
    #0:12345:respawn:/sbin/getty xvc0 9600
    
    #old system
    1:2345:respawn:/sbin/getty 38400 tty1
    2:23:respawn:/sbin/getty 38400 tty2
    3:23:respawn:/sbin/getty 38400 tty3
    4:23:respawn:/sbin/getty 38400 tty4
    5:23:respawn:/sbin/getty 38400 tty5
    6:23:respawn:/sbin/getty 38400 tty6
  12. Теперь пробуем загружаться с этого Франкенштейна, для этого в наш /etc/grub.d/40_custom прописываем загрузку нового ядра с LVM
    menuentry 'Debian GNU/Linux Old System' --class debian --class gnu-linux --class gnu --class os {
        load_video
        insmod gzio
        insmod part_msdos
        insmod ext2
        set root='(hd0,msdos1)'
        search --no-floppy --fs-uuid --set=root 89839485-a3d7-4d72-b96d-aba559b16634
        echo	'Loading Linux 3.2.0-4-amd64 ...'
        linux	/boot/vmlinuz-3.2.0-4-amd64 root=/dev/mapper/vg0-old_system ro consoleblank=0 panic=15
        echo	'Loading initial ramdisk ...'
        initrd	/boot/initrd.img-3.2.0-4-amd64
    }
    
  13. Обновляем GRUB, для автоматизации выставляем загрузку с этой строчки всегда по дефолту. Для этого правим строчку GRUB_DEFAULT=»0″ в файле /etc/default/grub на ту, которой соответствует наше творчество. Отсчет с нуля
  14. Если всё прошло гладко, попадаем внутрь старой системы на новом ядре. Правим сетевые параметры, ищем вхождения старого IP адреса по всей папке /etc и после внесения необходимых изменений удивляемся, что это еще и работает о_О

Ссылки: