Перевести уже работающий Linux-сервер на RAID1 значительно сложнее, чем создать RAID во время установки системы. Особенно если сервер находится удалённо, работает в режиме UEFI, содержит виртуальные машины и его нельзя надолго останавливать.
В этой статье разберём практический случай миграции CentOS Stream 8 на программный RAID1 средствами mdadm без переустановки операционной системы.
Основной принцип миграции следующий: сначала создаём деградированный RAID1 на свободном диске, полностью переносим туда систему, делаем новый диск загрузочным и проверяем реальный запуск с него. Только после успешной загрузки старый системный диск можно переразметить и добавить вторым зеркалом.
Исходная конфигурация сервера
На сервере изначально использовалась следующая схема:
/dev/sda 240 GB SSD — системный диск
├─sda1 600 MB /boot/efi
├─sda2 1 GB /boot
├─sda3 50 GB /
├─sda4 7.8 GB swap
└─sda5 164 GB /Data
/dev/sdd 240 GB SSD — пустой диск
/dev/sdb 4 TB HDD — старый /Backup
/dev/sdc 4 TB HDD — новый пустой диск
/dev/nvme0n1 256 GB NVMe
└─nvme0n1p1 /SSD
Каталоги /Data, /SSD и /Backup использовались в том числе виртуальными машинами KVM/libvirt.
Необходимо было получить следующую конфигурацию:
sda + sdd
↓
RAID1
md11 → /boot
md12 → / и /Data
sdb + sdc
↓
md10 → /Backup
nvme0n1p1 → /SSD
При этом отдельный раздел /Data было решено ликвидировать. После миграции /Data стал обычным каталогом внутри большой корневой файловой системы /.
Важное предупреждение
Команды wipefs, parted, mkfs и mdadm могут уничтожить данные.
Перед выполнением любых операций необходимо несколько раз проверить имена дисков:
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
findmnt
blkid
df -hT
cat /etc/fstab
Если сервер находится удалённо, особенно важно не уничтожать старый системный диск до тех пор, пока новый диск не пройдёт настоящую контрольную загрузку.
RAID1 не является резервной копией. RAID защищает от отказа физического диска, но не защищает от удаления файлов, повреждения файловой системы, шифровальщика, ошибки администратора или повреждения данных приложением.
Создание RAID1 для /Backup
Начнём с хранилища резервных данных.
Исходная схема:
/dev/sdb → старый /Backup
/dev/sdc → новый пустой HDD 4 TB
Заполненный sdb нельзя было сразу использовать для создания нового RAID, поэтому сначала массив был создан в деградированном состоянии только на пустом sdc.
Разметка нового диска
parted -s /dev/sdc mklabel gpt
parted -s -a optimal /dev/sdc mkpart primary 1MiB 100%
parted -s /dev/sdc set 1 raid on
partprobe /dev/sdc
udevadm settle
Создание деградированного RAID1
mdadm --create /dev/md10 \
--metadata=1.2 \
--level=1 \
--raid-devices=2 \
--bitmap=internal \
missing /dev/sdc1
После этого:
cat /proc/mdstat
покажет примерно:
md10 : active raid1 sdc1[1]
[2/1] [_U]
Это нормальное состояние: массив рассчитан на два устройства, но пока работает только на одном.
Создание файловой системы
mkfs.ext4 -m 0 -L BACKUP_RAID /dev/md10
Монтируем:
mkdir -p /mnt/backup-raid
mount /dev/md10 /mnt/backup-raid
Перенос данных
Перед копированием необходимо остановить виртуальные машины, которые используют файлы на старом /Backup.
Для обычных данных можно использовать:
rsync -aH --numeric-ids --info=progress2 \
/Backup/ \
/mnt/backup-raid/
Для активно работающих виртуальных дисков простого копирования .img или .qcow2 недостаточно. Виртуальную машину лучше корректно остановить либо использовать штатный механизм snapshot/backup гипервизора.
После переноса меняем /etc/fstab, чтобы /Backup монтировался с md10.
UUID определяем командой:
blkid /dev/md10
Пример строки:
UUID=<UUID_MD10> /Backup ext4 defaults 1 2
Проверяем:
findmnt /Backup
Должно быть:
/Backup /dev/md10 ext4
Перевод системного диска на RAID1
Теперь переходим к системным SSD.
/dev/sda — работающая система
/dev/sdd — пустой SSD такого же размера
Главный принцип безопасности: старый sda пока вообще не трогаем.
На пустом sdd создаём будущую систему, загружаемся с неё и только потом переразмечаем sda.
Разметка нового системного SSD
Для конкретного диска объёмом 240057409536 байт была использована следующая схема:
wipefs -a /dev/sdd
parted -s /dev/sdd mklabel gpt
parted -s /dev/sdd unit s mkpart ESP fat32 2048 1230847
parted -s /dev/sdd set 1 esp on
parted -s /dev/sdd unit s mkpart primary 1230848 3327999
parted -s /dev/sdd set 2 raid on
parted -s /dev/sdd unit s mkpart primary 3328000 468850687
parted -s /dev/sdd set 3 raid on
partprobe /dev/sdd
udevadm settle
Получаем:
sdd
├─sdd1 600M EFI
├─sdd2 1G Linux RAID
└─sdd3 222G Linux RAID
Важно: номера секторов выше подходят только для дисков с такой же геометрией. На другом сервере границы необходимо рассчитывать отдельно.
Создание RAID1 для /boot
mdadm --create /dev/md11 \
--metadata=1.0 \
--level=1 \
--raid-devices=2 \
--bitmap=none \
missing /dev/sdd2
Для /boot используется metadata 1.0.
Создание RAID1 для корневой файловой системы
mdadm --create /dev/md12 \
--metadata=1.2 \
--level=1 \
--raid-devices=2 \
--bitmap=none \
missing /dev/sdd3
Проверяем:
cat /proc/mdstat
Нормальное состояние на данном этапе:
md11 [2/1] [_U]
md12 [2/1] [_U]
Создание файловых систем
EFI
mkfs.vfat -F32 -n EFI_RAID2 /dev/sdd1
/boot
mkfs.ext4 -L boot_raid /dev/md11
Корень /
mkfs.ext4 -L root_raid /dev/md12
Монтирование будущей системы
mkdir -p /mnt/newroot
mount /dev/md12 /mnt/newroot
mkdir -p /mnt/newroot/boot
mount /dev/md11 /mnt/newroot/boot
mkdir -p /mnt/newroot/boot/efi
mount /dev/sdd1 /mnt/newroot/boot/efi
Проверяем:
findmnt /mnt/newroot
findmnt /mnt/newroot/boot
findmnt /mnt/newroot/boot/efi
Перенос работающей CentOS на md12
Для переноса корневой системы используем rsync.
Очень важен параметр -x. Он запрещает переходить на другие файловые системы, поэтому команда не начинает копировать внутрь root содержимое отдельно смонтированных /Data, /Backup, /SSD, /boot, /proc, /sys и других точек монтирования.
rsync -aHAx --numeric-ids --info=progress2 \
/ \
/mnt/newroot/
Первоначально использовался вариант с -X, но при переносе SELinux extended attributes появились ошибки:
rsync_xal_set:
lremovexattr(...,"security.selinux") failed:
Permission denied
Поэтому перенос повторили без -X, а SELinux-контексты решили восстановить отдельно после успешной миграции.
Перенос /boot
rsync -aHAx --numeric-ids --info=progress2 \
/boot/ \
/mnt/newroot/boot/
Перенос EFI
rsync -rt --info=progress2 \
/boot/efi/ \
/mnt/newroot/boot/efi/
Объединение /Data с корневой файловой системой
До миграции /Data находился на отдельном разделе:
/dev/sda5 → /Data
После миграции отдельный раздел решили убрать.
Перед переносом необходимо остановить виртуальные машины, которые используют файлы на /Data.
Проверить открытые файлы:
fuser -vm /Data
После остановки VM:
mkdir -p /mnt/newroot/Data
rsync -aHAx --numeric-ids --info=progress2 \
/Data/ \
/mnt/newroot/Data/
Проверяем размеры:
du -sh /Data
du -sh /mnt/newroot/Data
После перехода на новую систему:
/ → md12
/Data → обычный каталог внутри md12
Замена swap-раздела на swapfile
Отдельный swap-раздел после объединения пространства больше не нужен.
fallocate -l 8G /mnt/newroot/swapfile
chmod 600 /mnt/newroot/swapfile
mkswap /mnt/newroot/swapfile
Создание нового /etc/fstab
Получаем UUID:
ROOTUUID=$(blkid -s UUID -o value /dev/md12)
BOOTUUID=$(blkid -s UUID -o value /dev/md11)
EFIUUID=$(blkid -s UUID -o value /dev/sdd1)
BACKUPUUID=$(blkid -s UUID -o value /dev/md10)
SSDUUID=$(blkid -s UUID -o value /dev/nvme0n1p1)
Новый /etc/fstab:
UUID=<ROOTUUID> / ext4 defaults 1 1
UUID=<BOOTUUID> /boot ext4 defaults 1 2
UUID=<EFIUUID> /boot/efi vfat umask=0077,shortname=winnt 0 2
/swapfile none swap defaults 0 0
UUID=<BACKUPUUID> /Backup ext4 defaults 1 2
UUID=<SSDUUID> /SSD ext4 defaults 1 1
Отдельной записи для /Data больше нет.
Настройка mdadm.conf
Проверяем найденные массивы:
mdadm --detail --scan
Пример:
ARRAY /dev/md10 ...
ARRAY /dev/md11 ...
ARRAY /dev/md12 ...
Новая система должна содержать эти массивы в:
/etc/mdadm.conf
Подготовка chroot
Подключаем системные файловые системы:
mount --bind /dev /mnt/newroot/dev
mount --bind /dev/pts /mnt/newroot/dev/pts
mount -t proc /proc /mnt/newroot/proc
mount --bind /sys /mnt/newroot/sys
mount --bind /run /mnt/newroot/run
Заходим:
chroot /mnt/newroot /bin/bash
Пересборка initramfs с поддержкой RAID
Для текущего ядра:
dracut -N -f \
--add mdraid \
--mdadmconf \
/boot/initramfs-4.18.0-408.el8.x86_64.img \
4.18.0-408.el8.x86_64
Проверяем наличие mdraid и mdadm:
lsinitrd /boot/initramfs-4.18.0-408.el8.x86_64.img | \
grep -Ei 'mdadm|mdraid|mdadm.conf'
Также можно проверить встроенный конфигурационный файл:
lsinitrd \
/boot/initramfs-4.18.0-408.el8.x86_64.img \
/etc/mdadm.conf
Настройка kernelopts
Проверяем текущие параметры:
grub2-editenv /boot/grub2/grubenv list
Корневой раздел должен указываться через UUID новой файловой системы md12:
root=UUID=<UUID_MD12>
Также указываем mdraid-массив:
rd.md.uuid=<UUID_ARRAY_MD12>
Для первой удалённой тестовой загрузки можно временно использовать:
enforcing=0
Например:
grubby --update-kernel=ALL \
--args="root=UUID=<ROOT_UUID> rd.md.uuid=<MD12_UUID> enforcing=0"
Старые параметры root=, resume= и rd.md=0 необходимо удалить.
После изменения:
grub2-editenv /boot/grub2/grubenv list
Настройка GRUB для UEFI
Проверяем наличие загрузочных файлов:
find /boot/efi/EFI -maxdepth 2 -type f
В CentOS обычно присутствуют:
/boot/efi/EFI/centos/shimx64.efi
/boot/efi/EFI/centos/grubx64.efi
/boot/efi/EFI/centos/grub.cfg
Создаём конфигурацию GRUB:
grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
Если os-prober начинает сканировать старые диски и создаёт ошибки device-mapper, его можно временно отключить:
chmod -x /etc/grub.d/30_os-prober
grub2-mkconfig \
-o /boot/efi/EFI/centos/grub.cfg
chmod +x /etc/grub.d/30_os-prober
Проверяем синтаксис:
grub2-script-check /boot/efi/EFI/centos/grub.cfg
echo $?
Результат должен быть:
0
Также полезно проверить, что GRUB подключает поддержку mdraid:
grep -nE 'mdraid|blscfg' \
/boot/efi/EFI/centos/grub.cfg
В рабочей конфигурации должна присутствовать строка:
insmod mdraid1x
Безопасная тестовая загрузка через UEFI BootNext
На удалённом сервере не следует сразу менять постоянную загрузочную запись.
Создаём новую UEFI-запись для sdd:
efibootmgr -c \
-d /dev/sdd \
-p 1 \
-L "CentOS RAID TEST" \
-l '\EFI\centos\shimx64.efi'
Проверяем:
efibootmgr -v
Например:
Boot0000* CentOS RAID TEST
Назначаем эту запись только для следующего запуска:
efibootmgr -n 0000
Проверяем:
efibootmgr
Должно появиться:
BootNext: 0000
После корректного выключения виртуальных машин выполняем:
sync
reboot
Проверка после первой загрузки с RAID
После восстановления SSH выполняем:
efibootmgr
findmnt /
findmnt /boot
findmnt /boot/efi
findmnt /Data
cat /proc/mdstat
swapon --show
getenforce
Правильный результат:
/ → /dev/md12
/boot → /dev/md11
/boot/efi → /dev/sdd1
/Data → не является отдельной файловой системой
swap → /swapfile
SELinux → Permissive
При этом массивы пока деградированы:
md11 [_U]
md12 [_U]
Это нормально, потому что старый sda ещё не был добавлен.
Обязательная контрольная загрузка перед уничтожением старого sda
После первого успешного запуска необходимо отдельно проверить постоянную UEFI-запись нового SSD.
После reboot проверяем:
efibootmgr
findmnt /
findmnt /boot
findmnt /boot/efi
Необходимо убедиться, что:
BootCurrent → запись нового sdd
/ → /dev/md12
/boot → /dev/md11
/boot/efi → /dev/sdd1
Только после этого можно уничтожать старую систему на sda.
Добавление старого системного SSD в RAID1
После проверки загрузки старый sda переразмечивается аналогично sdd:
sda1 600M EFI
sda2 1G Linux RAID
sda3 222G Linux RAID
Перед добавлением обязательно сравниваем размеры:
blockdev --getsz /dev/sda2
blockdev --getsz /dev/sdd2
blockdev --getsz /dev/sda3
blockdev --getsz /dev/sdd3
Добавление второго диска в /boot RAID
mdadm --manage /dev/md11 --add /dev/sda2
Следим:
watch -n 2 cat /proc/mdstat
После завершения:
md11 [UU]
Добавление второго диска в root RAID
mdadm --manage /dev/md12 --add /dev/sda3
Следим:
watch -n 5 cat /proc/mdstat
В нашем случае итоговый результат:
md11 : active raid1 sda2[2] sdd2[1]
[UU]
md12 : active raid1 sda3[2] sdd3[1]
[UU]
Второй EFI-раздел
EFI System Partition в RAID1 не включается.
На втором SSD создаём отдельный FAT32 ESP:
mkfs.vfat -F32 -n EFI_RAID1 /dev/sda1
Монтируем:
mkdir -p /mnt/efi-sda
mount /dev/sda1 /mnt/efi-sda
Копируем текущий рабочий EFI:
rsync -rt /boot/efi/ /mnt/efi-sda/
sync
После копирования:
umount /mnt/efi-sda
Создаём UEFI-запись:
efibootmgr -c \
-d /dev/sda \
-p 1 \
-L "CentOS RAID SDA" \
-l '\EFI\centos\shimx64.efi'
Таким образом каждый системный SSD содержит собственный EFI System Partition, а /boot и / защищены RAID1.
Диагностика проблемного HDD при создании RAID1 для /Backup
Во время создания RAID1 для /Backup возник отдельный интересный случай.
Старый диск /dev/sdb имел историю ошибок чтения UNC.
SMART показывал:
SMART overall-health: PASSED
Reallocated_Sector_Ct 0
Current_Pending_Sector 0
Offline_Uncorrectable 0
Reported Uncorrectable Errors: 6
Несмотря на SMART PASSED, ранее в журнале диска присутствовали реальные UNC.
Первая попытка добавить диск
После добавления в RAID:
md10 : active raid1 sdb1[2](W)(F) sdc1[1]
Обозначения:
W = write-mostly
F = faulty
Диск был исключён из массива.
Проверка прямой записи
dd if=/dev/zero of=/dev/sdb1 \
bs=4M count=256 \
oflag=direct conv=fsync \
status=progress
Запись 1 GiB прошла успешно со скоростью около 190 MB/s.
Проверка известного проблемного участка
Дополнительно был перезаписан участок, содержащий ранее проблемный LBA:
dd if=/dev/zero of=/dev/sdb1 \
bs=4096 \
seek=14454479 \
count=4096 \
oflag=direct \
conv=fsync \
status=progress
Затем этот же участок был прочитан:
dd if=/dev/sdb1 of=/dev/null \
bs=4096 \
skip=14454479 \
count=4096 \
iflag=direct \
status=progress
Обе операции завершились с:
RC=0
Полный SMART Extended Test
smartctl -t long /dev/sdb
Для данного Toshiba 4 TB тест занял несколько часов.
Финальный результат:
Extended offline
Completed without error
После полного теста:
Reallocated_Sector_Ct 0
Current_Pending_Sector 0
Offline_Uncorrectable 0
Device Error Count 6
То есть старые шесть ошибок остались в истории SMART, но новых ошибок за полный проход поверхности не появилось.
Повторное добавление проблемного HDD в RAID
После полного тестирования диск был добавлен в массив ещё раз.
mdadm /dev/md10 --add /dev/sdb1
После успешного старта recovery для диска был включён режим write-mostly:
echo writemostly > \
/sys/block/md10/md/dev-sdb1/state
Проверяем:
cat /sys/block/md10/md/dev-sdb1/state
Во время восстановления:
write_mostly,spare
Массив:
md10 : active raid1 sdb1[2](W) sdc1[1]
[>....................] recovery = ...
После успешной синхронизации ожидаем:
md10 [UU]
и:
in_sync,write_mostly
Режим write-mostly означает, что Linux MD по возможности будет читать данные с другого зеркала и использовать данный диск преимущественно для записи копии.
Для диска с историей UNC это разумная дополнительная мера, хотя она не отменяет необходимости дальнейшего SMART-мониторинга.
Что делать с отдельным NVMe
На сервере дополнительно используется:
/dev/nvme0n1p1 → /SSD
На нём находятся наиболее производительно-зависимые диски виртуальных машин.
Добавлять NVMe в RAID1 с обычными SATA SSD нецелесообразно: производительность записи зеркала будет ограничена более медленным устройством.
Поэтому NVMe оставлен отдельным:
/SSD
Но одиночный NVMe становится отдельной точкой отказа.
Следовательно, данные с /SSD необходимо регулярно резервировать на:
/Backup
Для образов работающих виртуальных машин следует использовать консистентный backup: snapshot, guest-agent, штатные средства libvirt либо временную остановку VM.
Простое копирование активно работающего образа виртуального диска через cp или rsync не является полноценным резервным копированием.
Итоговая конфигурация сервера
SYSTEM RAID1
┌─────────────────────┐
│ │
/dev/sda /dev/sdd
│ │
sda2 ├────── md11 ────────┤ sdd2
│ /boot │
│ │
sda3 ├────── md12 ────────┤ sdd3
│ / │
│ /Data │
└─────────────────────┘
EFI:
sda1 ─ отдельная ESP
sdd1 ─ отдельная ESP
BACKUP RAID1
┌─────────────────────┐
│ │
sdb1 ├────── md10 ────────┤ sdc1
│ /Backup │
└─────────────────────┘
NVMe:
nvme0n1p1
│
/SSD
│
быстрые диски VM
│
backup → /Backup
Полезные команды мониторинга RAID
Общее состояние
cat /proc/mdstat
Подробная информация
mdadm --detail /dev/md10
mdadm --detail /dev/md11
mdadm --detail /dev/md12
Нагрузка на диски
iostat -xm 5
Сообщения ядра в реальном времени
journalctl -k -f
Поиск дисковых ошибок
journalctl -k --no-pager | \
egrep -i 'I/O error|UNC|medium error|failed|ata|sd[a-z]'
Полный SMART
smartctl -x /dev/sdb
Extended SMART Test
smartctl -t long /dev/sdb
Результаты self-test
smartctl -l selftest /dev/sdb
Возвращение SELinux в Enforcing
На время первой удалённой загрузки мы использовали:
enforcing=0
После полной проверки RAID, загрузчика, сетевых интерфейсов и сервисов необходимо вернуть штатный режим SELinux.
Для полной перемаркировки файловой системы:
touch /.autorelabel
Убираем временный параметр ядра:
grubby --update-kernel=ALL \
--remove-args="enforcing=0"
После этого выполняем перезагрузку в запланированное окно обслуживания:
reboot
Первая загрузка после полной SELinux-перемаркировки может занять значительно больше времени, поэтому на удалённом сервере желательно иметь доступ к IPMI, iDRAC, iLO, KVM или другой out-of-band консоли.
После загрузки:
getenforce
Ожидаемый результат:
Enforcing
Итог
Перевести уже установленный CentOS Stream 8 с обычного системного диска на программный RAID1 можно без переустановки операционной системы.
Самая безопасная схема миграции для удалённого сервера заключается не в попытке переделать работающий root «на месте», а в последовательном переносе:
- Создать деградированный RAID1 на свободном диске.
- Создать новые файловые системы.
- Перенести работающую систему через rsync.
- Перенести /boot и EFI.
- Объединить /Data с новой корневой файловой системой.
- Создать новый fstab и mdadm.conf.
- Пересобрать initramfs с поддержкой mdraid.
- Настроить GRUB и UEFI.
- Выполнить тестовую загрузку через BootNext.
- Проверить реальную загрузку с нового SSD.
- Только после этого переразметить старый системный диск.
- Добавить второй диск в RAID1 и дождаться состояния [UU].
В результате в нашем случае удалось:
- перевести
/bootна RAID1; - перевести корневую файловую систему
/на RAID1; - объединить старые
/и/Data; - заменить отдельный swap-раздел на swapfile;
- создать отдельный RAID1 для
/Backup; - сохранить NVMe как быстрое хранилище виртуальных машин;
- создать независимые EFI-разделы на обоих системных SSD;
- сохранить возможность загрузки сервера при отказе одного системного диска.
И главное правило, которое стоит помнить после завершения всех работ:
состояние RAID1 [UU] обеспечивает отказоустойчивость дисков, но RAID не заменяет резервное копирование.

Комментариев пока нет
Будьте первым — оставьте свой.