mdadmを用いたソフトウェアRAIDの管理

# はじめに

RAIDケースのハードウェアRAID機能を使ってきたけれども、さらに大規模なデータを扱うためにソフトウェアRAIDを有効に使っていくことにしました。

ハードウェアRAIDのケースをソフトウェアRAIDで繋ぐといった操作を目指していますが、リビルドなどに非常に長い時間がかかるために、この記事では4GBほどの非常に小規模なデータのソフトウェアRAIDで実験しました。

RAIDタイプはRAID5を使います。徐々に買いながらストレージを増やしていこうと考えているので、一度ソフトウェアRAIDを作った後に追加するための方法も記述していきます。

今回の作業は

```
Ubuntu 20.04
mdadm - v4.1 - 2018-10-01
```
で行いました。

# デバイス名の確認

初めにRAIDを構成するデバイスのデバイス名(/dev/sdaなど)を確認します。
GUIのディスクアプリを使うのが簡単ですが

```
sudo fdisk -l
```

としても良いです。この後の作業でデバイス名を間違えると、データ損失など大変なことになるので注意深く進めましょう。

# デバイスにパーティションを作成

Gpartedを用いてそれぞれのデバイスにパーティションを作成する。デバイスを丸ごとRAIDにすることもできるが、パーティションを作ってから、そのパーティションを作った方が、取り扱いが楽なように見える。

Gpartedを開いて
1. デバイス→パーティションテーブルの作成→gptとして適用
2. パーティション→新規→ファイルシステム(xfs)として追加

この作業をそれぞれのデバイスについて行う

# 新しいRAIDアレイの構築

`mdadm`を使います。`mdadm`の詳しい使い方については、`man mdadm`として確認しましょう。
上記で確認したデバイスのパーティション3つ（ここでは/dev/sdm1 /dev/sdn1 /dev/sdl1とする）を1つのRAIDアレイにします。

```shell-session
sudo mdadm --create --verbose --force --assume-clean --raid-devices=3 --level=raid5 /dev/md16 /dev/sdm1 /dev/sdn1 /dev/sdl1
```

mdadmの使い方は以下のようになっています。

```
sudo mdadm (オプション) (RAIDアレイ名) (繋げるデバイスのパーティション名)
```

ここでそれぞれのオプションの意味は以下のようになっています。

```shell-session
--create: 新しいRAIDアレイを作るオプション。一番最初に書く
--verbose: コマンド実行時に表示される情報を増やす
--force: オプションによって動作は異なるが、ここではRAID5作成時にスペアを作らせないため
--assume-clean: マニュアルを読むとなくても大丈夫なように見えるが、これをつけないとリビルドが始まってしまう
--raid-devices=N: デバイスの数
--level: RAIDレベル。RAID0やRAID5のこと
```

最初のオプション(ここでは`--create`)さえ一番最初に持ってくればあとの順番は多少融通が効くようです。
`--force`と`--assume-clean`オプションを付けないと、デバイスのうちを一つをスペアとして取り扱い構築と同時にリビルドを始めてしまいます。一つをスペアとして使った方が、高速に動作するようですが、最初のリビルドにとても長い時間がかかるために、これを避けたい場合は`--force`と`--assume-clean`オプションをつけると良いです(特に練習の時は時間節約のために必要でしょう)。

# RAIDアレイのフォーマット

`fdisk`や`Gparted`でフォーマットを行います。`Gparted`で行う場合は
1. デバイス
2. パーティションテーブルの作成
3. 新しいパーティションテーブルの形式を選択 gpt, 適用
4. パーティション
5. 新規
6. ファイルシステムxfs, 追加
7. チェックマークをクリック
と進めていきます。

# /etc/mdadm/mdadm.conf

このままでもRAID arrayは使えるのだが、再起動するとデバイス名が変わってしまうことがよくある。その対策のために

```
sudo mdadm --detail --scan 
```

として出力される結果を`/etc/mdadm/mdadm.conf`に貼り付ける。その後

```
sudo update-initramfs -u
```

とすることで情報をアップデートする。

# 新しいデバイスの追加

すでに構築されたRAIDアレイに新しくデバイスを追加したくなった場合を見ていきます。追加するデバイスのパーティション(ここでは/dev/sds1とする)をよく確認したのちに、以下のコマンドで追加します。

```
sudo mdadm --add /dev/md16 /dev/sds1
```

さらに以下のコマンドで容量を増やします。

```
sudo mdadm --grow /dev/md16 --raid-disks=4
```
`--raid-disks`のところには増やした後のデバイスの数を書きます。この操作をした後に`reshape`が始まります。デバイスの追加後の`reshape`は、CPU・I/O性能にも依存しますが、非常に長い時間がかかります。気長に待ちましょう。
以下のコマンドで`reshape`の進捗を確認することができます。

```
cat /proc/mdstat
```

100%となったらおしまいです。ここまでできたらシステムに容量が増えたことを知らせます。
`xfs_growfs`を用いても行うことは可能ですが、ここでもGpartedを使うのが簡単です。

Gpartedを開くと

```
Not all the space available to /dev/*** appears to be 
used, you can fix the GPT to use all of the space (an extra 
****** blocks) or continue with the current setting?
```

と聞かれるのでfixをクリックする。その後、Gpartedで該当RAIDアレイを選択してリサイズ。最大値とします。「データの消失する可能性があります」と言われるので、データが消失する可能性があるのかもしれません(何度か試しましたが、データが消えたことは今のところありません)。


# RAIDアレイを作り直したいとき

作ったRAIDアレイがいらなくなった場合は、以下のようにしてストップします。

```shell-session
sudo mdadm --misc --stop /dev/md16
```

動いているRAIDアレイは以下のコマンドで確認できます。

```shell-session
cat /proc/mdstat 
```

これだけでRAIDアレイが消えてくれる場合もありますが、多くの場合それぞれのデバイスには情報が残っていて、再起動などをすると見たことのないRAIDアレイが出現します(ここでは/dev/md01としておきます)。

まずは、出現したRAIDアレイの情報を見ます。構成しているデバイスのパーティションをメモしておきます(ここでは/dev/sdm1, /dev/sdn1, /dev/sdl1としておきます。)。

```shell-session
sudo mdadm --detail /dev/md01
```

RAIDアレイを止めます。

```shell-session
sudo mdadm --misc --stop /dev/md01
```

スーパーブロックにゼロを書き込んで情報を消します。構成していた全てのデバイスについて行います。

```shell-session
sudo mdadm --misc --zero-superblock /dev/sdm1
sudo mdadm --misc --zero-superblock /dev/sdn1
sudo mdadm --misc --zero-superblock /dev/sdl1
```
実際は、最初にストップしたときに、`zero-superblock`をやっておけばいいものと思います(試していません)

#デバイスが故障したとき(の練習)

故障を特定したら`--fail`の印をつけます。

```shell-session
sudo mdadm --manage /dev/md16 --fail /dev/sdn1
```

```shell-session
cat /proc/mdstat
```
とすると該当デバイスに(F)のマークがついていることがわかります。以下のコマンドで故障したデバイスを取り除きます。

```shell-session
sudo mdadm --manage /dev/md16 --remove /dev/sdn
```

トラブルの練習の時は、一度取り外したデバイスに`zero-superblock`して

```shell-session
sudo mdadm --misc --zero-superblock /dev/sdn
```

再度追加します(本当に故障した時は新しいものを追加するようにしましょう)。

```
sudo mdadm --manage /dev/md16 --add /dev/sdn1
```

# RAIDアレイのモニター

[こちら](https://www.suse.com/support/kb/doc/?id=000016716)を参考にさせていただきました。

`--monitor`でRAIDを監視します。まずは、`/etc/mdadm/mdadm.conf`を編集します。状況によっては`/etc/mdadm.conf`の場合もあるようです。

```conf
DEVICE partitions # デバイス名でなくパーティションでRAIDを判断するための印
PROGRAM /etc/raid_events # モニターでFailがあったときに実行されるプログラム(任意の場所・名前で良い)
```

実行するプログラムでは、Failがあったときに`/etc/motd`にメッセージを書き込みログイン時にメッセージを読み取れるようにしておきます。

```shell
#!/bin/bash
#
# mdadm RAID health check
#
# Events are being passed to xmessage via $1 (events) and $2 (device)
#
# Setting variables to readable values
event=$1
device=$2
# Check event and then popup a window with appropriate message based on event
if [ $event == "Fail" ];then
    echo  >> /etc/motd
    echo CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC >  /etc/motd
    echo CCCCC A failure has been detected on device $device CCCCC >> /etc/motd
    echo CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC >> /etc/motd
    echo  >> /etc/motd		
    #xmessage "A failure has been detected on device" $device
else
    if [ $event == "FailSpare" ]; then
	echo  >> /etc/motd
	echo CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC >  /etc/motd
	echo CCCCC A failure has been detected on spare device $device CCCCC >> /etc/motd
	echo CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC >> /etc/motd
	echo  >> /etc/motd		
        #xmessage "A failure has been detected on spare device" $device
    else
        if [ $event == "DegradedArray" ]; then
	    echo  >> /etc/motd
	    echo CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC >  /etc/motd
	    echo CCCCC A Degraded Array has been detected on device $device CCCCC >> /etc/motd
	    echo CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC >> /etc/motd
	    echo  >> /etc/motd
            #xmessage "A Degraded Array has been detected on device" $device
        else
	    if [ $event == "TestMessage" ]; then
		echo  >> /etc/motd
		echo CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC >  /etc/motd
		echo CCCCC A Test Message has been generated on device CCCCC >> /etc/motd
		echo CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC >> /etc/motd
		echo  >> /etc/motd		
                #xmessage "A Test Message has been generated on device" $device
            fi
        fi
    fi
fi
#~~~~~~~~~~~~~~~~~~~~~~~~~ End of Script ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

```

ここまで準備ができたら

```shell
sudo mdadm --monitor --scane
```
としてモニターを始めます。

```shell
sudo mdadm --manage /dev/md16 --fail /dev/sdn1
```

として一度Failにしてみます。そうするとログインメッセージに

```shell
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCC A failure has been detected on device /dev/md16 CCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
```

などと表示されるはずです。メッセージをリセットしたい場合は`/etc/motd`の中身をクリアしてください。
普段のモニターは一時間に一回ほどすれば良いと思うので

```shell-session
sudo mdadm --monitor --scan --daemonize --delay=3600
```
とします。`--daemonize`としてデーモン化します。これでうまく行くのか確証はありませんが、しばらく運用してこの記事を更新したいと思います。