Перенос данных между серверами с помощью LVM

aquarium-PR-332-4

Вопрос масштабирования ресурсов выделенных серверов сопряжен с целым рядом сложностей: добавление памяти или дисков невозможно без простоев, а апгрейд дисковой подсистемы зачастую предполагает полный перенос всех данных (объем которых может быть очень большим) со старого сервера на новый. Простое перемещение дисков из одного сервера в другой очень часто тоже оказывается невозможным: причиной этого может быть несовместимость интерфейсов, использование разных RAID-контроллеров, географическая удаленность серверов друг от друга и т.п. Копирование же данных по сети может занимать очень много времени, в течение которого сервис простаивает. Как можно перенести данные на новый сервер, минимизировав время простоя сервисов?

Мы долго думали над этим вопросом и сегодня представляем вниманию широкой аудитории решение, которое кажется нам наиболее удачным.

LVM_v3
Процедура переноса данных с помощью рассматриваемого в этой статье способа состоит из следующих шагов:

  1. новый сервер загружается с внешнего носителя, подготавливаются блочные устройства: размечаются диски, создаются RAID-массивы;
  2. блочные устройства нового сервера экспортируются через iSCSI — создаются iSCSI таргеты;
  3. на старом сервере запускается iSCSI инициатор и подключается к таргетам на новом сервере. На старом сервере появляются и становятся доступны блочные устройства нового сервера;
  4. на старом сервере блочное устройство нового сервера добавляется в LVM группу;
  5. данные копируются на блочное устройство нового сервера с помощью зеркалирования данных в LVM;
  6. старый сервер выключается;
  7. на новом сервере, все еще загруженном с внешнего носителя, монтируется перенесенная на него ФС, в настройки вносятся необходимые правки;
  8. новый сервер перезагружается с дисков, после чего запускаются все сервисы.

Если с новым сервером обнаружены проблемы, он выключается. Включается старый сервер, все сервисы продолжают работать на старом сервере.

Предлагаемая нами методика подходит для всех ОС, где используется LVM для логических разделов и возможна установка iSCSI таргета и инициатора. На сервере, на котором мы осуществляли опытную проверку предлагаемой методики, была установлена ОС Debian Wheezy. В других ОС могут использоваться другие программы и команды, но порядок действий будет аналогичным.

Все операции осуществлялись на сервере с разметкой дисков, стандартной для наших серверов при автоматической установке ОС. Если на вашем сервере используется другая разметка дисков, параметры некоторых команд потребуется изменить.

Наш способ переноса данных рассчитан на опытных пользователей, хорошо знающих, что такое LVM, mdraid, iSCSI. Предупреждаем, что ошибки в командах могут привести к полной или частичной потере данных. Прежде чем приступать к переносу данных, необходимо сохранить резервные копии важной информации на внешнем носителе или хранилище.

Готовим новый сервер

Если вы переносите данные на сервер с иной аппаратной конфигурацией (особое внимание следует обратить на контроллер дисков), установите на новый сервер тот же дистрибутив ОС, что и на старом, а также драйверы, необходимые для работы. Проверьте, что все устройства определяются и работают. Сохраните/запишите необходимые действия, в дальнейшем их надо будет выполнить в перенесенной системе, чтобы новый сервер смог загрузиться после переноса.

Затем загрузите новый сервер с внешнего носителя. Нашим клиентам мы рекомендуем загрузиться в Selectel Rescue, используя меню управления загрузкой сервера.
По завершении загрузки подключитесь к новому серверу по SSH. Задайте для нового сервера его будущий hostname. Это необходимо в случае, если вы собираетесь использовать на новом сервере mdraid: при создании RAID-массива hostname будет сохранен в метаданных RAID-массива на всех входящих в него дисках.

# hostname cs940

Далее следует разметить диски. В нашем случае на каждом сервере будет создано по два основных раздела на каждом диске. Первые разделы будут использованы для сборки RAID1 для /boot, вторые — для сборки RAID10 под LVM Physical Volume, на котором и будут размещены основные данные.

# fdisk /dev/sda
Command (m for help): p
...
Device     Boot     Start         End          Blocks      Id  System
/dev/sda1    *       2048         2099199      1048576     fd  Linux raid autodetect
/dev/sda2         2099200      1953525167    975712984     fd  Linux raid autodetect
Command (m for help): w

Чтобы все было проще и быстрее, можно разметить только первый диск, а на остальные скопировать его разметку. Затем создайте RAID-массивы при помощи утилиты mdadm.

# sfdisk -d /dev/sda | sfdisk /dev/sdb -f
# mdadm --create /dev/md0 --level=1  --raid-devices=4 /dev/sda1 /dev/sdb1 /dev/sdc1 /dev/sdd1
# mdadm --create /dev/md1 --level=10 --raid-devices=4 /dev/sda2 /dev/sdb2 /dev/sdc2 /dev/sdd2
# mdadm --examine --scan
 ARRAY /dev/md/0 metadata=1.2 UUID=e9b2b8e0:205c12f0:2124cd91:35a3b4c8 name=cs940:0
 ARRAY /dev/md/1 metadata=1.2 UUID=4be6fb41:ab4ce516:0ba4ca4d:e30ad60b name=cs940:1

Затем установите и настройте iSCSI-таргет для копирования RAID-массивов по сети. Мы использовали tgt.

# aptitude update
# aptitude install tgt

Если при запуске tgt возникнут ошибки загрузки отсутствующих ядерных модулей, не стоит беспокоиться: они нам не понадобятся.

# tgtd
librdmacm: couldn't read ABI version.
librdmacm: assuming: 4
CMA: unable to get RDMA device list
(null): iser_ib_init(3263) Failed to initialize RDMA; load kernel modules?
(null): fcoe_init(214) (null)
(null): fcoe_create_interface(171) no interface specified.

Следующий этап — настройка LUN’ов. При создании LUN нужно указать IP старого сервера, с которого будет разрешено подключение к таргету.

# tgt-setup-lun -n tgt0 -d /dev/md0 10.0.0.1
# tgt-setup-lun -n tgt1 -d /dev/md1 10.0.0.1
# tgt-admin -s

Новый сервер готов, перейдем к подготовке старого сервера.

Подготовка старого сервера и копирование данных

Теперь подключимся к старому серверу по SSH. Установим и настроим iSCSI-инициатор, а затем подключим к нему экспортированные с нового сервера блочные устройства:

# apt-get install open-iscsi

Добавим в конфигурационный файл данные авторизации: без них инициатор не будет работать.

# nano /etc/iscsi/iscsid.conf
node.startup = automatic
node.session.auth.username = MY-ISCSI-USER
node.session.auth.password = MY-ISCSI-PASSWORD
discovery.sendtargets.auth.username = MY-ISCSI-USER
discovery.sendtargets.auth.password = MY-ISCSI-PASSWORD

Дальнейшие операции занимают довольно много времени; чтобы избежать неприятных последствий в случае их прерывания при закрытии SSH, воспользуемся утилитой screen. С ее помощью мы создадим виртуальный терминал, к которому можно будет подключаться по SSH и отключаться без завершения запущенных команд:

# apt-get install screen
# screen

Затем подключаемся к порталу и получаем список доступных таргетов; указываем при этом текущий IP-адрес нового сервера:

# iscsiadm --mode discovery --type sendtargets --portal 10.0.0.2
10.0.0.2:3260,1 iqn.2001-04.com.cs940-tgt0
10.0.0.2:3260,1 iqn.2001-04.com.cs940-tgt1

Затем подключаем все доступные таргеты и LUN’ы; в результате выполнения этой команды мы увидим список новых блочных устройств:

# iscsiadm --mode node --login
Logging in to [iface: default, target: iqn.2001-04.com.cs940-tgt0, portal: 10.0.0.2,3260] (multiple)
Logging in to [iface: default, target: iqn.2001-04.com.cs940-tgt1, portal: 10.0.0.2,3260] (multiple)
Login to [iface: default, target: iqn.2001-04.com.cs940-tgt0, portal: 10.0.0.2,3260] successful.
Login to [iface: default, target: iqn.2001-04.com.cs940-tgt1, portal: 10.0.0.2,3260] successful.

iSCSI-устройства в системе имеют те же имена, что и обычные SATA/SAS. Но при этом у двух типов устройств различается имя производителя: для iSCSI-устройств оно указано как IET.

# cat /sys/block/sdc/device/vendor
IET

Теперь можно приступить к переносу данных. Сначала отмонтируем boot и скопируем его на новый сервер:

 
# umount /boot
# cat /sys/block/sdc/size
1999744
# cat /sys/block/md0/size
1999744
# dd if=/dev/md0 of=/dev/sdc bs=1M
976+1 records in
976+1 records out
1023868928 bytes (1.0 GB) copied, 19.6404 s, 52.1 MB/s

Внимание! С этого момента не активируйте VG и не запускайте никаких LVM-утилит на новом сервере. Одновременная работа двух LVM с одним и тем же блочным устройством может вызвать порчу или потерю данных.

Теперь приступаем к переносу данных. Добавляем в VG экспортированный с нового сервера RAID10-массив:

# vgextend vg0 /dev/sdd
# pvs
 PV             VG   Fmt      Attr     PSize       PFree
 /dev/md1       vg0  lvm2     a--      464.68g    0
 /dev/sdd       vg0  lvm2     a--      1.82t      1.82t

Не забываем о том, что /dev/sdd представляет собой /dev/md1, экспортированный с нового сервера, загруженного в Rescue:

# lvs
 LV         VG     Attr          LSize       Pool Origin Data%  Move Log Copy%  Convert
 root       vg0   -wi-ao--       47.68g
 swap_1     vg0   -wi-ao--       11.44g
 var        vg0   -wi-ao--       405.55g

Теперь создаем для каждого логического тома копию на новом сервере командой lnconvert. Параметр —corelog позволит обойтись без отдельного блочного устройства под логи зеркала.

# lvconvert -m1 vg0/root --corelog /dev/sdd
 vg0/root: Converted: 0.0%
 vg0/root: Converted: 1.4%
 …
 vg0/root: Converted: 100.0% 

Так как при создании зеркальной копии LVM все операции записи осуществляются синхронно, на скорость записи будет влияет скорость канала между серверами, производительность open-iSCSI (500 мБ/с), а также задержка сети. После создания копий всех логических томов убедимся в том, что все они синхронизированы:

# lvs
 LV         VG    Attr          LSize    Pool Origin Data%  Move Log     Copy%   Convert
 root       vg0   mwi-aom-      47.68g                                  100.00
 swap_1     vg0   mwi-aom-      11.44g                                  100.00
 var        vg0   mwi-aom-      405.55g                                 100.00

На данном этапе все данные скопированы и идет синхронизация данных старого сервера с новым удаленным сервером. Чтобы минимизировать изменения в файловой системе, нужно остановить все сервисы приложений (сервис БД, веб-сервер и т.п.).

Остановив все важные сервисы, отключаем iSCSI-устройства и исключаем ставшую недоступной копию LVM. После отключения iSCSI-устройств на старом сервере будут выдаваться многочисленные сообщения об ошибках ввода-вывода, но это не должно быть причиной для беспокойства: все данные сохраняются на LVM, лежащий выше блочных устройств.

# iscsiadm --mode session -u
# vgreduce vg0 --removemissing --force
# lvs
 LV         VG   Attr         LSize   Pool Origin Data%  Move Log Copy%  Convert
 root       vg0  -wi-ao--     47.68g
 swap_1     vg0  -wi-ao--     11.44g
 var        vg0  -wi-ao--     405.55g

Теперь можно выключить старый сервер. Все данные на нем остались, и в случае каких-либо проблем с новым сервером ими всегда можно воспользоваться.

# poweroff

Запуск нового сервера

После переноса данных новый сервер нужно подготовить к самостоятельной загрузке и запустить.
Подключаемся по ssh, останавливаем iSCSI-таргет и активируем копию LVM:

# tgtadm --lld iscsi --mode target --op delete --tid 1
# tgtadm --lld iscsi --mode target --op delete --tid 2

# pvscan

Теперь исключаем из LVM копию со старого сервера; на сообщения об отсутствии второй половины не обращаем внимания.

# vgreduce vg0 --removemissing --force
 Couldn't find device with uuid 1nLg01-fAuF-VW6B-xSKu-Crn3-RDJ6-cJgIax.
 Unable to determine mirror sync status of vg0/swap_1.
 Unable to determine mirror sync status of vg0/root.
 Unable to determine mirror sync status of vg0/var.
 Wrote out consistent volume group vg0

Убедившись, что все логические тома на месте, активируем их:

# lvs
 LV         VG    Attr         LSize   Pool Origin Data%  Move Log Copy%  Convert
 root       vg0   -wi-----      47.68g
 swap_1     vg0   -wi-----      11.44g
 var        vg0   -wi-----      405.55g

# vgchange -ay
 3 logical volume(s) in volume group "vg0" now active

Желательно также проверить файловые системы на всех логических томах:

# fsck /dev/mapper/vg0-root

Далее выполним chroot в скопированную систему и внесем финальные изменения. Это можно сделать с помощью скрипта infiltrate-root, доступного в Selectel Rescue:

# infiltrate-root /dev/mapper/vg0-root

Далее все действия на сервере выполняем из chroot. Выполним монтирование всех файловых систем из fstab (по умолчанию chroot монтирует только корневую файловую систему):

Chroot:/# mount -a

Теперь обновим информацию о RAID-массивах на новом сервере в файле настроек mdadm. Удалим оттуда все данные о старых RAID-массивах (строки, начинающиеся с «ARRAY») и добавим новые:

Chroot:/# nano /etc/mdadm/mdadm.conf
Chroot:/# mdadm --examine --scan >> /etc/mdadm/mdadm.conf

Пример валидного mdadm.conf:

Chroot:/# cat /etc/mdadm/mdadm.conf
DEVICE partitions

# auto-create devices with Debian standard permissions
CREATE owner=root group=disk mode=0660 auto=yes

# automatically tag new arrays as belonging to the local system
HOMEHOST 

# instruct the monitoring daemon where to send mail alerts
MAILADDR root

# definitions of existing MD arrays
ARRAY /dev/md/0 metadata=1.2 UUID=2521ca82:2a52a408:565fab6c:43ba944e name=cs940:0
ARRAY /dev/md/1 metadata=1.2 UUID=6240c2db:b4854bd7:4c4e1510:d37e5010 name=cs940:1

После этого нужно обновить initramfs, чтобы он мог найти и загрузиться с новых RAID-массивов. Также установим на диски загрузчик GRUB и обновим его конфигурацию:

Chroot:/# update-initramfs -u
Chroot:/# grub-install /dev/sda --recheck
Installation finished. No error reported.
Chroot:/# grub-install /dev/sdb --recheck
Installation finished. No error reported.
Chroot:/# update-grub
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.2.0-4-amd64
Found initrd image: /boot/initrd.img-3.2.0-4-amd64
done

Удалим файл udev c cоответствиями названий сетевых интерфейсов и MAC-адресов (при следующей загрузке он будет создан заново):

Chroot:/# rm /etc/udev/rules.d/70-persistent-net.rules

Теперь новый сервер готов к загрузке:

Chroot:/# umount -a
Chroot:/# exit

Изменим порядок загрузки на загрузку с первого жесткого диска в меню управления сервером и перезагрузим его:

# reboot

Теперь проверим с помощью KVM-консоли, что сервер загрузился, и проверим доступ к серверу по IP-адресу. Если с новым сервером возникают какие-то проблемы, вы можете вернуться к старому серверу.

Не загружайте старый и новый серверы в рабочую ОС одновременно: они будут загружены с одним и тем же IP, что может привести к потере доступа и другим проблемам.

Адаптация файловой системы после миграции

Все данные перенесены, все сервисы работают и дальнейшие действия можно производить не торопясь. В рассматриваемом нами примере миграция данных осуществлялась на сервер с большим размером дискового пространства. Все это дисковое пространство теперь нужно задействовать. Для этого сначала расширим физический раздел, затем — логический раздел и, наконец, файловую систему в целом:

# pvresize /dev/md1
# pvs
 PV         VG   Fmt  Attr PSize PFree
 /dev/md1   vg0  lvm2 a--  1.82t 1.36t
# vgs
 VG   #PV #LV #SN Attr   VSize VFree
 vg0    1   3   0 wz--n- 1.82t 1.36t
# lvextend /dev/vg0/var /dev/md1
 Extending logical volume var to 1.76 TiB
 Logical volume var successfully resized
# lvs
 LV     VG   Attr     LSize  Pool Origin Data%  Move Log Copy%  Convert
 root   vg0  -wi-ao-- 47.68g
 swap_1 vg0  -wi-ao-- 11.44g
 var    vg0  -wi-ao--  1.76t

# xfs_growfs /var
meta-data=/dev/mapper/vg0-var    isize=256    agcount=4, agsize=26578176 blks
         =                       sectsz=512   attr=2
data     =                       bsize=4096   blocks=106312704, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0
log      =internal               bsize=4096   blocks=51910, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 106312704 to 472291328

# df -h
Filesystem            Size        Used      Avail    Use%     Mounted on
rootfs                 47G        660M        44G      2%     /
udev                   10M           0        10M      0%     /dev
tmpfs                 1.6G        280K       1.6G      1%     /run
/dev/mapper/vg0-root   47G        660M        44G      2%     /
tmpfs                 5.0M           0       5.0M      0%     /run/lock
tmpfs                 3.2G           0       3.2G      0%     /run/shm
/dev/md0              962M         36M       877M      4%     /boot
/dev/mapper/vg0-var   1.8T        199M       1.8T      1%     /var

Заключение

Несмотря на свою сложность, описанный нами подход имеет ряд преимуществ. Во-первых, он позволяет избежать длительного простоя сервера — все сервисы продолжают работать во время копирования данных. Во-вторых, в случае каких-либо проблем с новым сервером в резерве остается старый, готовый к быстрому старту. В-третьих, он универсален и не зависит от того, какие сервисы работают на сервере.

Аналогичным способом можно осуществлять миграцию и под другими операционными системами — CentOS, OpenSUSE и др. Естественно, в этом случае возможны различия в некоторых нюансах (подготовка ОС для старта на новом сервере, настройка загрузчика, initrd и т.п.).

Мы прекрасно понимаем, что предлагаемую нами методику вряд ли можно считать идеальной. Будем благодарны за любые замечания и предложения по ее усовершенствованию. Если кто-то из наших читателей может предложить собственный вариант решения проблемы переноса данных без остановки серверов, будем рады с ним ознакомиться.