mdraid上のファイルシステム拡張手順備忘録

この度、RAID1のmd上のファイルシステムをオンラインで拡張したので、備忘録を残しておきます。

# 前提
- 環境はArchLinux、SATA上の6TBHDD2台でmdadmを使い、RAID1を組んでいます。
- 筆者の環境では、mdデバイス上に複数のパーティションを切るのではなく、物理ディスク2台に同じサイズの複数のパーティションを切って、複数のmdデバイスを作っています。
- もし一つの大きなmdデバイス上に複数のパーティションを切りたい場合は、LVMを活用することで拡張性を確保する設計にすることをおすすめします。
- 一つの大きなmdデバイス上に複数のパーティションを切っており、内側からパーティションを拡張したい場合は、1台のHDDのパーティション用の手順を参考に出来ると思いますので、探してみてください。多分GParted等を使う手順が見つかります。
- 当たり前ですが、ディスクに空きがあることを前提としています。空きがない場合はディスクを買い直すなり追加するなりしてください。

# 発端
### 容量不足の顕在化
当初からvarは10GB、homeは100GBと現代のメインマシンとしては少々小さめで、正直ちょっとしんどい感じではあったものの、あまりハードは使い方はしないので特に問題はありませんでした。
しかし、この度とあるゲームをインストールしようとしたところ、40GBほど求められ、一瞬で詰んだので、致し方なくめんどくさいながらパーティションを切り直すことにしました。

# 計画

## コンセプト
1. /varは2倍、/homeは3倍、/shareは2倍にする
2. めんどくさいのは嫌だ！
3. なのでバックアップは取らないしシングルユーザモードもやだ！
4. でも安全を期したい
5. お参りは済ませているしお守りも完備している

### 現状
メインマシンはArch Linuxで、/はNVMeのSSD上、/var、/home、/home/share（ファイルサーバ領域）がHDDのRAID1上にあります。
今回、/homeの拡張が必要になりましたが、この際RAID1上のパーティションをまとめて拡張したいと思います。

### 課題
RAID1を使っている場合、容量を増やそうと思うと、通常のパーティション拡張と違い、かなり手順が面倒です。
１．RAID1の2台のHDDの内、1台を切り離す。
２．切り離したHDDのパーティションを切り直す。
３、切り離したHDDをRAID1に復帰する。
４、同期させる。
５、もう1台のHDDを切り離す。
６、以下２〜４を繰り返し

とてもめんどくさそうです。。。



# 実施
## まず現状を把握する
```
// デバイス状況
$ ls -l /dev/disk/by-uuid/
lrwxrwxrwx 1 root root 10 Mar 20 11:02 xxxxxxxxxxxx -> ../../sdb1
lrwxrwxrwx 1 root root  9 Mar 20 11:02 xxxxxxxxxxxx -> ../../md1
lrwxrwxrwx 1 root root  9 Mar 20 11:02 xxxxxxxxxxxx -> ../../md0
lrwxrwxrwx 1 root root 15 Mar 20 11:02 xxxxxxxxxxxx -> ../../nvme0n1p2
lrwxrwxrwx 1 root root  9 Mar 20 11:02 xxxxxxxxxxxx -> ../../md2
lrwxrwxrwx 1 root root 15 Mar 20 11:02 xxxxxxxxxxxx -> ../../nvme0n1p1
lrwxrwxrwx 1 root root 10 Mar 20 11:02 xxxxxxxxxxxx -> ../../sda1

// sda1とsdb1はswapにあてています。

// 物理パーティション
# parted -a opt /dev/sda
(parted) u MiB
(parted) p
Number  Start      End         Size        File system     Name    Flags
 1      1.00MiB    32769MiB    32768MiB    linux-swap(v1)  swap
 2      32769MiB   43009MiB    10240MiB                    var1    raid
 3      43009MiB   145409MiB   102400MiB                   home1   raid
 4      145409MiB  1193985MiB  1048576MiB                  share1  raid
(parted) q

# parted -a opt /dev/sdb
(parted) u MiB
(parted) p
Number  Start      End         Size        File system     Name    Flags
 1      1.00MiB    32769MiB    32768MiB    linux-swap(v1)  swap
 2      32769MiB   43009MiB    10240MiB                    var2    raid
 3      43009MiB   145409MiB   102400MiB                   home2   raid
 4      145409MiB  1193985MiB  1048576MiB                  share2  raid
(parted) q

//mdデバイス
$ cat /proc/mdstat
md0 : active raid1 sdb2[1] sda2[0]
      10476544 blocks super 1.2 [2/2] [UU]
      
md2 : active raid1 sda4[0] sdb4[1]
      1073609728 blocks super 1.2 [2/2] [UU]
      bitmap: 0/8 pages [0KB], 65536KB chunk

md1 : active raid1 sda3[0] sdb3[1]
      104791040 blocks super 1.2 [2/2] [UU]

# mdadm --detail --scan
ARRAY /dev/md2 metadata=1.2 name=myhost:2 UUID=xxxxxxxxxxxxxxxx
ARRAY /dev/md1 metadata=1.2 name=myhost:1 UUID=xxxxxxxxxxxxxxxx
ARRAY /dev/md0 metadata=1.2 name=myhost:0 UUID=xxxxxxxxxxxxxxxx

//ファイルシステム
$ mount
/dev/nvme0n1p2 on / type ext4 (rw,noatime)
/dev/nvme0n1p1 on /boot type vfat (rw,noatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
/dev/md0 on /var type ext4 (rw,noatime)
/dev/md1 on /home type ext4 (rw,noatime)
/dev/md2 on /home/share type ext4 (rw,noatime)

// 大分はしょってます。
```
今回、拡張したいのはmd0、md1、md2で、それぞれsda/bの2,3,4番のパーティションで構成されています。

## RAIDのチェック
RAIDの状態をチェックし、実はエラーがあって復旧出来なかった、みたいな惨事を出来うる限り避けます。

// かなり時間がかかりますので、本を読むなり用事を片付けるなりしておくとよいと思います。

```
# echo check > /sys/block/md0/md/sync_action 
# echo check > /sys/block/md1/md/sync_action 
# echo check > /sys/block/md2/md/sync_action 
```

## RAIDの解除
満を持してRAIDを解除します。
今回は副ボリューム（sdb側）から切り離します。

```
# mdadm --manage /dev/md0 --fail /dev/sdb2
# mdadm --manage /dev/md1 --fail /dev/sdb3
# mdadm --manage /dev/md2 --fail /dev/sdb4
# cat /proc/mdstat     // 間違ってない事を確認

# mdadm --manage /dev/md0 --remove /dev/sdb2
# mdadm --manage /dev/md1 --remove /dev/sdb3
# mdadm --manage /dev/md2 --remove /dev/sdb4
# cat /proc/mdstat　   // RAIDから切り離されたことを確認
```

## superblockの削除
これをやっておかないとパーティションが作り直せませんので、必ず実行しておいてください。
実施前に深呼吸して対象パーティションが間違っていないことを確認してください。

```
mdadm --misc --zero-superblock /dev/sdb2 /dev/sdb3 /dev/sdb4
```

## パーティションの再作成
切り離した方のディスクのパーティションを切り直します。
こちらは間違えると多分エラーが出ますが、やはり深呼吸してからのほうが良いかと思います。

```
# parted -a opt /dev/sdb
(parted) u MiB
(parted) p
 1      1.00MiB    32769MiB    32768MiB    linux-swap(v1)  swap
 2      32769MiB   43009MiB    10240MiB                    var2    raid
 3      43009MiB   145409MiB   102400MiB                   home2   raid
 4      145409MiB  1193985MiB  1048576MiB                  share2  raid
(parted) rm 2
(parted) rm 3
(parted) rm 4
(parted) mkpart PRIMARY 32769 53249
(parted) mkpart PRIMARY 53249 360449
(parted) mkpart PRIMARY 360449 2457601
(parted) name 2 var2
(parted) name 3 home2
(parted) name 4 share2
(parted) toggle 2 raid
(parted) toggle 3 raid
(parted) toggle 4 raid
(parted) p
 1      1.00MiB    32769MiB    32768MiB    linux-swap(v1)  swap
 2      32769MiB   53249MiB    20480MiB                    var2    raid
 3      53249MiB   360449MiB   307200MiB                   home2   raid
 4      360449MiB  2457601MiB  2097152MiB                  share2  raid
(parted) q
```

パーティションが無事拡張されました。
## RAIDの回復
これも相当時間がかかります。同期完了までの間は冗長性がありませんのでおすすめはしませんが、電源をオフすることも可能です。
電源オンすると自動的に同期が再開します。

```
mdadm --manage /dev/md0 --add /dev/sdb2
mdadm --manage /dev/md1 --add /dev/sdb3
mdadm --manage /dev/md2 --add /dev/sdb4
```

下記コマンドで進捗状況を監視することが可能です。
`$ watch cat /proc/mdstat`

同期速度を上げたい場合は、こんなふうにパラメータをいじれます。（単位はKB/S）
`# echo 400000 >/proc/sys/dev/raid/speed_limit_max`

終わったらctrl-cで終了します。

## 反対側ディスクでRAID解除からRAID回復までを実施
mdデバイスは最小のパーティションに合わせたサイズになりますので、現状ではまだボリュームのサイズは変わっていません。
上記の例では/dev/sdb側からやったので、同じ操作を今度は/dev/sda側でやります。
結局めんどくさいじゃないか、と言われそうですが、多分これ以上は無理なので許してください。

以下デバイス違いの同じ手順なので省略

## RAIDボリュームの拡張
ここまで来てやっとRAIDボリュームが拡張出来ます。

```
# mdadm --grow /dev/md0 --size=max
# mdadm --grow /dev/md1 --size=max
# mdadm --grow /dev/md2 --size=max
```

## ファイルシステムの拡張
ここまで来たらあと一歩、と言いたいところですが、実は拡張したパーティションに対しても再同期が走るので、結構時間がかかります。
前の再同期と同様、電源オフすることも可能です。冗長性はありませんが、夜中遅くて耐えられない人は電源オフして寝るのも一手です。

```
resize2fs /dev/md2
resize2fs /dev/md1
resize2fs /dev/md0
```

進捗状況を眺めたい人は前と同様下記で眺められます。
`$ watch cat /proc/mdstat`

## 事後確認
お疲れ様でした。ここまでエラーなく終わっていたら、目的が達成されているはずですが、念の為状況を確認しておきましょう。

```
$ ls -l /dev/disk/by-uuid/
lrwxrwxrwx 1 root root 10 Mar 20 11:02 xxxxxxxxxxxx -> ../../sdb1
lrwxrwxrwx 1 root root  9 Mar 20 11:02 xxxxxxxxxxxx -> ../../md1
lrwxrwxrwx 1 root root  9 Mar 20 11:02 xxxxxxxxxxxx -> ../../md0
lrwxrwxrwx 1 root root 15 Mar 20 11:02 xxxxxxxxxxxx -> ../../nvme0n1p2
lrwxrwxrwx 1 root root  9 Mar 20 11:02 xxxxxxxxxxxx -> ../../md2
lrwxrwxrwx 1 root root 15 Mar 20 11:02 xxxxxxxxxxxx -> ../../nvme0n1p1
lrwxrwxrwx 1 root root 10 Mar 20 11:02 xxxxxxxxxxxx -> ../../sda1
// うまくいっていれば何も変わっていないはずです。

$ cat /proc/mdstat
md0 : active raid1 sda2[3] sdb2[2]
      20962304 blocks super 1.2 [2/2] [UU]
      
md2 : active raid1 sda4[3] sdb4[2]
      2147351552 blocks super 1.2 [2/2] [UU]
      bitmap: 2/8 pages [8KB], 131072KB chunk

md1 : active raid1 sda3[3] sdb3[2]
      314506240 blocks super 1.2 [2/2] [UU]
# mdadm --detail --scan
ARRAY /dev/md2 metadata=1.2 name=myhost:2 UUID=xxxxxxxxxxxxxxxx
ARRAY /dev/md1 metadata=1.2 name=myhost:1 UUID=xxxxxxxxxxxxxxxx
ARRAY /dev/md0 metadata=1.2 name=myhost:0 UUID=xxxxxxxxxxxxxxxx
// うまくいっていれば何も（略

$ mount
/dev/nvme0n1p2 on / type ext4 (rw,noatime)
/dev/nvme0n1p1 on /boot type vfat (rw,noatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro)
/dev/md0 on /var type ext4 (rw,noatime)
/dev/md1 on /home type ext4 (rw,noatime)
/dev/md2 on /home/share type ext4 (rw,noatime)
// うまくいって（ｒｙ
```

# 終わりに
大体半日くらいの作業でした。
まあ思ったよりは楽だったかな、ということで、一応記録を残しておきます。
なお、今回mdデバイス上にパーティションを切らず、物理パーティション上にmdデバイスを切っているので、動的な拡張が出来ましたが、もしこれがmdデバイス上にパーティションを切る形だとこの作業は出来なかったと思います。