wiki:LinuxRAID1Transition

Version 28 (modified by sgk, 12 years ago) (diff)

--

最小限のダウンタイムでRAIDに移行する

この項目の内容は現在実施途中なので、うまくいくかどうか結論は出ていません。

LinuxのソフトウェアRAIDで助かったのに気をよくしていたら、他のサーバが心配になってきました。 個人管理のサーバって、どういうわけか数台有るのです。 そういや、「そのうちRAIDにしよう」なんて言ったきり数年、放置してました。 残りのサーバも、なるべく急いで順次RAIDに移行したいと思います。 この項目では、Linuxの普通のディスクからRAID1に移行する手順を、解説するのでなくて記録していきます。 現在実施途中なので、この方針でうまくいくかどうかはまだ結論が出ていません。 今回の課題は、ダウンタイムを最小限にすることです。 なにしろ、いろいろ重要なウェブサイトが動いているのです。

伝言

うちのスタッフに伝言です。 当社自身のサーバはスタッフにまかせます。 身に覚えのあるスタッフの人は、早めに取りかかってください。 こういうことを経験するチャンスを奪っちゃいけないなあと、最近は反省しています。

サーバの構築とかメンテって、難しいかなあ?  難しくないと思うんだけどな。 情報収集と、正しい情報の見極めさえちゃんとやれば難しくはない。 僕だって、やり方をいちいち覚えているわけではないよ。調べながらやっている。 あとは、最悪の場合の復旧手段の確保(バックアップと切り戻し手順の確認)と、リスクの分析、評価、リスクヘッジをして、最後は思い切り。

細かいことだけど、どっかの知らない人が書いたウェブの内容なんて信用してはいけない。結構、間違い情報が多い。 参考にするのはいいことだけど、ちゃんと自分でmanとかinfoで調べて検証すること。

前提の状況

  • OSは、Linux Debian 4.0 (Etch)。
  • 1Uサーバ。
  • 80GBのSATAドライブ2台を内蔵。
    1. 1台目、sdaは起動ディスク、ルートファイルシステムとスワップ領域。ルートファイルシステムに全部入っている。
    2. 2台目、sdbはカラっぽ。他のマシンのバックアップ領域として使っていたけど、不要になった。

方針

  1. カラっぽだったドライブで、ドライブ1台だけでRAID1を作る。
  2. ルートファイルシステムから中身をコピーする。
  3. 作ったRAIDをルートファイルシステムとして動くように、起動の設定を変更する。
  4. 再起動する。                                 ←いまここ
  5. 元々ルートファイルシステムだったドライブを消去し、RAIDに参加させる。
  6. リビルドが終わるのを待つ(放置)。

準備

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の値にします。

最後に、通常は必要ありませんが、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

起動の設定を変更する

GRUBの設定を変更して、ルートファイルシステムのデバイス名を変更します。

# vi /boot/grub/menu.lst

このファイルの最後の方、以下のようになっている部分を探します(もちろん、環境によって細部は異なります)。

title           Debian GNU/Linux, kernel 2.6.18-4-686
root            (hd0,0)
kernel          /boot/vmlinuz-2.6.18-4-686 root=/dev/sda1 ro
initrd          /boot/initrd.img-2.6.18-4-686
savedefault

title           Debian GNU/Linux, kernel 2.6.18-4-686 (recovery mode)
root            (hd0,0)
kernel          /boot/vmlinuz-2.6.18-4-686 root=/dev/sda1 ro single
initrd          /boot/initrd.img-2.6.18-4-686
savedefault

ここで、「root=/dev/sda1」となっているのを、「root=/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/sdb1       /backup         ext3    defaults,errors=remount-ro 0       1

/etc/fstabを開き、「/dev/sda1」となっているのを、「/dev/md0」に変更します。

各種サービスを停止してから、もいちどrsyncして再起動

先ほどrsyncを行ってから、自分で変えたファイルの他、勝手に変わったファイルがいくつもあるはずです。 サービス(デーモンのたぐい)が動いている最中は、ログファイルなどがどんどん変わってしまします。サービスを止めてからrsyncを行います。 普通はシャットダウンでシングルユーザモードに落とすんですが、それではsshで操作ができなくなってしまいます。 今回は、ssh以外の不要なサービスを手動で止めることにします。

ここから再起動するまでは急いで作業します。 「ps -ef」の結果と、「/etc/init.d/*」とを見比べながら、手動でサービスを止めます。 sshで作業しているなら、「ssh」だけは止めないようにします(ログイン中のセッションは切れないという説もあり、要調査)。

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/sdaからstage2とmenu.lstを読み込んで動きます。 Linuxが立ち上がった後は、/dev/sdb1から成るRAID1ドライブ/dev/md0をルートファイルシステムとして動くので、/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」でパーティションテーブルを書き込みます。 このとき、「再起動しないと反映されないよ」とか文句を言われます。 swap領域として/dev/sda5を使っているからです。 パーティションの位置やサイズは変えてないから、大丈夫でしょう。このまま進みます。

RAIDに/dev/sda1を組み込みます。

# mdadm /dev/md0 --add /dev/sda1
mdadm: added /dev/sda1
# 

一瞬で非常に素っ気ないメッセージが返ってきますが、これで大丈夫です。 「mdadm --detail /dev/md0」または「cat /proc/mdstat」で状態を見ると、同期が始まっているはずです。

GRUBのCDを作る

このあと、GRUBの設定をいじります。最悪の場合、起動しなくなっちゃいます。 最悪の場合の復旧のために、GRUB入りのCDを作っておくといいです。 CDさえあれば、なんとか起動できます。

また、 SystemRescueCdなんかをダウンロードしてCDに焼いておくのもいいでしょう。 ただし、!SystemRescueCdでは、ブートローダだけが壊れたシステムを手っ取り早く起動することはできません。 !SystemRescueCdのCDブートLinuxで起動して、GRUBを正しく設定しなおすことが求められます。

今日はここまで

今日はここまで。続き、つまり最大の山場は、サーバの設置場所に行ったときにやります。 このまま遠隔操作でなんとかできちゃう気もするのですが、何か間違えたときにどうにもならないので、それはやめておきます。

このあとのあらすじ

  • fdisk /dev/sdaで、sda1のシステムIDをRAIDに変える。
  • /dev/sda1をRAIDに参加させる。
  • mkswap /dev/sdb2、vi /etc/fstab、swapon -a
  • GRUB stage1/stage2のインストール。
  • 再起動。祈る。
  • リビルドを待つ(放置)。
  • ドライブをはずして、再起動してみたりする。

2008/1/9 sgk


以下、一時置き場。

GRUB stage1/stage2をインストール

GRUBのstage1をsdbのMBRにインストールします。 パーティションに直接にファイルシステムを入れてある場合には簡単なのですが、パーティションでRAIDを構成し、その中にファイルシステムが有る場合には、ちょっと面倒です。

grub」コマンドを実行して、以下のように操作します。

# 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/sdb
grub> root (hd0,0)
 Filesystem type is ext2fs, partition type 0xfd
grub> install --stage2=/mnt/boot/grub/stage2 /boot/grub/stage1 d (hd0) /boot/grub/stage2 /boot/grub/menu.lst
grub> quit
# 

上記の「/boot/grub/stage2」の後に「0x8000」を指定する流儀もあるようですが、指定しなければ自動的に決定されます。 むしろ、指定しない方がいいと思います。

device (hd0) /dev/sdb
今回の操作の中で「(hd0)」とは「/dev/sdb」のことだと宣言します。
root (hd0,0)
今回の操作の中で「ルートデバイス」は「(hd0,0)」だと宣言します。
install --stage2=/mnt/boot/grub/stage2 /boot/grub/stage1 d (hd0) /boot/grub/stage2 /boot/grub/menu.lst
stage1をsdbドライブの先頭にインストールします。 現在このパーティションをマウント中なので、「--stage2=...」が必要です。 さもないと、マウント中にもかかわらず、ブロックデバイスを直接に変更してしまいます。 起動時に「起動ドライブ(stage1を読み込んだドライブ)以外のドライブでもstage2を探す」ことを、「d」で指示します。 ※「--stage2=...」以外の引数でファイル名のような物は全て、ルートデバイス中でのファイル名です。