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

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

  • Изменяем размер корневой файловой системы на новой виртуалке
  • Переносим снапшот 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 и после внесения необходимых изменений удивляемся, что это еще и работает о_О

Ссылки: