Перенос установленной ОС Linux на программный RAID.

Предположим, у нас есть сервер с установленной на нём операционной системой Linux. Система установлена на единственном диске и нам нужно сделать отказоустойчивую конфигурацию, застраховавшись от выхода этого диска из строя. Для этого мы добавляем к серверу второй диск и хотим создать RAID1 («зеркало»), т. е. конфигурацию, при которой все данные с первого диска дублируются на второй и при выходе из строя одного из дисков система работает на оставшемся. Ситуация осложняется тем, что на нашем сервере отсутствует аппаратный RAID-контроллер, поэтому RAID будем строить программный (софтовый).

Все описываемые ниже действия проведены на операционной системе Ubuntu 12.04. Для других операционных систем семейства Linux команды могут несколько отличаться от приведённых, но общие принципы построения программных RAID-массивов останутся неизменными. Мы ограничимся рассмотрением RAID1, но путём небольшой модификации данную инструкцию можно применять и для массивов других типов, например, RAID5, RAID6, RAID10 и т. п. Мы предполагаем, что объём нового (добавляемого) диска не меньше чем у старого (работающего). (На самом деле можно и меньше – см. примечание 5.) Также будем предполагать, что сервер можно на некоторое время остановить и несколько раз перезагрузить.

Внимание! Операция переноса при ошибке может привести к потере данных или к неработоспособности сервера. Перед её выполнением создайте резервную копию!

Будем считать, что старый диск у нас в системе обозначен sda, а новый – sdb. Также будем считать, что на sda у нас три раздела:

sda1    /boot    Загрузочный раздел
sda2    /        Корневой раздел
sda3    swap     Раздел подкачки

 

Первый способ – RAID-массив на каждый раздел.

Первое действие, которое нам необходимо сделать – это скопировать таблицу разделов с первого диска на второй. Сделаем это следующим образом:

sfdisk -d /dev/sda | sfdisk /dev/sdb

В этой последовательности первая команда выдаёт список (дамп) разделов первого диска (ключ -d), а вторая записывает этот список разделов на второй диск, полностью затирая существующую таблицу.

Внимание! После этой операции данные на втором диске будут потеряны! Убедитесь, что на нём нет ничего важного!

Теперь можно убедиться, что на обоих дисках одинаковые таблицы разделов, проанализировав вывод следующих двух команд:

sfdisk -d /dev/sda
sfdisk -d /dev/sdb

Следующим шагом изменим идентификаторы разделов второго диска. Сейчас они, скорее всего, равны 83 (Linux) для sdb1 и sdb2 и 82 (Linux swap) для sdb3. Нам нужно установить идентификаторы этих разделов в fd (Linux raid auto). Для этого выполняем следующую команду:

fdisk /dev/sdb

После появления на экране приглашения ввода команды выполняем следующие действия:

t  (команда смены идентификатора раздела)
1  (изменяемый раздел)
fd  (новый идентификатор раздела)

Повторяем эту последовательность для второго и третьего разделов, меняя на втором шаге номер раздела:

t 
2 
fd 
t 
3 
fd 

С помощью команды p можно посмотреть, что у нас получилось. Стоит помнить, что на данном этапе никакие изменения на диск ещё не записаны и можно выйти без сохранения изменений с помощью команды q. Если же нас всё устраивает, то вводим команду w, которая предписывает fdisk записать на диск изменения и выйти.

Примечание 1. Изменение идентификаторов раздела является необязательной операцией, программный RAID нечувствителен к ним и может работать с любыми идентификаторами. Изменение производится в основном для того, чтобы сторонние программы работы с дисковыми разделами правильно интерпретировали их содержимое.

Разделы второго диска созданы. Теперь будем строить на этих разделах RAID-массивы. Пока что мы работаем только со вторым диском, разделы и данные первого диска остаются неизменными. Поэтому вначале построенные нами массивы будут «деградированными», состоящими только из одного диска вместо двух.

Устанавливаем пакет mdadm:

apt-get install mdadm

Создаём массив на первом разделе нового диска:

mdadm --create /dev/md0 --level=1 --raid-devices=2 missing /dev/sdb1

Параметр --level=1 указывает mdadm создать массив RAID1 («зеркало»), --raid-devices=2 создаёт массив, располагающийся на двух устройствах. Поскольку мы работаем только на одном диске, вместо первого устройства мы указываем зарезервированное слово missing, что позволяет нам создать «деградированный» массив. Последний параметр команды указывает на раздел, который будет использоваться для массива. После запуска данной команды на исполнение мы можем получить предупреждение, подобное следующему:

mdadm: Note: this array has metadata at the start and
    may not be suitable as a boot device.  If you plan to
    store '/boot' on this device please ensure that
    your boot-loader understands md/v1.x metadata, or use
    --metadata=0.90
Continue creating array?

Здесь mdadm предупреждает нас, что наш загрузчик должен поддерживать метаданные для программного RAID версии 1.x и рекомендует добавить параметр --metadata=0.90 в случае, если поддержка отсутствует. В Ubuntu 12.04 загрузчик grub такие метаданные поддерживает, поэтому смело отвечаем «Y» (Yes) и жмём клавишу Enter. Массив создан.

Аналогичным образом создаются массивы на оставшихся разделах диска:

mdadm --create /dev/md1 --level=1 --raid-devices=2 missing /dev/sdb2
mdadm --create /dev/md2 --level=1 --raid-devices=2 missing /dev/sdb3

В итоге мы получили три массива:

md0    /boot    Загрузочный раздел
md1    /        Корневой раздел
md2    swap     Раздел подкачки

Примечание 2. Вовсе не обязательно начинать нумерацию RAID-массивов именно с нуля и нумеровать массивы подряд. Можно было бы, например, создать массивы с именами md10, md34 и md505.

Форматируем наши массивы (предполагается, что корень имеет файловую систему ext4, а раздел /bootext2):

mkfs.ext2 /dev/md0
mkfs.ext4 /dev/md1
mkswap /dev/md2

Если мы сейчас перезагрузим машину, то столкнёмся с проблемами – она будет сообщать о «деградированном» RAID-массиве и останавливаться на стадии initramfs. Чтобы машина нормально загрузилась, надо разрешить ей работать с «деградированными» массивами. Для этого запускаем команду

dpkg-reconfigure mdadm

и соглашаемся со всеми её предложениями, нажимая клавишу Enter, за исключением последнего вопроса, в котором нас спрашивают, следует ли загружать систему в случае разрушенных массивов (Do you want to boot system if your RAID becomes degraded?), на который нужно ответить «Yes». Осталось только обновить initrd командой

update-initramfs -u

Теперь, если перезагрузить систему, она нормально загрузится несмотря на неполные RAID-массивы.

Примечание 3. Возможно, вы не хотите, чтобы машина загружалась при выходе из строя одного из дисков массива. В этом случае вызывать dpkg-reconfigure не нужно. При перезагрузке после вывода на экран подсказки (initramfs) нормальную загрузку можно будет продолжить, введя команду return.

Примечание 4. Если в вашей системе не одно ядро, а несколько, то, вам нужно обновить initrd для всех ядер, вызвав команду с дополнительным параметром:
update-initramfs -u -k all

В принципе, дальнейшие действия можно делать и на работающей системе без перезагрузки, но это чревато некоторыми опасностями. Дело в том, что нормально работающая система может в процессе своей работы весьма существенно менять данные на дисках, что не позволяет в общем случае скопировать на второй диск актуальные данные. В процессе копирования данные на дисках могут измениться, причём до такой степени, что данные некоторых приложений не позволят этим приложениям нормально запуститься. Самая меньшая беда что нас ожидает – потеря некоторого количества данных, например, в SQL-сервере. Чтобы ни одна из этих неприятностей не произошла, нам необходимо остановить все чувствительные к таким условиям сервисы. Один из гарантированных способов – загрузиться в режиме восстановления, когда файловые системы монтируются в режиме «только чтение». Поэтому перезагружаем машину, держа нажатой клавишу Shift. Нажатый Shift заставляет загрузчик grub вывести на экран меню со списком вариантов загрузки, которое в иных случаях либо вообще не выводится, либо проскакивает на экране так быстро, что мы ничего не успеваем заметить. В меню загрузчика выбираем строку со словами «recovery mode» («режим восстановления»). Через некоторое время на экране появится меню режима восстановления, в котором выбираем пункт «root» («Drop to root shell prompt») и оказываемся в режиме командной строки с файловыми системами, смонтированными в режиме «только чтение».

Монтируем новую корневую файловую систему к /mnt:

mount /dev/md1 /mnt

и копируем на неё данные из старой командой

cp -ax / /mnt

(можно добавить ключ -v, чтобы cp выводила имена объектов, которые она обрабатывает). Следующим шагом монтируем новый раздел /boot и копируем на него данные из старого:

mount /dev/sda1 /boot
mount /dev/md0 /mnt/boot
cp -ax /boot /mnt

(первая команда нам нужна потому, что в режиме восстановления раздел /boot на первом диске смонтирован не будет).

Все данные скопированы. Но система ещё не сможет загрузиться с нового диска. Дело в том, что на новом диске отсутствует загрузчик, а уникальные идентификаторы (UUID) разделов отличаются от прописанных в конфигурационных файлах. Связываем системные каталоги с новыми разделами и переходим в скопированную систему:

mount --bind /proc /mnt/proc
mount --bind /dev /mnt/dev
mount --bind /sys /mnt/sys
chroot /mnt

Устанавливаем первую стадию загрузчика grub на новый диск и обновляем его конфигурационный файл:

grub-install /dev/sdb
update-grub

Для полной уверенности, что загрузчик сконфигурирован правильно, стоит проверить идентификаторы дисков в конфигурационном файле grub. Выводим на экран идентификаторы RAID-массивов и сравниваем их с идентификаторами в файле grub.cfg:

blkid /dev/md*
cat /boot/grub/grub.cfg | more

(вместо второй команды можно использовать ваш любимый текстовый редактор – vi, vim, nano, mcedit и т. п.). Далее необходимо заменить UUID дисков в файле /etc/fstab. Это можно сделать, например, дописав в этот файл вывод команды blkid и отредактировав файл с помощью любого текстового редактора. Например, так:

blkid /dev/md* >> /etc/fstab
nano /etc/fstab

Все необходимые настройки произведены. Выходим из новой системы и перезагружаем систему.

exit
reboot

Не забудьте поменять порядок загрузки в BIOS, либо выбрать в загрузочном меню BIOS второй диск. Проверить,что мы загрузились с RAID можно проверив точки монтирования:

mount | grep md

В выводе команды корневой каталог (/) должен ссылаться на /dev/md1, а /boot – на /dev/md0.

Наконец, мы можем добавить к нашему массиву первый диск (sda). Это можно сделать без перезагрузки и даже без остановки сервера. Поскольку разделы на обоих дисках у нас одинаковые, достаточно просто изменить их идентификаторы и добавить к массиву. Идентификаторы меняются с помощью fdisk точно так же, как и для sdb, а для добавления разделов к массивам используем следующие команды:

mdadm --add /dev/md0 /dev/sda1
mdadm --add /dev/md1 /dev/sda2
mdadm --add /dev/md2 /dev/sda3

Теперь можно понаблюдать за процессом синхронизации массивов с помощью команды

watch cat /proc/mdstat

(выход по комбинации клавиш Ctrl+C).

Примечание 5. Применяемый нами метод копирования данных (команда cp) позволяет создать на втором диске разделы иного размера, чем на первом. Для этого разделы можно создавать, вручную указывая их размер в программе fdisk. Если размер разделов изменён, то нужно будет привести в соответствие разделы первого диска, например, с помощью команды
sfdisk -d /dev/sdb | sfdisk /dev/sda

Может возникнуть вопрос, для чего нам понадобился отказоустойчивый раздел подкачки (swap). Дело в том, что на разделе подкачки операционная система может хранить критичные данные запущенных приложений и при выходе из строя диска с разделом подкачки некоторые сервисы могут работать некорректно. Чтобы избежать такой ситуации, мы и резервируем эти данные. Если же вы строите RAID на домашнем компьютере или рабочей станции, то можно не делать RAID для подкачки, сделав вместо этого, например, два раздела подкачки на двух дисках. Но если в такой конфигурации один из дисков выйдет из строя, то компьютер, в общем случае, не сможет работать дальше в нормальном режиме и потребует, как минимум, перезагрузки.

 

Второй способ – один RAID-массив для всех разделов.

Выше мы рассматривали случай, когда для каждого раздела мы строили свой отдельный RAID-массив. Однако, можно создать один-единственный массив, на котором будут созданы разделы.

Для реализации этого подхода создаём на диске sdb с помощью fdisk единственный раздел (sdb1) с идентификатором fd. По умолчанию fdisk предлагает в качестве первого сектора для раздела сектор с номером 2048. Необходимо согласиться с таким предложением. Это связано с тем, что нужно где-то хранить первую стадию загрузчика (grub) и если мы будем строить массив на всём диске, а не на разделе или не оставим для загрузчика места, то система просто не сможет загрузиться. Запускаем fdisk командой

fdisk /dev/sdb

и выполняем следующие действия:

o  (команда создания пустой таблицы разделов)
n  (команда создания нового раздела)
p  (создаём первичный раздел)
1  (создаём раздел с номером 1)
 (соглашаемся с начальным сектором раздела)
 (соглашаемся с конечным сектором раздела)
t  (команда смены идентификатора раздела)
fd  (новый идентификатор раздела)
w  (записываем изменения на диск)

Внимание! После этой операции данные на sdb будут потеряны! Убедитесь, что на нём нет ничего важного!

Теперь создаём RAID-массив:

mdadm --create /dev/md0 --level=1 --raid-devices=2 missing /dev/sdb1

(на вопрос программы отвечаем «Y»). Следующим действием будет создание разделов на массиве с помощью fdisk:

fdisk /dev/md0

Разделы создаются аналогичным образом с помощью команды n. Для облегчения расчёта размера разделов можно предварительно выполнить команду

sfdisk -d /dev/sda

которая покажет размеры всех разделов в секторах. Затем при указании последнего сектора можно будет использовать эти размеры используя знак + (учтите, что нужно будет от размера отнять единицу!) Созданные разделы будут иметь имена md0p1, md0p2 и md0p3.

Примечание 6. Копировать разделы с помощью sfdisk нельзя, поскольку размер /dev/md0 на 2048 секторов меньше размера /dev/sdb и если sdb такого же размера, как и sda, а разделы занимают весь диск, то места не хватит и sfdisk откажется что-либо делать.

Массив создан, но если сейчас перезагрузить машину, то вместо /dev/md0 у нас возникнет массив с именем вида /dev/md127. Чтобы этого не произошло, необходимо обновить initrd:

update-initramfs -u

Далее создаём файловые системы, копируем данные, обновляем grub.cfg и fstab аналогично первому варианту создания массивов, заменяя mdN на соответствующие md0pN. Перезагружаем компьютер, выбрав в качестве загрузочного второй диск, создаём на первом такую же таблицу разделов, как на втором и устанавливаем загрузчик:

sfdisk -d /dev/sdb | sfdisk /dev/sda
grub-install /dev/sda
update-grub

После этого также нужно перезагрузиться, поскольку ядро, скорее всего, будет хранить старую таблицу разделов и mdadm не сможет корректно отработать, ссылаясь на неверные размеры разделов. (Вместо перезагрузки можно попробовать принудительно обновить таблицу разделов, выполнив команду partprobe.) Осталось добавить первый диск к массиву и наблюдать за процессом синхронизации:

mdadm --add /dev/md0 /dev/sda1
watch cat /proc/mdstat

(выход по Ctrl+C).

 

Замена диска.

Если один из дисков массива вышел из строя, то для восстановления массива достаточно заменить его и выполнить действия, аналогичные вышеописанным для добавления к RAID-массиву диска sda. А именно, создать на нём такие же разделы, как и на работающем, а затем добавить к массиву с помощью mdadm. Не забудьте установить на заменённый диск загрузчик командой вида

grub-install /dev/sdX

(вместо sdX подставьте имя нового диска) и обновить загрузчик командой

update-grub

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

mdadm --remove -f /dev/md0 /dev/sda1

(если на диске создано несколько массивов, нужно отсоединить его разделы от всех). Ключ -f заставляет mdadm принудительно прекратить использовать диск, без этого ключа mdadm откажется выполнять команду, ссылаясь на то, что устройство используется. Далее меняем диск и действуем так же, как описано выше.