Grub auf einem RAID1
Mit yast bei der Installation ist es nicht möglich die /boot Partition
auf einem Software-RAID unterzubringen.
Beschäftigt man sich näher mit dem Thema stellt sich heraus, dass einige Bedingungen erfüllt sein müssen, damit eine Boot-Partition auf einem Software-RAID funktioniert und sinnvoll ist.
- Im Bios des Rechners muss die Platte, von der gebootet werden soll, einstellbar sein.
- Der Boot-Loader muss auf jeder Platte entweder im Master Boot Record der Platte oder der Partition installiert sein.
- Der Boot-Loader muss die Blöcke, die zu den zu ladenden Files gehören, auf der Partition finden.
Besonders der letzte Punkt hat es in sich. Die für Linux verfügbaren Boot-Loader
grub und lilo verstehen nämlich von Haus aus kein RAID
und wollen alle zu ladenden Blocks auf der selben Platte finden. Damit sind solche
RAID-Level, die die Daten zu einer Datei auf unterschiedliche Platten verteilen,
für die Boot-Partition nicht verwendbar. Ein kurzer Blick genügt um festzustellen,
dass eigentlich nur RAID1 (Spiegelung) verwendbar ist. Lilo stellt keine weiteren
Ansprüche; soll jedoch grub verwendet werden, muss ein Filesystem gewählt werden, das
Grub versteht. Glücklicherweise steht der RAID-Superblock am Ende jeder Partition, so
dass jede Partition für sich genommen wie ein Filesystem auf einer ganz gewöhnlichen
Platte aussieht, wie im folgenden Experiment zu sehen ist:
pelmen:/ # mdadm -D /dev/md2
/dev/md2:
Version : 00.90.01
Creation Time : Tue Apr 12 20:35:07 2005
Raid Level : raid1
Array Size : 3148608 (3.00 GiB 3.22 GB)
Device Size : 3148608 (3.00 GiB 3.22 GB)
Raid Devices : 2
Total Devices : 2
Preferred Minor : 2
Persistence : Superblock is persistent
Update Time : Tue Apr 12 22:06:21 2005
State : clean
Active Devices : 2
Working Devices : 2
Failed Devices : 0
Spare Devices : 0
UUID : d074e4e9:0ceced94:17001820:f1ccf8e0
Events : 0.220
Number Major Minor RaidDevice State
0 8 17 0 active sync /dev/sdb1
1 8 33 1 active sync /dev/sdc1
pelmen:/ # dd if=/dev/md2 bs=10k count=1 | file -
1+0 records in
1+0 records out
10240 bytes (10 kB) copied, 0.01185 seconds, 864 kB/s
/dev/stdin: Linux rev 1.0 ext3 filesystem data (needs journal recovery)
pelmen:/ # dd if=/dev/sdb1 bs=10k count=1 | file -
1+0 records in
1+0 records out
10240 bytes (10 kB) copied, 0.002784 seconds, 3.7 MB/s
/dev/stdin: Linux rev 1.0 ext3 filesystem data (needs journal recovery)
pelmen:/ # cmp <(dd if=/dev/sdb1 bs=10k count=1) <(dd if=/dev/md2 bs=10k count=1)
1+0 records in
1+0 records out
10240 bytes (10 kB) copied, 5.7e-05 seconds, 180 MB/s
1+0 records in
1+0 records out
10240 bytes (10 kB) copied, 6.3e-05 seconds, 163 MB/s
Hier wird als erstes der Status der Device /dev/md2 erfragt, um zu sehen, dass diese
aus /dev/sdb1 und /dev/sdc1 besteht. Mit dem file Kommando wird dann
ermittelt, dass die Anfänge sowohl von /dev/sdb1 als auch von /dev/md2 wie ein
ext3-Filesystem aussehen. Zum Schluß vergewissern wir uns mit dem cmp
Kommando, dass die ersten 10 KByte wirklich gleich sind.
Vorgehensweise
Wie gesagt, die Installation des Boot-Loaders Grub während der Installation auf dem RAID ging schief. Daher installierte ich erstmal mit einer normalen Partition als Boot-Partition. Meine 3 Platten sind gleich partitioniert. Die ersten Partitionen /dev/sda1, /dev/sdb1 und /dev/sdc1 sollen später als RAID1 die Boot-Partition beherbergen.
Zum Installieren des Suse 9.3 wählte ich /dev/sda1 als Boot-Partition. Sie wird
als ext3 formatiert und unter /boot eingebunden. Grub wird im
Master-Boot-Record von /dev/sda installiert.
Die Partitionen /dev/sdb1 und /dev/sdc1 werden während der Installation in der
gleichen Größe erstellt, aber nicht formatiert oder irgendwie eingebunden. Yast
bastelt daraus dann /dataN Mountpoints, die man hinterher getrost
löschen kann.
Nach der Installation basteln wir uns ein RAID1 aus /dev/sdb1, /dev/sdc1 und einem fehlenden Disk, den wir später durch /dev/sda1 ersetzen:
mdadm -C /dev/md2 -l raid1 -n 3 missing /dev/sdb1 /dev/sdc1
Es kann passieren, dass mdadm dabei etwas schimpft oder warnt, aber wir wissen ja, was wir tun. Dieses RAID mounten wir unter einem temporären Verzeichnis und übertragen wir erstmal den Inhalt von /boot dorthin:
mkfs.ext3 /dev/md2
mkdir /boot.new
mount /dev/md2 /boot.new
tar -C /boot -cf - .| tar -C /boot.new -xvf -
Grub-Installation
Grub benutzt zur Benennung der Partitionen nicht die Linux-typischen Bezeichnungen
/dev/sdX oder /dev/hdX, sondern Namen aus der BSD-Welt. Unter
/boot/grub/device.map wird jedoch eine Datei angelegt, aus der die
Zuordnung ersichtlich ist:
pelmen:/ # cat /boot.new/grub/device.map
(fd0) /dev/fd0
(hd0) /dev/sda
(hd2) /dev/sdc
(hd1) /dev/sdb
Ich will Grub zuerst auf den 2 Partitionen installieren, die zu /dev/md2 schon gehören. So verändere ich die bestehende Boot-Partition auf /dev/sda1 erstmal überhaupt nicht und habe immer eine Rückfall-Option, falls irgendwas schief geht. Aus obiger Tabelle ist ersichtlich, dass /dev/sdb hd1 und /dev/sdc hd2 und folglich /dev/sdb1 hd1,0 und /dev/sdc1 hd2,0 heißen.
pelmen:~ # grub
grub> root (hd1,0)
Filesystem type is ext2fs, partition type 0xfd
grub> setup (hd1)
Checking if "/boot/grub/stage1" exists... yes
Checking if "/boot/grub/stage2" exists... yes
Checking if "/boot/grub/e2fs_stage1_5" exists... yes
Running "embed /boot/grub/e2fs_stage1_5 (hd1)"... 16 sectors are embedded.
succeeded
Running "install /boot/grub/stage1 (hd1) (hd1)1+16 p (hd1,0)/boot/grub/stage2
/boot/grub/menu.lst"... succeeded
Done.
grub> root (hd2,0)
Filesystem type is ext2fs, partition type 0xfd
grub> setup (hd2)
Checking if "/boot/grub/stage1" exists... yes
Checking if "/boot/grub/stage2" exists... yes
Checking if "/boot/grub/e2fs_stage1_5" exists... yes
Running "embed /boot/grub/e2fs_stage1_5 (hd2)"... 16 sectors are embedded.
succeeded
Running "install /boot/grub/stage1 (hd2) (hd2)1+16 p (hd2,0)/boot/grub/stage2
/boot/grub/menu.lst"... succeeded
Done.
grub> quit
/boot/grub/menu.lst
Zum Schluß muss noch /boot.new/grub/menu.lst angepasst werden.
Ich stelle hier schon die Endfassung vor, wenn alle 3 Platten zu dem RAID gehören
werden.
color white/blue black/light-gray
default 0
fallback 1
fallback 2
timeout 8
#gfxmenu (hd0,0)/message
title SUSE LINUX 9.3 (/dev/sda) - raid
kernel (hd0,0)/vmlinuz root=/dev/md0 vga=0x317 selinux=0 splash=verbose console=tty0 showopts
initrd (hd0,0)/initrd
title SUSE LINUX 9.3 (/dev/sdb) - raid
kernel (hd1,0)/vmlinuz root=/dev/md0 vga=0x317 selinux=0 splash=verbose console=tty0 showopts
initrd (hd1,0)/initrd
title SUSE LINUX 9.3 (/dev/sdc) - raid
kernel (hd2,0)/vmlinuz root=/dev/md0 vga=0x317 selinux=0 splash=verbose console=tty0 showopts
initrd (hd2,0)/initrd
title Floppy
root (fd0)
chainloader +1
Wichtig hierbei sind die default 0 und die beiden fallback
Anweisungen. Sie bewirken, dass normalerweise der erste Eintrag zum Booten benutzt
und damit von /dev/sda gebootet wird. Sollte die Platte aber einen Fehler haben,
dann wird automatisch der nächste und der übernächste Eintrag probiert.
Die gfxmenu Zeile ist auskommentiert, da sie eine bestimmte Platte
anspricht. So haben wir zwar kein grafisches Boot-Menu, aber ein sicheres.
/etc/fstab nicht vergessen
Genau. In der Fstab ist ja als /boot immer noch /dev/sda1
gemountet. Das müssen wir noch ändern.
/dev/md0 / xfs defaults 1 1
/dev/md2 /boot ext3 acl,user_xattr 1 2
/dev/md1 /home xfs defaults 1 2
/dev/md3 /var/log xfs defaults 1 2
/dev/md4 swap swap pri=42 0 0
devpts /dev/pts devpts mode=0620,gid=5 0 0
proc /proc proc defaults 0 0
usbfs /proc/bus/usb usbfs noauto 0 0
sysfs /sys sysfs noauto 0 0
Zeit für den Reboot
Wir stellen fest, dass immer noch das grafische Boot-Menu der Suse-Installation
erscheint. Was ist falsch? Ahh ..., wir haben vergessen, die Boot-Platte im BIOS
zu ändern. Gut, nachdem das geändert ist, erscheint das Boot-Menu unserer geänderten
menu.lst im Text-Modus. Hier wählen wir einen Eintrag, der auf das RAID
zeigt, also in unserem Fall den zweiten oder dritten.
Wenn der Rechner betriebsbereit ist und wir die verschiedenen Boot-Varianten ein
bißchen getestet haben, wird es Zeit, das RAID um die fehlende Platte zu ergänzen.
Dazu gibt es natürlich wieder mdadm. Sofort nach dem Hinzufügen der neuen Partition
wird sie in das RAID integriert, was in /proc/mdstat verfolgt werden
kann.
pelmen:~ # mdadm /dev/md2 -a /dev/sda1
mdadm: hot added /dev/sda1
pelmen:~ # cat /proc/mdstat
Personalities : [raid1] [raid5]
md2 : active raid1 sda1[3] sdc1[2] sdb1[1]
3148608 blocks [3/2] [_UU]
[>....................] recovery = 4.2% (134592/3148608) finish=0.7min speed=67296K/sec
md3 : active raid5 sdc3[2] sdb3[1] sda3[0]
5253120 blocks level 5, 64k chunk, algorithm 2 [3/3] [UUU]
md4 : active raid1 sdc5[2] sdb5[1] sda5[0]
4714944 blocks [3/3] [UUU]
md1 : active raid5 sdb7[1] sdc7[0] sda7[2]
260108160 blocks level 5, 64k chunk, algorithm 2 [3/3] [UUU]
md0 : active raid1 sdc6[2] sdb6[1] sda6[0]
15735552 blocks [3/3] [UUU]
unused devices: <none>
Ach ja, um ganz sicher zu gehen installieren wir Grub nochmal auf /dev/sda. Das hatte yast während der Installation zwar schonmal gemacht, trotzdem, sicher ist sicher. Die Kommandos sind die gleichen wie oben nur ist hd1 durch hd0 zu ersetzen.
Alarm
Zum Schluß sei noch ein kleines Script vorgestellt, das auf einfache Weise einen
Alarm auslöst, falls mit dem RAID irgendwas nicht stimmt. Die Idee ist einfach,
/proc/mdstat hat einen konstanten Inhalt. Also merken wir uns irgendwo
dessen MD5-Summe und lassen den Rechner piepsen, wenn sie nicht mehr stimmt.
#!/bin/bash
beep () {
echo -e '\a' >/dev/console
}
alarm () {
beep
usleep 200000
beep
usleep 300000
beep
usleep 200000
beep
usleep 200000
beep
usleep 300000
beep
usleep 200000
beep
usleep 200000
beep
usleep 300000
beep
usleep 200000
beep
}
md5sum -c /etc/proc-mdstat.md5 >/dev/null 2>&1 || alarm
Die MD5-Summe wird dann einmalig in /etc/proc-mdstat.md5 abgelegt:
md5sum /proc/mdstat >/etc/proc-mdstat.md5
und das Script per /etc/crontab minütlich aktiviert:
pelmen:~ # cat /etc/crontab
...
* * * * * root /usr/local/sbin/mdalarm
...
So, jetzt können wir einem Plattenausfall entspannt entgegen sehen. Hauptsache im Ernstfall ist schnell eine Ersatzplatte zur Hand. Also evtl. eine in die Schublade legen!
Letzte Aktualisierung: 03.08.2008


