GRUB на программном RAID: как не остаться без загрузки при вылете диска
Проблема, которую замечают слишком поздно
Собрали зеркало на mdadm, поставили систему, всё красиво: /dev/md0 в статусе clean, оба диска на месте. Через полгода первый диск умирает — и сервер не грузится вообще. Массив цел, данные целы, но BIOS не находит, с чего стартовать.
Причина простая: mdadm работает на уровне блочного устройства, а загрузчик живёт вне его. MBR — это первые 512 байт физического диска, они не входят в RAID-раздел и не реплицируются. Если GRUB был установлен только на /dev/sda, то на /dev/sdb в MBR лежат нули.
Ниже — как сделать правильно и как чинить, если уже поздно.
Базовый вариант
В Legacy/BIOS-режиме GRUB ставится в MBR каждого диска массива по отдельности:
grub-install --target=i386-pc --recheck /dev/sda
grub-install --target=i386-pc --recheck /dev/sdb
update-grub
Ключевой момент: аргументом идёт физический диск — /dev/sda, а не /dev/md0 и не раздел /dev/sda1. Попытка установить загрузчик на md-устройство либо завершится ошибкой, либо (что хуже) отработает не так, как вы ожидаете.
Правильный вариант для Debian и Ubuntu
Ручной grub-install — разовое действие. При очередном обновлении пакета grub-pc система переустановит загрузчик только на те диски, которые записаны в debconf. Поэтому вместо ручного вызова используем:
dpkg-reconfigure grub-pc
В диалоге пробелом отмечаем все диски массива. После этого каждое обновление GRUB будет автоматически раскатываться на оба диска.
Проверить текущее состояние и задать значение неинтерактивно (пригодится в Puppet, Ansible или в скрипте развёртывания):
debconf-show grub-pc | grep install_devices
echo 'grub-pc grub-pc/install_devices multiselect /dev/disk/by-id/ata-XXXX,/dev/disk/by-id/ata-YYYY' \
| debconf-set-selections
Обратите внимание на /dev/disk/by-id/. Имена вида sda/sdb не гарантированы: смена контроллера, добавление диска или просто другой порядок инициализации ядра — и sdb станет sdc. Загрузчик после этого поедет не туда, куда вы думали.
Требования к массиву, на котором лежит /boot
Уровень RAID
Для раздела с /boot — RAID1. Формально GRUB в BIOS-режиме умеет читать RAID5/6/10 через свои модули, но это лишний слой хрупкости в самом критичном месте загрузки. Классическая схема: небольшой отдельный /boot на зеркале, всё остальное — на любом уровне, хоть на RAID10, хоть поверх LVM.
Версия метаданных
Метаданные 1.2 работают — GRUB подхватывает их модулем mdraid1x. Но суперблок при этом лежит в начале раздела, то есть BIOS видит там не файловую систему, а служебную структуру mdadm.
Максимально безопасный вариант для /boot — метаданные 0.90 или 1.0: суперблок пишется в конец раздела, и с точки зрения любого стороннего загрузчика раздел выглядит как обычный ext2/ext4. Это тот случай, когда «устаревший» формат объективно надёжнее.
mdadm --create /dev/md1 --level=1 --raid-devices=2 \
--metadata=1.0 /dev/sda1 /dev/sdb1
Флаги и служебные разделы
- Раздел с
/bootдолжен иметь флагbootв MBR-таблице. - Если диски размечены в GPT, но загрузка идёт через BIOS — на каждом диске нужен BIOS boot partition размером около 1 МБ, тип
EF02. Без негоgrub-installпросто откажется работать: между GPT-заголовком и первым разделом нет места под core.img.
sgdisk -n1:2048:+1M -t1:EF02 /dev/sdb
Именно на этом шаге чаще всего спотыкаются при добавлении нового диска в существующий массив: разделы скопировали через sgdisk --backup/--load-backup, а вот grub-install на новый диск выполнить забыли.
Восстановление из live-системы
Сценарий: диск вылетел, сервер не грузится. Загружаемся с любого live-образа и собираем массив вручную.
# Собрать все найденные массивы
mdadm --assemble --scan
cat /proc/mdstat
# Смонтировать корень и /boot
mount /dev/md0 /mnt
mount /dev/md1 /mnt/boot # если /boot вынесен отдельно
# Пробросить служебные ФС
for i in dev dev/pts proc sys run; do mount --bind /$i /mnt/$i; done
chroot /mnt
Дальше — внутри chroot:
grub-install /dev/sda
grub-install /dev/sdb
update-grub
# Зафиксировать конфигурацию массива и пересобрать initramfs
mdadm --detail --scan >> /etc/mdadm/mdadm.conf
update-initramfs -u
Строку mdadm --detail --scan в конфиг стоит добавлять осознанно — проверьте, что там не появился дубликат ARRAY со старым UUID. Пересборка initramfs обязательна: без актуального mdadm.conf внутри initramfs ядро может собрать массив под другим именем (/dev/md127 — классика жанра) и не найти корень.
Проверка
Убедиться, что GRUB реально лежит в MBR обоих дисков:
dd if=/dev/sda bs=512 count=1 2>/dev/null | strings | grep -i grub
dd if=/dev/sdb bs=512 count=1 2>/dev/null | strings | grep -i grub
Обе команды должны что-то вывести. Если вторая молчит — загрузчика на диске нет.
Но настоящая проверка одна: физически отключить первый диск и попробовать загрузиться. Всё остальное — косвенные признаки. Пятнадцать минут даунтайма в удобное вам время стоят дешевле, чем выяснение этого вопроса в три часа ночи.
Заодно проверьте настройки BIOS/UEFI: порядок загрузки должен включать оба диска, иначе при вылете первого сервер честно упрётся в «No bootable device», имея рабочий загрузчик на втором.
Чек-лист
grub-installвыполнен на каждый физический диск массива.- В Debian/Ubuntu все диски отмечены в
dpkg-reconfigure grub-pc, устройства указаны через/dev/disk/by-id/. /boot— на RAID1, метаданные 1.0 или 0.90.- Для GPT + BIOS на каждом диске есть раздел
EF02. /etc/mdadm/mdadm.confактуален, initramfs пересобран.- В BIOS в списке загрузки присутствуют все диски.
- Загрузка с отключённым первым диском проверена вживую.
Пункт 7 не опционален. Резервный загрузчик, который никто не проверял, — это не резервный загрузчик, а предположение.