最小限のダウンタイムでRAIDに移行する
LinuxのソフトウェアRAIDで助かったのに気をよくしていたら、他のサーバが心配になってきました。 個人管理のサーバって、どういうわけか数台有るのです。 そういや、「そのうちRAIDにしよう」なんて言ったきり数年、放置してました。 残りのサーバも、なるべく急いで順次RAIDに移行したいと思います。 この項目では、Linuxの普通のディスクからRAID1に移行する手順を、解説するのでなくて記録していきます。 現在実施途中なので、この方針でうまくいくかどうかはまだ結論が出ていません。 今回の課題は、ダウンタイムを最小限にすることです。 なにしろ、いろいろ重要なウェブサイトが動いているのです。
伝言
うちのスタッフに伝言です。 当社自身のサーバはスタッフにまかせます。 身に覚えのあるスタッフの人は、早めに取りかかってください。 こういうことを経験するチャンスを奪っちゃいけないなあと、最近は反省しています。
サーバの構築とかメンテって、難しいかなあ? 難しくないと思うんだけどな。 情報収集と、正しい情報の見極めさえちゃんとやれば難しくはない。 僕だって、やり方をいちいち覚えているわけではないよ。調べながらやっている。 あとは、最悪の場合の復旧手段の確保(バックアップと切り戻し手順の確認)と、リスクの分析、評価、リスクヘッジをして、最後は思い切り。
細かいことだけど、どっかの知らない人が書いたウェブの内容なんて信用してはいけない。結構、間違い情報が多い。 参考にするのはいいことだけど、ちゃんと自分でmanとかinfoで調べて検証すること。
前提の状況
- OSは、Linux Debian 4.0 (Etch)。
- 1Uサーバ。
- 80GBのSATAドライブ2台を内蔵。
- 1台目、sdaは起動ディスク、ルートファイルシステムとスワップ領域。ルートファイルシステムに全部入っている。
- 2台目、sdbはカラっぽ。他のマシンのバックアップ領域として使っていたけど、不要になった。
方針
- カラっぽだったドライブで、ドライブ1台だけでRAID1を作る。
- ルートファイルシステムから中身をコピーする。
- 作ったRAIDをルートファイルシステムとして動くように、起動の設定を変更する。
- 再起動する。
- 元々ルートファイルシステムだったドライブを消去し、RAIDに参加させる。
- リビルドが終わるのを待つ(放置)。
- GRUBをちゃんと設定する。
準備
「mdadm」をインストールします。
# apt-get install mdadm
いろいろ聞かれます。
- 「rootファイルシステムに必要な MDアレイ」には「all」と答えます。
- 「mdadmは、毎月MDアレイの冗長性チェックを行いますか?」は「はい」でいいでしょう。
- 「MD監視デーモンを起動しますか?」は「はい」がいいでしょう。
- 「メール通知の宛先」は「root」のままにしておきます。
いくつかウォーニングが出ますが、とりあえずは気にしないことにします。 あと、メールの設定をいじって、root宛のメールがちゃんと人間に届くようにしておきます。
ちなみに、上記の設定を後から変更したいときは、「dpkg-configure mdadm」コマンドを実行してください。
これだけの操作で、mdadmがインストールされ、最小限の設定がされます。 さらに、自動的にinitrd.imgが作り直され、OSの起動時にRAIDを起動するように設定されます。 Debianすごいな(Debianに限らないでしょうけれど)。
あと、くだらないことですが、/etc/fstabでsdb1をマウントするようにしていたのをやめ、アンマウントしました。
fdisk
現在ルートファイルシステムとして使っているsda1は、最終的にRAIDに参加させる予定です。 そのため、sda1と同じサイズのパーティションをsdbに作成することにしました。 パーティションのタイプ(システムID)は「fd(Linux raid autodetect)」にします。 余った部分は、スワップ領域として使うことにします。 この後の「GRUB stage1/stage2をインストール」とも関係しますが、sdb1に起動フラグをつけておきます。
fdiskの結果はこんな感じです。もちろん、サイズなどは個々の環境によって異なります。
Device Boot Start End Blocks Id System /dev/sdb1 * 1 9388 75409078+ fd Linux raid autodetect /dev/sdb2 9389 9964 4626720 82 Linux swap / Solaris
ドライブ1台だけでRAID1を作る
RAID1にはドライブが2台必要なのに、何を言ってるんだ…と言われそうです。 RAID1に必要なドライブ2台のうち、1台が壊れて取り外しているのと同じ状態にします。
# mdadm --create /dev/md0 --auto=md --level=1 --raid-devices=2 missing /dev/sdb1
実行すると「このディスク、ext2みたいなんだけど、どうする?」みたいなことを聞かれることがあります(実際のメッセージは「mdadm: /dev/sdb1 appears to contain an ext2fs file system」)。 これは、以前にext2/3でフォーマットして使っていたからです。 指定したデバイスに間違いが無くて、確かに消してしまっていいのであれば、「y」と答えます。
- 「--auto=md」を指定しないと、「/dev/md0が無いぞ」というようなエラーで動きません。
- 「--level=1」は、RAID1を選択する指示です。
- 「--raid-devices=2 missing /dev/sdb1」でドライブを指定しています。RAIDは2台で構成する、1台目は「まだ無い」、2台目は/dev/sdb1という指示です。「missing」と「/dev/sdb1」の順序は逆順でも問題なく動きます。ただし、以後「mdadm --detail」に含まれるドライブの情報は、ここで指定した順に表示されます。sdbが先に表示されて気持ち悪いので、必ず「missing」、「/dev/sdb1」の順にしておきます。
RAIDはこれでできあがりですが、設定ファイル「mdadm.conf」に反映しておきます。 このファイルに関係なくRAIDを動かすことができますが、何かと不便なのです。
# mdadm --detail /dev/md0
「mdadm --detail」を実行するとRAIDの状態などが表示されます。 この中に「UUID」があるので、値をコピーしておきます。 UUIDは「e3f637a8:0ba8f91b:4c7f4245:5fbcddbb」というような形式です。 次に、「/etc/mdadm/mdadm.conf」を編集して、以下のような内容にします。
DEVICE partitions ARRAY /dev/md0 UUID=e3f637a8:0ba8f91b:4c7f4245:5fbcddbb MAILADDR root
もちろん、「UUID=」の右の部分はさっきコピーしたUUIDの値にします。
あまり本質的ではないことですが、「/var/lib/mdadm/CONF-UNCHECKED」というファイルを削除しておきます。 これを削除しておかないと、以後、カーネルを更新する度に警告(ウォーニング)が出ます。この話はDebianに限定です。
# rm /var/lib/mdadm/CONF-UNCHECKED
最後に、通常は必要ありませんが、RAIDの止め方、動かし方をメモしておきます。
- RAIDを止めたければ、「mdadm --stop /dev/md0」です。initスクリプトを使うなら「/etc/init.d/mdadm-raid stop」です。
- 止まってるRAIDを動かすには、「mdadm --assemble /dev/md0」です。 initスクリプトを使うなら「/etc/init.d/mdadm-raid start」です。 ただし、作ったRAIDをmdadm.confに反映してない場合は、いずれもダメです。 代わりに「mdadm --assemble /dev/md0 /dev/sdb1」を使ってください。
ルートファイルシステムから中身をコピーする
ここは特記するようなことはありません。ファイルシステムを作って、rsyncでコピーするだけです。 「--one-file-system」オプションは、「-x」でいいです。
# mkfs -t ext3 /dev/md0 # mount /dev/md0 /mnt # rsync -aH --one-file-system / /mnt
起動の設定を変更する(Debianの場合)
GRUBの設定を変更して、ルートファイルシステムのデバイス名を変更します。
# vi /boot/grub/menu.lst
このファイルの中程、「# kopt=root=…」という行を探します。
# kopt=root=/dev/sda1 ro
ここで、「root=/dev/sda1」となっているのを、「root=/dev/md0」に変更します。 さらに、「update-grub」コマンドを実行します。
# update-grub
もういちど「menu.lst」ファイルを開いてみて、以下のようにルートファイルシステムのデバイス名が反映されていることを確認します(もちろん、環境によって細部は異なります)。
title Debian GNU/Linux, kernel 2.6.18-6-686 root (hd0,0) kernel /boot/vmlinuz-2.6.18-6-686 root=/dev/md0 ro initrd /boot/initrd.img-2.6.18-6-686 savedefault
起動の設定を変更する(Debianじゃない場合)
GRUBの設定を変更して、ルートファイルシステムのデバイス名を変更します。
# vi /boot/grub/menu.lst
このファイルの最後の方、以下のようになっている部分を探します(もちろん、環境によって細部は異なります)。
title Linux kernel 2.6.18 root (hd0,0) kernel /boot/vmlinuz-2.6.18 root=/dev/sda1 ro initrd /boot/initrd.img-2.6.18 savedefault title Linux kernel 2.6.18 (recovery mode) root (hd0,0) kernel /boot/vmlinuz-2.6.18 root=/dev/sda1 ro single initrd /boot/initrd.img-2.6.18 savedefault
ここで、「root=/dev/sda1」となっているのを、「root=/dev/md0」に変更します。
ルートファイルシステムとして使うパーティションを変更
以後、ルートファイルシステムとして、/dev/md0を使います。
「/etc/fstab」を開きます。
# /etc/fstab: static file system information. # # <file system> <mount point> <type> <options> <dump> <pass> proc /proc proc defaults 0 0 /dev/sda1 / ext3 defaults,errors=remount-ro 0 1 /dev/sda5 none swap sw 0 0 /dev/hdc /media/cdrom0 iso9660 ro,user,noauto 0 0 /dev/fd0 /media/floppy0 auto rw,user,noauto 0 0
「/dev/sda1」となっているのを、「/dev/md0」に変更します。
各種サービスを停止してから、もいちどrsyncして再起動
先ほどrsyncを行ってから、自分で変えたファイルの他、勝手に変わったファイルがいくつもあるはずです。 サービス(デーモンのたぐい)が動いている最中は、ログファイルなどがどんどん変わってしまします。サービスを止めてからrsyncを行います。 普通はシャットダウンでシングルユーザモードに落とすんですが、それではSSHで操作ができなくなってしまいます。 今回は、sshd以外の不要なサービスを手動で止めることにします。
ここから再起動するまでは急いで作業します。 「ps -ef」の結果と、「/etc/init.d/*」とを見比べながら、手動でサービスを止めます。 SSHで作業しているなら、「sshd」だけは止めないようにします(ログイン中のセッションは切れないという説もあり、要調査)。
rsyncします。
# rsync -aHv --one-file-system --del / /mnt
今回のrsyncには、「-v」と「--del」オプションを指定しました。 「-v」により、ファイルの更新および削除の進行状況がわかります。 先ほどのrsyncは全ファイルのコピーだったので、「-v」をつけませんでした。 つけると、画面表示がいっぱいで大変だったはずです。 今回は更新されるファイル数が少ないので、「-v」をつけても大丈夫です。 「--del」により、ルートファイルシステム上から削除されたことを、/mntにも反映します。
再起動します。
# sync # reboot
なんとなく、rebootの直前にsyncをたたきたくなるのは、年寄りの証拠です。 syncをたたいて、1秒待って、もう一度syncしろとか、いろいろと流儀がありました。
ふう。
あまり祈らなくても、正常に起動するはずです。 GRUBの設定をいじってないのに、なぜ? GRUBは、/dev/sdaのMBRを読み込み、/dev/sda1からstage2とmenu.lstを読み込んで動きます。 Linuxが立ち上がった後は、/dev/sdb1から成るRAID1ドライブ/dev/md0をルートファイルシステムとして動きます。 起動には/dev/sdaしか関与していません。これまでのところ、/dev/sdaの設定はいじってないので、起動には問題が無いはずです。
起動したら「df」コマンドで、ルートファイルシステムが/dev/md0であることを確認しておきます。 いや、ルートファイルシステムに限っては、dfコマンドの結果って必ずしも信用できないのです…。どうやって確認しようかなあ。 「umount /dev/md0」コマンドを実行してみて、「umount: /: device is busy」って出ればだいじょうぶかなあ。
sdaを使う
もう、/dev/sda1にあったルートファイルシステムは使っていません。 これを一度壊して、RAID1に参加させます。
# fdisk /dev/sda
「t」コマンドで、/dev/sda1のパーティションのタイプ(システムID)を「fd(Linux raid autodetect)」に変えます。 最後に「w」でパーティションテーブルを書き込みます。 このとき、「再起動しないと反映されないよ」とか文句を言われます。 スワップ領域のために/dev/sda5を開いたままだからです。 パーティションの位置やサイズは変えてないから、大丈夫でしょう。このまま進みます。
RAIDに/dev/sda1を組み込みます。
# mdadm /dev/md0 --add /dev/sda1 mdadm: added /dev/sda1 #
一瞬で非常に素っ気ないメッセージが返ってきますが、これで大丈夫です。 「mdadm --detail /dev/md0」または「cat /proc/mdstat」で状態を見ると、同期(リビルド)が始まっているはずです。 この先、GRUBの設定を行う段階では、同期が完了している必要があります。 少々時間があるので、この間に、次の「スワップを追加する」作業と「GRUBのCDを作る」作業をやっておきましょう。
同期がなかなか進まないと思う場合は、RAID1を復旧した話のページの、「speed_limit_min」の説明を参考にしてください。
スワップを追加する
最初のfdiskで、/dev/sdb2のパーティションのタイプ(システムID)を「Linux swap」として設定しましたが、まだ使っていません。 使うように設定します。
# mkswap /dev/sdb2
「/etc/fstab」を編集して、/dev/sdb2をスワップ領域として使うように設定します。 うちの環境では以下のようにしました。太字の部分が、追加した行です。
# /etc/fstab: static file system information. # # <file system> <mount point> <type> <options> <dump> <pass> proc /proc proc defaults 0 0 /dev/md0 / ext3 defaults,errors=remount-ro 0 1 /dev/sda5 none swap sw 0 0 /dev/sdb2 none swap sw 0 0 /dev/hdc /media/cdrom0 iso9660 ro,user,noauto 0 0 /dev/fd0 /media/floppy0 auto rw,user,noauto 0 0
このあと、以下のコマンドを実行します。
# swapon -a
ちゃんとスワップ領域として使われるようになったかは、「swapon -s」コマンドで確認します。
GRUBのCDを作る
このあと、GRUBの設定をいじります。最悪の場合、起動しなくなっちゃいます。 最悪の場合の復旧のために、GRUB入りのCDを作っておくといいです。 CDさえあれば、なんとか起動できます。
また、SystemRescueCdなんかをダウンロードしてCDに焼いておくのもいいでしょう。 ただし、SystemRescueCdでは、ブートローダだけが壊れたシステムを手っ取り早く起動することはできません。 SystemRescueCdのCDブートLinuxで起動して、GRUBを正しく設定しなおすことが求められます。
ブートローダのインストール
ブートローダとして、GRUBをインストールします。 その前に、RAIDの同期(リビルド)が終わっている必要があります。 上記のように、「mdadm --detail /dev/md0」コマンドで、同期が終わったことを確認してください。
ハードディスク1台目(sda)、2台目(sdb)それぞれのMBRに、GRUBで言うところのstage1をインストールします。 1台目が機能しなくて、2台目だけでブートされた場合にうまくいくよう、sdbに対しても(hd0)としてインストールしています。 しかし、これだけの対処では起動できないようなシナリオも、依然として残ります。 どこかであきらめないといけないと思います。
# grub
GNU GRUB version 0.97 (640K lower / 3072K upper memory)
[ Minimal BASH-like line editing is supported. For
the first word, TAB lists possible command
completions. Anywhere else TAB lists the possible
completions of a device/filename. ]
grub> device (hd0) /dev/sda
grub> setup --stage2=/boot/grub/stage2 (hd0) (hd0,0)
grub> device (hd0) /dev/sdb
grub> setup --stage2=/boot/grub/stage2 (hd0) (hd0,0)
grub> quit
#
「--stage2=/boot/grub/stage2」は、stage2が入っているファイルシステム、つまりルートファイルシステムをアンマウントすることができないので必要です。 ネット上で、RAIDの場合のGRUBの設定を調べると、この「--stage2=」オプションを付けていない例ばかり見受けられます。 でも、それでは、アンマウントしてないファイルシステムにstage2が入っている場合は、ちょっとまずいことが起こる可能性が高いです。 なぜならば、GRUBのsetupコマンドは、stage2ファイルの中にバイナリでデータを書き込むのです。 「--stage2=」オプションが無ければ、自らファイルシステムのデータ構造を解析してファイルを見つけて書き込みます。 このオプションが有れば、OSに依頼してファイルを見つけて書き込みます。
再起動
あとはうまくいくことを祈りながら再起動するだけです。 うまく起動できなかった場合は、焦らず騒がず、先ほど作成したGRUB入りCDで起動してください。 操作は以下のような感じです。
grub> root (hd0,0) grub> kernel /boot/vmlinuz… grub> initrd /boot/inird… grub> boot
GRUBシェルの操作については他の資料に譲りますが、そんなに難しくはありません。 kernelやinitrdコマンドで、それぞれカーネルやinitrdをフルパスで指定しなければいけないのですが、ここではタブ補完が効きます。
ドライブを外してみる
気が向いたら、ドライブの一方を取り外した状態で起動してみてください。
はまった話
GRUBがコケるに書きましたが、GRUBのインストール後の再起動でコケるという問題ではまって10日間浪費しました。 ご興味があったら、読んでみてください。
(2008/1/21 - sgk)
