USBメモリでRAID 5を構築・RAIDから起動(ブート)できるようにする
MicroSDカードをシステムディスクとして使用していると、いつ壊れるか分からず不安なので
Raspberry Piを24時間運転のサーバとして使用したいと考えた場合、ネックになるのは、やはり MicroSDカードの寿命でしょう。自分は既にMicroSDカードの故障を2回経験しています。スワップやログ出力を止めたり、RAMディスク(tmpfs)を使用する等の延命策を講じていましたが、24時間運転させると1年から1年半ほどで壊れました。
そこで、せっかくRaspberry Pi 3 (Raspbian Jessie) で USBメモリを使った RAID 5を構築したのですから、Raspbian のシステムをRAIDアレイに移し、MicroSDカードからブートするのではなく、RAIDからブートできるようにしてみたい(システムディスクのRAID化)と思います。
とは言え、Raspberry Piのブートの仕組み上、"/boot" パーティションだけはMicroSDカード上のFAT32上になければなりません。それ以外の"/" (ルート)パーティションを RAIDに移します。
"/boot" パーティションは、システムの起動時に読み出されるだけですから、MicroSDカードの寿命で壊れる可能性はかなり低くなると考えられます。容量も 80MB程度で足りますから、容量の少ない安価な MicroSDに変えてしまうこともできます。また、バックアップも短時間で済みます。
逆にRAIDに移した"/" (ルート)パーティションについては、これまでの「MicroSDカード全体を Mac, Windows等の他PCを用いてバックアップする」という方法が使えなくなりますので、別のバックアップ方法を考える必要があります。バックアップ方法については、後日検討することにします。
Raspbian をRAIDアレイからブートしようとした場合、重大な問題が1つあります。それは RAIDアレイの構築にmdadmというソフトウェアRAIDを用いているという事です。ソフトウェアRAIDですから、システム(カーネル)が起動した後でなければ使用(RAIDアレイの構成、マウント)することができませんが、そのシステムがRAID内にあるという状態になるわけです。(金庫を開ける鍵が金庫の中に入っているようなもんです。)
幸いなことに、Linuxにはこのような問題を解決する(様々なデバイスからブートできるようにする)ための仕組みがあります。それが「initramfs」です。これはLinuxがブートする際に使用する「ミニルート」ファイルシステムで、RAM上に展開されて使用されます。この中にソフトウェアRAIDのデバイスドライバ(カーネルモジュール)を組み込んでおけば、ブート時からRAIDアレイが使用できるようになります。(詳しくは「initramfs」等で調べてください。)通常の Raspbian では initramfs は使用されていません。理由はおそらく、ブート時から MicroSDカードの"/" (ルート)パーティション("/dev/mmcblk0p2" デバイス)を直接マウント可能なようになっているからではないかと推測されます。
よって、大まかな手順としては以下のようになります。
- initramfsを作成する
- initramfsを使ってブートできるようにする
- "/"(ルート)パーティションの内容をRAIDにコピーする
- "/"(ルート)にRAIDアレイデバイス("/dev/md0")をマウントする
1. バックアップを取る
作業ミスがあるとRaspberry Piが起動しなくなる可能性があります。作業前に必ず MicroSDカードのバックアップを作成しておきましょう。
2. システムを最新化する。
Raspbian を最新化しておきます。ファームウェアのアップデートも忘れずに実施します。
# apt-get update
# apt-get upgrade
# apt-get dist-upgrade
# rpi-update
# reboot
|
3. initramfsを作成する
initramfsに組み込みたいカーネルモジュールを"/etc/initramfs-tools/modules" に記述します。
# cd /etc/initramfs-tools
# vi modules
|
# List of modules that you want to include in your initramfs.
# They will be loaded at boot time in the order below.
#
# Syntax: module_name [args ...]
#
# You must run update-initramfs(8) to effect this change.
#
# Examples:
#
# raid1
# sd_mod
|
となっているところを以下の赤字のように編集します。RAIDアレイの構成がRAID 1であれば、raid1モジュールで良いですが、ワタシの場合はRAID 5なので、raid456モジュールを組み込ませます。
# List of modules that you want to include in your initramfs.
# They will be loaded at boot time in the order below.
#
# Syntax: module_name [args ...]
#
# You must run update-initramfs(8) to effect this change.
#
# Examples:
#
raid456
md_mod
ext4
|
initramfsを作成し、内容を確認します。initramfsは"/boot/initrd.img-X.X.X" と言った名前で作成されます。
# uname -r
4.4.21-v7+
# update-initramfs -c -k `uname -r`
update-initramfs: Generating /boot/initrd.img-4.4.21-v7+
# ls -l /boot/initrd.img-4.4.21-v7+
-rwxr-xr-x 1 root root 6324242 9月 18 15:20 /boot/initrd.img-4.4.21-v7+
# lsinitramfs /boot/initrd.img-4.4.21-v7+ | grep raid
lib/udev/rules.d/64-md-raid-assembly.rules
lib/udev/rules.d/63-md-raid-arrays.rules
lib/modules/4.4.21-v7+/kernel/drivers/md/raid10.ko
lib/modules/4.4.21-v7+/kernel/drivers/md/raid1.ko
lib/modules/4.4.21-v7+/kernel/drivers/md/raid0.ko
lib/modules/4.4.21-v7+/kernel/drivers/md/raid456.ko ←※入ってますね
lib/modules/4.4.21-v7+/kernel/crypto/async_tx/async_raid6_recov.ko
lib/modules/4.4.21-v7+/kernel/lib/raid6
lib/modules/4.4.21-v7+/kernel/lib/raid6/raid6_pq.ko
|
4. initramfsでブートするように設定する
initramfsを使ってブートするように設定を変更します。設定の変更には"/boot/config.txt" を編集します。
# cd /boot
# cp -p config.txt config.txt.org ※バックアップを作成しておきます
# vi config.txt
|
以下の2行(赤字の部分)を追加します。
kernel=kernel7.img
initramfs initrd.img-4.4.21-v7+ followkernel
|
"/boot" 配下には"kernel.img" と"kernel7.img" の2つのカーネルイメージファイルがありますので、Raspberry Piの CPUに合わせてkernel= に指定します。Raspberry Pi A/A+/B/B+/Zero では CPUがARMv6ですので"kernel.img" を、Raspberry Pi 2/3 では"kernel7.img" を指定します。
initramfs の第一パラメタには、先ほど作成した"initrd.img-X.X.X" (ここでは"initrd.img-4.4.21-v7+" )を指定します。
編集できたら保存し、再起動できるか?確認します。
無事に再起動できたら、先ずは第一段階クリアです。再起動できなかった場合は、カーネルイメージファイル名や initramfsファイル名を間違えていないか確認してください。
# uname -a
Linux RaspberryPi3 4.4.21-v7+ #911 SMP Thu Sep 15 14:22:38 BST 2016 armv7l GNU/Linux
|
5. "/"配下のファイルをRAID配下にコピーする
"/" (ルート)配下にあるファイルを全てRAID配下にコピーします。ワタシの場合、RAIDアレイは"/media" にマウントされていますから、以下のようにコピーします。
cpコマンドの-xオプションを指定することで、"/" のファイルシステム内のファイルだけをコピーするようにしています。(そうしないと"/media" 配下のファイルもコピーしようとしてしまうだろう)コピーにはちょっと時間がかかりますので、気長にお待ちください・・・
6. "/boot/cmdline.txt"を編集
カーネルへ渡すパラメタファイル"/boot/cmdline.txt" を編集します。
# cd /boot
# cp -p cmdline.txt cmdline.txt.org ※バックアップを作成しておきます
# vi cmdline.txt
| |
dwc_otg.lpm_enable=0 console=serial0,115200
console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4
elevator=deadline fsck.repair=yes rootwait
|
注)行が長いので折り返していますが、実際には1行です。
これを以下のように修正(赤字の部分)します。
dwc_otg.lpm_enable=0 console=serial0,115200
console=tty1 root=/dev/md0 rootfstype=ext4
elevator=deadline fsck.repair=yes rootdelay=10 rootwait
|
root= パラメタには"/" 配下のファイルをコピーした先のRAIDデバイス名を指定します。ワタシの場合は"/dev/md0" になります。(*1)
また、USBメモリが認識されるまで少し時間がかかるので、rootdelay=10 パラメタを指定することで10秒間遅延させるようにしています。(*2)
7. fstabを編集
"/" にRAIDデバイスをマウントさせるように"/etc/fstab" ファイルを編集します。ただし、元の"/etc/fstab" ではなく、RAIDにコピーした方の"/etc/fstab" (ここでは"/media/etc/fstab" )を編集します。
# cd /media/etc
# cp -p fstab fstab.org ※バックアップを作成しておきます
# vi fstab
|
現在、既にRAIDを"/media" にマウントして使用していますので、fstabファイルは以下のようになっています。
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
#
# tmp files put on RAM disk
tmpfs /tmp tmpfs defaults,size=128m,noatime,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,size=16m,noatime,mode=1777 0 0
#
# Log files write on RAM disk
tmpfs /var/log tmpfs defaults,size=32m,noatime,mode=0755 0 0
UUID=f8b8beba-56e0-4f91-a717-8f2bc7459453 /media ext4 defaults,noatime,nofail 0 2
|
これを以下のように変更(赤字の部分)します。
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults 0 2
#/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
UUID=f8b8beba-56e0-4f91-a717-8f2bc7459453 / ext4 defaults,noatime,errors=remount-ro 0 1
# a swapfile is not a swap partition, no line here
# use dphys-swapfile swap[on|off] for that
#
# tmp files put on RAM disk
tmpfs /tmp tmpfs defaults,size=128m,noatime,mode=1777 0 0
tmpfs /var/tmp tmpfs defaults,size=16m,noatime,mode=1777 0 0
#
# Log files write on RAM disk
tmpfs /var/log tmpfs defaults,size=32m,noatime,mode=0755 0 0
#UUID=f8b8beba-56e0-4f91-a717-8f2bc7459453 /media ext4 defaults,noatime,nofail 0 2
|
8. 再起動する
無事に再起動できれば(たぶん)成功!確認してみましょう。
# df -h
ファイルシス サイズ 使用 残り 使用% マウント位置
udev 10M 0 10M 0% /dev
tmpfs 195M 4.8M 190M 3% /run
/dev/md0 174G 66G 99G 40% / ←※"/"のデバイスが"/dev/md0"になった
tmpfs 487M 0 487M 0% /dev/shm
tmpfs 5.0M 4.0K 5.0M 1% /run/lock
tmpfs 487M 0 487M 0% /sys/fs/cgroup
tmpfs 32M 148K 32M 1% /var/log
tmpfs 16M 0 16M 0% /var/tmp
tmpfs 128M 50M 79M 39% /tmp
/dev/mmcblk0p1 60M 34M 27M 56% /boot
overlaid 128M 50M 79M 39% /tmp/asd-root/var/lib/monitorix
tmpfs 98M 0 98M 0% /run/user/109
tmpfs 98M 0 98M 0% /run/user/0
|
再起動できない(ブートしない)場合は、一旦Raspberry Piの電源をオフにし、MicroSDカードを抜いて PC等にマウントします。"/boot" パーティションはFAT32ですから、普通に Macや Windowsからアクセスできますので、"/boot/cmdline.txt" ファイルをバックアップファイルに戻せば復旧するはずです。(それでも復旧しなかったら、一番最初に取った MicroSDカード全体のバックアップに書き戻すだね。^^;)
無事に起動できれば作業は終了です。後は"/boot" パーティションを、もっと容量が少なくて安価な MicroSDカードに入れ替えてしまっても良いでしょう。今では 4GB, 8GB程度の MicroSDカードなら数百円程度で売っています。まぁ32GBでも千円程度ですけどね。
(*1):"/dev/md0" ではなく、fstab のように UUIDで指定することもできました。
dwc_otg.lpm_enable=0 console=serial0,115200
console=tty1 root=UUID=f8b8beba-56e0-4f91-a717-8f2bc7459453 rootfstype=ext4
elevator=deadline fsck.repair=yes rootdelay=10 rootwait
|
(あまり無いとは思いますが)Raspberry Piに複数台のRAIDアレイを接続している場合は、UUIDで指定する必要があります。
(*2):以前は
"/etc/init.d/mdadm-raid" スクリプトにsleepを入れることで、USBメモリが認識されるまで遅延させていましたが、これはもう不要になります。
|