LVMボリュームをSoftware RAID1の上に載せ替えてみた



## 背景

RAID1はバックアップにあらず、という話はちらほら聞くし、そうだと思う。実際バックアップでちゃんと運用しようと思うと面倒なので、もうRAID1にしたくなった（なんで最初からRAID1にしなかったのかというと、TimeMachineのバックアップストレージをRAID1にする必要はないかな、と思ったからだったが、2TBのディスクが無駄に余っているのでその必要すらなかった・・）。
こんなこともあろうかと™、既存のディスクLVMにしておいたので、Logical Volumeを生のディスクからRAID1に載せ替えた。

※実はLVMにもmirroring機能があるが、以前運用していた時に、同期のためのbitmapを外部のディスクに持たないと再起動のたびにresyncするとかいう仕様に疲れたので、今回は使わなかった。

## 前提

- 自分の環境はUbuntu 14.04 LTS Desktop Editionです。
- 全く同じディスクが2台接続されていて、片方が未使用である（自分はバックアップ用のディスクを消した）。
- rootがLVMに載っている。下記を想定しているが環境に合わせて読み替え願います。
  - Volume Groupはデフォのubuntu-vg
  - Logical Volumeはデフォのrootとswap_1
  - Phisical Volumeはデフォの/dev/sda5
- 但し書きがなければコマンドはsudoで打ってます。

## 免責事項

お決まりの **自己責任**。

ミスった操作やバグを踏まなければ基本的に起動できなくなっても復旧できる手順ですが、データを飛ばす勇気やどんな手段を使ってでも復旧する自身がなければ **バックアップをとってください** 。

また、この手順を踏む際は新旧どちらか片方でもディスクがぶっ壊れているとデータが破損します。smartctlやbadblocksなど、 **適切なツールを使用して壊れていないことを確認** してから進めることをおすすめします。

さらに、RAID1は正しく監視・運用しないと、いつの間にか両方のディスクが壊れたりするかもしれません。 **mdadmのメール通知などを適切に設定** してください。

## 準備

RAIDドライブの管理にはmdadmを使う。

```bash
apt-get install mdadm
```

LVMの管理にはlvsとかvgsとかpvsとか使うけど、すでにLVM構成の人はインストール済みのはず。

注意！！：起動できなくなることももちろんあるので、必ず現在のバージョンのLive CDや[Live USB](http://www.ubuntu.com/download/desktop/create-a-usb-stick-on-mac-osx)が起動できる状態であることを確認してから始めること。僕はこれで罠を乗り切りました・・。

## 手順

### 新しいディスクを初期化する

新しいディスクのパーティショニングにpartedを使います。あえてcfdiskではなくpartedなのは、gptを使用してみようかなと思ったため。

partedには-a optimalオプションを渡して、パフォーマンスが低下するようなパーティション配置を防いでおいたほうが良いそうです（align）。

```bash
parted -a optimal /dev/sdX # 注意！！！：中身が消えても良いデバイスかどうか、よく確認して下さい。

(parted) print # いわゆるlsです。
(parted) mklabel gpt # パーティションテーブル消して初期化します。警告出ます。

# /boot用の領域作ります。
(parted) mkpart # パーティション作ります。
Partition name?  []?
File system type?  [ext2]?
Start? 0% # 0%で指定すると、alignが自動調整されます。
End? 256MiB

(parted) print
Number  Start   End     Size    File system  Name  Flags
 1      1049kB  268MB   267MB

(parted) set 1 bios_grub on # これを指定しないとgrub-installが失敗します。

# LVM用の領域作ります。
(parted) mkpart
Partition name?  []?
File system type?  [ext2]?
Start? 256MiB
End? 100%

(parted) set 2 raid on

(parted) print
Number  Start   End     Size    File system  Name  Flags
 1      1049kB  268MB   267MB                      bios_grub
 2      268MB   2000GB  2000GB                     raid

(parted) quit
```

### 作ったパーティションをRAID1化する

先に便利なコマンドを紹介しておきます。

```bash
mdadm --detail --scan # RAIDデバイスのlsコマンド
```

下記でパーティションをRAID1で初期化します。

```bash
mdadm --create --level=1 --raid-devices=2 --bitmap=internal missing /dev/sdb1
mdadm --create --level 1 --raid-devices 2 --bitmap=internal missing /dev/sdb2
```

※なお自分は[degraded（片方壊れてる）なRAID1からbootするとき、起動時に聞かれる](https://help.ubuntu.com/community/Installation/SoftwareRAID#Boot_from_Degraded_Disk
)みたいな記述をみたので、下記のように無理やり「1デバイスのみ」のRAID1を作っちゃいましたが、特にその必要はないかと・・。

```bash
# device 1個とか普通しねぇよという警告出たらforceオプションをつける
mdadm --create --level 1 --raid-devices 1 /dev/sdb1 # /boot領域が/dev/md1に作成されるはず
mdadm --create --level 1 --raid-devices 1 /dev/sdb2 # LVM # LVM領域が/dev/md2に作成されるはず
# この方法で作ったら、あとでdevice追加した後にmdadm --grow --raid-devices 2しないとコピーが開始されない。
```

### /bootをRAID化する

LVMじゃなかったんで新しいファイルシステム作って全ファイル移動しました。

先に古いkernel消して/bootを軽くおいたほうが良いかもしれません。

```bash
apt-get autoremove
```

まずは/bootの中身をRAID1上にコピーします。

```bash
mdadm --detail --scan # でどの/dev/mdXがboot用なのか必ず確認して下さい！

mkfs.ext2 /dev/md1 # 現在の/bootがext2かどうかはmountコマンドで確認しておいてください。違う場合は該当fsで初期化するのがよさそうです。

mkdir newboot
mount /dev/md1 newboot
cp -dpr /boot/* newboot/ # -dpはpermissionとかownerとかlinkとかtimestampとかを維持するやつです。これやればmvと同じになると思っている。必要に応じて/boot/.*もコピーする。
```

fstabをRAID1の方に向けます。

```bash
tune2fs -l /dev/md1 | grep UUID
Filesystem UUID:          cdea643d-240c-476c-b2a4-8ec05bbd8647

nano /etc/fstab # お好きなエディタでどうぞ
# /bootのUUID欄を書き換える。もし/dev/...直指定だったら、/dev/md1に書き換える。
```

grubの設定を更新したりするので、新しい/bootをmountしておく。

```bash
umount newboot /boot
rmdir newboot
mount /boot # /etc/fstabを更新していれば新しいほうがmountされる。mountコマンドで/dev/mdXになってるか確認。
```

新しいデバイスにgrub（の最初に起動されるプログラム）をインストールする。注意！/dev/mdXじゃなくて/dev/sdXにインストール！

```bash
grub-install /dev/sdb
```

新しい/bootに合わせて、RAID対応の/boot/grub/grub.cfgを書き出す

```bash
update-grub # これやらないと/dev/sda1（旧/boot）を潰したあとに起動できなくなるはず
# /boot/grub/grub.cfgにinsmod mdraid1xという行が入っていれば成功しています。
```

※なお、grub自体のraid対応は、update-grubコマンドで、/usr/share/grub/grub-mkconfig_libのprepare_grub_to_access_deviceあたりで入るようですが、コード読む限り/bootがRAID1化されたあとじゃないと対応が入らないっぽいので、手順通りやらない場合は注意が必要です。

### 旧/bootを使わないように設定する


```bash
# 人柱になって古い/bootのパーテイションのbootフラグを落とします。
# これをすると、強制的にRAID1上の/bootから立ち上がるはず。
# 旧ディスクはcfdisk使えたのでぶっちゃけ↓のどっちが正しいかわからない。
parted /dev/sda set boot off
parted /dev/sda set bios_grub off

# （できるだけ）ここで一回新しい/bootで起動できるか確認してみてください。
# これを確認できていると、罠にハマった時に/がダメなのか/bootがダメなのか見分けるのが簡単になります。
reboot
```

起動できなくなったらLive USBとかでbootフラグ戻してください・・・。またはBIOSの設定書き換えてる人は旧bootドライブしか見ない設定になってないか確認して下さい。

### LVMのPhisical Volumeを初期化し、移動する

一応/dev/mdXが正しいかどうか、mdadm --detail --scanで確認して下さい。

```bash
pvcreate /dev/md2
vgextend ubuntu-vg /dev/md2
pvmove /dev/sda5 /dev/md2 # sda5に載ってるLogical Volumeを全部md2に移動
# 容量によってめちゃくちゃ時間かかります。なおこれ終了すると非RAIDのディスクからはもう起動できないのであしからず・・。
# このさきシャットダウンとかするとLive CDで作業することになりますorz...
```

これでいけると思うじゃん？？自分の環境だと/boot領域のサイズが微妙に違って残念結果になってしまいましたよorz... `Insufficient free space: 12800 extents needed, but only 12795 available` みたいなエラー出たら、swap_1のLogical Volumeのサイズを減らせば何とかなります。

```bash
swapoff /dev/mapper/ubuntu--vg-swap_1 # swapをメモリに吐き出してunmountする。メモリ足りなさすぎるとエラー。

lvresize -l -5 /dev/mapper/ubuntu--vg-swap_1 # ちっちゃくする。注意！！：-5は足りないextentsの数でやってください！上記エラーだと12800-12795の結果です！
mkswap /dev/mapper/ubuntu--vg-swap_1 # 小さくなったサイズで再初期化。

less /etc/fstab # でswapデバイスの指定方法を確認する。/dev/mapper/ubuntu--vg-swap_1と書かれていればおｋだが、UUIDと書かれていたら、swaplabelコマンドで取れるUUIDに書き換えておく。手元だとパスで指定されていたので不要だった。

swapon /dev/mapper/ubuntu--vg-swap_1

pvmove /dev/sda5 /dev/md2 # リトライ
```

### RAID1な/をmountする対応をしておく

※pvmove実行中にやって良さそうな気がします。

このままだと再起動後に "incrementally starting raid arrays" というログが出続けて起動しなくなります（rescue modeもダメ、自分はこの状態になってLive USB対応しましたorz）。

```bash
# RAIDデバイスのマッピングを書いておく。/etc/fstabで/dev/mdXを参照していなければなくてもいけるかもしれないが、update-initramfsの時に警告が出たので・・。
mdadm --detail --scan >> /etc/mdadm/mdadm.conf

# boot時にraid1をロードする。これやらないと上記のエラーログループ。
echo 'raid1' >> /etc/initramfs-tools/modules # 中身よく見るとexamplesにraid1って書いてあったorz...
update-initramfs -k all -u # raid1モジュールが起動時に使えるようになる

# 不要な気もするが念のためgrubも更新する
update-grub
```

### 旧ディスクをVolume Groupから取り除く＋人柱の再起動

pvmoveが終わった旨が表示されたらvgreduceして再起動してみる。

```bash
vgreduce ubuntu-vg /dev/sda5
# 失敗するならpvmoveも正しく終わってないですよ・・！？

# 祈る
reboot
```

### 旧ディスクをRAID化する

再起動できたら旧ディスクをRAID化して追加しちゃいます。

まずは、「新しいディスクを初期化する」の手順を旧ディスクに適用します。注：全く同じサイズでpartition切らないともちろん問題になりそう・・。

/dev/sda1 (/boot用)と/dev/sda2 (/用)が初期化されたとします。

次に一応grubを再インストールします。

```bash
grub-install /dev/sda
```

最後にRAID1に追加します。

```bash
# mdadm --detail --scanやmountなどで、どの/dev/mdXが何用なのかは必ず確認して下さい。

mdadm --manage -a /dev/md1 /dev/sda1
mdadm --manage -a /dev/md2 /dev/sda2

# 以前の手順で--raid-devices 1にしている人はここでmdadm --grow --raid-devices 2してください
```

RAIDの状態を確認してみます。

```bash
mdadm --detail /dev/md1 # syncが一瞬で終わってState : activeになってました

mdadm --detail /dev/md2 # 
# 中略
    Update Time : Sat Apr  4 14:51:12 2015
          State : active, degraded, recovering
 Active Devices : 1
Working Devices : 2
 Failed Devices : 0
  Spare Devices : 1

 Rebuild Status : 50% complete

           Name : ubuntu:2
           UUID : 258cf472:ddec60d4:878cde67:86a9dd16
         Events : 5469

    Number   Major   Minor   RaidDevice State
       0       8       18        0      active sync   /dev/sdb2
       1       8        2        1      spare rebuilding   /dev/sda2

# ↑手元で出したものですが、やり方の都合で実際に表示される順番とちょっと違います。spare rebuildingになってれば大丈夫かと。
```

### お疲れ様でした

rebuildが終わればRAIDになってるはずです！

冒頭にも書きましたが、RAIDは監視・運用してはじめてデータが安全に保たれます（この点はバックアップと変わりませんが）。
上手に使っていきましょう・・！

※あ、あと、swapがちゃんと有効化されているか確認しておいてください。

## 起動しなくなった時のトラブルシューティング

### 環境準備

1. Live USBが一番楽です。Live CD/USBは必ず先に用意しておきます。
  - [MacでLive USBを作る場合](http://www.ubuntu.com/download/desktop/create-a-usb-stick-on-mac-osx)
  - 現在インストールされているUbuntuのバージョンのものを用意したほうが良いはずです。
  - Desktop版なら、Alternate Install CDのイメージを用意すると良いようです。
  - Desktop版のLive CDイメージの場合、作業開始前に別手順が必要です。
2. マシンをCD/USBから起動します。BIOSの設定やF12などが必要な場合があります。
3. Desktop版Live CDイメージの場合
  - Ctrl+Alt+F1〜F6でコンソールが出せます。
  - apt-get install mdadm --no-install-recommends します。
  - mdadm --assemble --scan で既存のRAIDを初期化します。LVMはこれと同時に必要に応じて初期化されます。
4. 本来の/をmountしておきます
  - mkdir newroot
  - mount /dev/ubuntu-vg/root newroot
5. /devなどを[bind mount](https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Storage_Administration_Guide/sect-Using_the_mount_Command-Mounting-Bind.html)します。
  - 便利ツール https://gist.github.com/ypresto/80e32204df4354b9634a
6. chrootします
  - chroot newroot
7. /bootをmountします
  - mount /boot

### 確認箇所

- /etc/initramfs-tools/modulesにraid1を書いてからupdate-initramfsしたか
- update-grubしたか、/boot/grub/grub.cfgにmdraid1が入ってるか
- /etc/fstabの/bootのUUIDは書き換えたか

## 参考資料

- https://help.ubuntu.com/community/Installation/SoftwareRAID
- https://feeding.cloud.geek.nz/posts/setting-up-raid-on-existing/
- http://askubuntu.com/questions/200801/how-should-a-raid-partition-be-created-and-configured-using-parted
- エラーメッセージが出たらだいたいそれをググった