Ubuntu ServerでソフトウェアRAID1したい
ただ、それだけだった。はずなのに。
調べれば調べるほど、どれが正しい方法か、わからなくなった…(今でもわからない)。
やりたいことや環境に応じた選択肢が用意されている、と前向きに考えてみる。
やったことまとめ
- Ubuntu 16.04 Serverで、mdadmでなくLVMミラーリングしてみた
- ほぼ普通にインストールした後に、ミラーを作成できて、楽だった
- UEFI環境で、2台目ディスクからも起動できた
- 起動まわりの設定は、UEFIだからか、少し面倒だった
- 性能未測定
手順まとめ
- Ubuntu ServerをLVMでインストール時に、rootのLVを少しだけ小さくする
- GPTのパーティションテーブルを
sgdisk
でコピー- 2台目のGUIDは生成し直し
- ESPと/bootパーティションを
dd
でコピー -
update-grub
で、/bootのgrub設定をアップデート- ESP内のgrub設定は手動編集
-
efibootmgr
で、2台目ESPのエントリーを、UEFIのNVRAMに登録 -
lvconvert -m 1
でミラー作成 - swapは2つ作ってミラーせず
-
fstab
で、ESPと/bootとswapのオプションに、nofail
指定
ここにたどり着くまでが長かった…。
以下はその過程。
環境
事前に決めていたのは、Ubuntu Server 16.04と、ソフトウェアRAID1を使うことだけ。
あと、なるべく楽したい…。
調査
RAID1実装とファイルシステム
RAID1するにも、環境がいろいろある。
- mdadm
- LVM
- Btrfs
- ZFS
どちらのディスクでも起動できるように設定すると、問題が起こった時に楽だが、起動に関連する要素もいろいろある。
- BIOS
- UEFI
- MBR
- GPT
通常、起動関連はハードウェアに紐づいて選べないが、今回は仮想マシン上に新規構築するため、何でも選べる。
物理マシンへのインストールも想定し、起動はUEFIで、ファイルシステムはデフォルトのext4。
最近LVMに救われているので、UEFI+GPT+mdadm(+LVM+ext4)と仮決め。
mdadmとLVM
この2つを同時に使う場合、理論的には以下の選択肢がある。
- mdadmで作成したmdデバイス上でLVMする(LVM on RAID1)
- LVMで作成したLVデバイス上でmdadmする
この選択肢については、こちらが詳しい。こちらにも議論がある。
こちらでは前者、LVMとRAIDに関するArchWikiの記事やLinux RAIDの記事、Ubuntu Community Helpの記事も前者。
とりあえず、前者のLVM on RAID1を選択。
この場合、RAIDパーティション全体がミラーされることになる。
swapはどうなる?
RAID1とswap
swapをミラーするかどうかも、議論がある。
クリティカルな環境ではないので、swapのミラーは不要としよう。
一方、インストーラーの自動パーティショニングに頼ると、md上にswapが作られ、自動的にミラーされてしまう気がする。
インストール前にmdを作るのだろうから、インストール前に手動パーティショニングすることになる?
インストールとパーティショニング
UbuntuインストールガイドのSoftware RAIDの項目に "Select Manual as the partition method" とあるので、インストール時にマニュアルでパーティショニングするものなのだろう。
こちらにmdadmでの詳細手順例があるが、なかなか大変そう…。
今回はUEFIなので、ESPも作成する必要がある。
なるべく楽な方法は?
方針変更
Ubuntu16.04のmdadmに、degrade時の起動に問題があり、パッケージを16.10のものに更新する必要があるという記事を見つけた。うーむ。
先ほどのRAID1とLVMの記事では、LVMにミラーリング機能があるとのこと。
こちらのほうが、自動パーティショニングでインストールした後、簡単にミラーを作れそうな気がしてきた。mdadmの問題も回避できるかも?
LVMのミラーリング機能
先ほどの記事では、トータル性能や電源断耐性は、mdadmのほうがよさそうだ。
でも、クリティカルな用途でないので、とりあえずLVMでやってみよう。
こちらに実施例があるが、楽そうに見える。(フラグ)
ただ、RAID1を開始するlvconvert -m1
でエラーが出る、との情報が気になる。
こちらの記事の、外部のディスクがいる、というのも気になる。
LVMのextent不足
試しにVGにsdb3を足して、lvconvert
してみる。
# lvconvert -m1 /dev/hoge-vg/root /dev/sdb3
Insufficient free space: 1 extents needed, but only 0 available
エラーが出た。文字通り、RAID1化に必要なLVMの空きextentが足らないのだろう。
こちらでは、ext4とLVを縮めてVGに空きを作っている。(ちなみにXFSはオフラインでも縮められないのか…)
こちらによると、lvconvert
時のオプション--alloc anywhere
で3台目を不要にできるとある。3台目の代わりに、空きextentを使うということ?
今回は新規インストールなので、パーティショニング時のLVの容量をちょっと小さくすれば、空きextentを使って2台でRAID1にできると予想。
ArchWikiのRAIDの項目でも、RAID1では100MBくらい残しておけば?と書いてある。(今回は仮想化環境なので条件が異なり、意味ないかもだが)
幸い、Ubuntu ServerではLVMでのインストール時にrootのLVのサイズを聞かれるので、0.1GBだけ減らしてみる。インストールガイドのStep 12.参照。
Ubuntuの自動パーティション構成
LVMでインストールした後に、gdisk
でパーティションを確認すると、
Number Start (sector) End (sector) Size Code Name
1 2048 1050623 512.0 MiB EF00
2 1050624 2050047 488.0 MiB 8300
ESPと/bootが別だ。
mount
でも確認すると、
# mount | grep sd
/dev/sda2 on /boot type ext2 (rw,relatime,block_validity,barrier,user_xattr,acl)
/dev/sda1 on /boot/efi type vfat (rw,relatime,fmask=0077,dmask=0077,codepage=437,iocharset=iso8859-1,shortname=mixed,errors=remount-ro)
ESPはvfat、/bootはext2だ。
これらがsdbにも無いと、2台目で起動できない。
また、これらはLVMの外なので、ミラーされない。
パーティション情報と中身の両方を、手動でコピーする必要がある?
GPTのコピー
こちらに、sgdisk
を使ったパーティションテーブルのコピー例がある。
sfdisk
の例も見かけるが、sfdisk
はMBR用の模様。GPT用はsgdisk
か。関連記事1 関連記事2
# sgdisk /dev/sda -R /dev/sdb
# sgdisk -G /dev/sdb
sgdisk -G
で、GUIDが再生成され、ユニークになる。
そうすると、efibootmgr -v
で表示されるGUIDも、1台目と2台目で別のものになり、わかりやすい。
ESPのコピー
こちらでは、dd
でESPをコピーしている。やはりESPは手動でコピーする必要があるということか。
上記の通りUbuntuでは/bootはESPと別パーティションなので、/bootもコピーする必要がある。
grubやカーネルのアップデート時に自動でコピーすることもできると思うが、アップデート回数はそんなに多くないだろうから、手動でもいいか。
# dd if=/dev/sda1 of=/dev/sdb1
# dd if=/dev/sda2 of=/dev/sdb2
fstabによるESPと/bootのmount
ESPと/bootはfstab
で自動的にmountされるが、これだと、1台目か2台目のどちらかしかmountできないことになる。
つまり、1台目と2台目の両方で起動できるようにできない? 詰んだかも…。
そこで、試しにfstab
からESPと/bootのエントリーを削除してみると、普通に起動できた。
起動時は、UEFIのNVRAMやgrub.cfg
でパーティションなどを指定しているので、fstab
にエントリーが無くても起動できるのは、理論的には当然か。
fstab
に記載してmountするのは、起動後にアップデートできるようにするため?
こちらの似た例では、fstab
でUUIDの代わりにPARTUUIDを指定しつつ、2台目を/boot/esp2
にmountしている。何で?
UUIDとPARTUUID
fstabに書かれているUUIDは、gdisk
のDisk identifier (GUID)
にもPartition GUID code
にもPartition unique GUID
にも出て来ない。何を指定しているの? 関連記事
こちらによると、blkid
に出てくるUUIDとのこと。そこでblkid
を実行してみる。
$ blkid | grep sd[ab][12]
/dev/sda1: UUID="0088-9E70" TYPE="vfat" PARTUUID="25a2fe63-0350-442c-a32e-7e393862c81e"
/dev/sda2: UUID="cc044c77-ec4b-4a4f-94db-7718e1afc315" TYPE="ext2" PARTUUID="7b3f10af-13a1-46ad-bb1b-5f8b0bffef9f"
/dev/sdb1: UUID="0088-9E70" TYPE="vfat" PARTUUID="69a02c5e-3042-409a-b323-f570e7c8f1e2"
/dev/sdb2: UUID="cc044c77-ec4b-4a4f-94db-7718e1afc315" TYPE="ext2" PARTUUID="c28968f1-4b66-411d-be4b-d7d91453bdac"
sdaとsdbでUUIDがまるっきり同じだ。sgdisk -G
でGUIDを再生成しているのに…。
つまり、dd
でコピーしているパーティションの中身に、UUIDが入っているということか。
実際、こちらでは、バイナリエディタでESPのUUIDを書き換えている。すごい。
fstab
でPARTUUIDを指定すれば、UUIDはdd
のコピーのままにしても、マウント元を一意に指定できるので、1台目と2台目をそれぞれmountできる。
しかし、ESPと/bootのアップデート時にdd
でコピーするなら、2台目のESPと/bootをmountしておいたところで、unmountしてからコピーすることになる。
そこで、fstab
では、1台目をmountすること明確にするためにPARTUUIDで指定しつつ、2台目のESPと/bootのエントリーは記載せず、mountしないでおくことにする。
UUIDが重複すると、/dev/disk/by-uuid/
に片方のディスクしか出て来ないようで、不安だが…。
grub.cfg
ESPも/bootもdd
でコピーすると、中にあるgrub.cfg
もコピーされるはず。
すると、grub.conf
の中身によっては、コピーでは2台目で起動できない可能性に気づく。
/boot/grub/grub.cfg
を確認すると、hd0
という指定やUUIDが書いてある。
search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 cc044c77-ec4b-4a4f-94db-7718e1afc315
2台目にhd0と書いてあると、1台目が無い時に、2台目で起動できない。
hd1
に修正しようと思ったが、ご丁寧にファイルの先頭にDO NOT EDIT THIS FILE
と書かれている。
こちらではgrub-install
で2台目にgrubをインストールしているが、grub自体はdd
でコピーしているので、こちらにあるようなupdate-grub
によるgrub.cfg
の更新で済みそうだ。
man update-grub
によると、コマンドラインオプションで場所は指定できないので、2台目を/boot
と/boot/esp
にmountし直してから、実行する。
# umount /boot/efi
# umount /boot
# mount /dev/sdb2 /boot
# mount /dev/sdb1 /boot/efi
# update-grub
2つのgrub.cfg
2台目でupdate-grub
後、1台目の/boot/grub/grub.cfg
を比較すると、
67c67
< set root='hd0,gpt2'
---
> set root='hd1,gpt2'
69c69
< search --no-floppy --fs-uuid --set=root --hint-bios=hd0,gpt2 --hint-efi=hd0,gpt2 --hint-baremetal=ahci0,gpt2 cc044c77-ec4b-4a4f-94db-7718e1afc315
---
> search --no-floppy --fs-uuid --set=root --hint-bios=hd1,gpt2 --hint-efi=hd1,gpt2 --hint-baremetal=ahci1,gpt2 cc044c77-ec4b-4a4f-94db-7718e1afc315
(以下略)
hd0
がhd1
になっている。いい感じ。
cc044c77
のUUIDは、/bootをdd
でコピーしているので、同じままでいいはず。
ただ、よく調べると、ESPにも/boot/efi/EFI/ubuntu/grub.cfg
というファイルがある。
search.fs_uuid cc044c77-ec4b-4a4f-94db-7718e1afc315 root hd0,gpt2
set prefix=($root)'/grub'
configfile $prefix/grub.cfg
ここにもhd0
があり、これは/bootを指定しているようだが、update-grub
でもhd1
にはならなかった。
詳細未調査だが、2台目のESPの/boot/efi/EFI/ubuntu/grub.cfg
は、手動でhd1
に変更。
# sed -i -e "s/hd0/hd1/g" /boot/efi/EFI/ubuntu/grub.cfg
2つのswap
swapをミラーしないことにしたので、2台目のswapは手動で作る必要がある。
LVMのVGにswapのLVを作ればよいので、これは簡単。
# lvcreate -L 2GiB -n swap_2 hoge-vg /dev/sdb3
# mkswap /dev/hoge-vg/swap_2
ただ、2つ作ったswapをfstab
に書いたとして、1つがダメだったら、起動しなくなってしまうのでは?
実験1: fstab
で指定したLVはあるが、mkswap
されていない状態で起動
起動時に一瞬エラーが表示されるが、そのまま起動した。
swapon
で確認しても、片方だけがswapとして利用されていた。
実験2: fstab
で指定したLVが無い状態で起動
90秒待った後、Welcome to maintenance mode!
で、起動せず。画面例
ESPも/bootも、パーティションが存在せずにmountできないと、同じように起動しなかった。
片方のディスクが死んで取り外したら、起動しないことになる…。
fstab
のオプション
パーティションが無くても起動するfstab
オプションを探すために、man mount
を見る。
唯一それっぽかったのが、nofail
。
Do not report errors for this device if it does not exist.
fstab
の/boot
, /boot/efi
, /dev/mapper/hoge--vg-swap_1
, /dev/mapper/hoge--vg-swap_2
の<options>
にnofail
を付けたら、片方のディスクのパーティションが無くても起動した。関連記事
脱線: swap priority
今回の自分の環境では、性能の異なるディスク間でのミラーとなる。
こちらによると、swapには優先度が付けられる。
fstab
の編集ついでにやってみよう。
ようやく手順
Ubuntu Server 16.04のインストール
省略。
LVMのLVのサイズを、0.1MB小さくしてみた。
パーティションテーブルのコピー
# sgdisk /dev/sda -R /dev/sdb
# sgdisk -G /dev/sdb
# gdisk /dev/sdb
pとiでパーティション状態とGUIDを確認
# partprobe
partprobe
で、コピー後のパーティションテーブルを、カーネルに読み込ませる。
ESPと/bootをコピー
# dd if=/dev/sda1 of=/dev/sdb1
# dd if=/dev/sda2 of=/dev/sdb2
2つ目のgrub.cfg
修正
# umount /boot/efi
# umount /boot
# mount /dev/sdb2 /boot
# mount /dev/sdb1 /boot/efi
# update-grub
# sed -i -e "s/hd0/hd1/g" /boot/efi/EFI/ubuntu/grub.cfg
2台目のESPをUEFIに登録
# efibootmgr -c -d /dev/sdb -p 1 -l '\EFI\ubuntu\shimx64.efi' -L 'ubuntu2'
(以下抜粋)
BootCurrent: 0005
BootOrder: 0007,0005,0001,0002,0003,0004,0000,0006
Boot0005* ubuntu
Boot0007* ubuntu2
次の起動時は、BootOrder
上、2台目(0007
)から起動される。
LVMのPVとVGの準備
# pvcreate /dev/sdb3
# pvdisplay
# vgextend hoge-vg /dev/sdb3
# vgdisplay
VG Size
とFree PE
が増えていることを確認。
LVをミラー化
# lvconvert -m 1 /dev/hoge-vg/root /dev/sdb3
# lvs -a -o +devices
--alloc anywhere
しなくても、2台でできるようだ。
[root_rmeta_0] hoge-vg ewi-aor--- 4.00m /dev/sda3(50925)
[root_rmeta_1] hoge-vg ewi-aor--- 4.00m /dev/sdb3(0)
Cpy%Sync
がじわじわ増えて行く。
sdbにswapを作成
# lvcreate -l 511 -n swap_2 hoge-vg /dev/sdb3
# lvdisplay
# mkswap /dev/hoge-vg/swap_2
# echo '/dev/mapper/hoge--vg-swap_2 none swap sw 0 0' >> /etc/fstab
# swapon -a
# swapon
lvdisplay
で確認した時のswap_1
のCurrent LE
が、512ではなく511だったので、swap_2は、サイズ指定ではなくextent数指定でlvcreate
してみた。
fstab
の<options>
にpri=100
などを付けると、優先順位が付き、swapon
でも確認できる。
fstabのPARTUUID化とnofail追加
# blkid
(PARTUUIDを確認)
# vi /etc/fstab
(ESPと/bootをPARTUUID指定に置き換え、swapも含め<options>にnofailを追加)
再起動
# reboot
:(再起動)
# efibootmgr -v
# efibootmgr -o 0005,0007,0001,0002,0003,0004,0000,0006
BootCurrent: 0007
BootOrder: 0005,0007,0001,0002,0003,0004,0000,000
(後略)
2台目で起動した。(BootCurrent: 0007
)
efibootmgr -o
で起動順を1台目に戻し、さらに再起動。
感想
- 結局mdadmと同じくらいの手間になった気がする…(無事フラグ回収)
- LVMはまだ使われそうというニュースもあるし、勉強になった
- UEFIとRAID1の相性悪し
This is arguably a mis-design in the UEFI specification
- みなさん…本当にこんなこと…してるんでしょうか…
聞こえた囁き
- BIOS…ESPから解放
- mdadm…情報多い
- ハードウェアRAID…お金で解決
- CentOS…インストーラーが楽?
- Btrfs…統一的管理の夢
宿題
(おまけ)戻す時
# swapoff -a
# vi /etc/fstab
swap_2を削除
# swapon -a
# lvremove /dev/hoge-vg/swap_2
# lvconvert -m 0 /dev/hoge-vg/root
# vgreduce hoge-vg /dev/sdb3
# pvremove /dev/sdb3
# efibootmgr -B -b 7
UEFIのNVRAMから2台目のエントリーを削除
# gdisk /dev/sdb
dで/bootとESPを削除
# partprobe
Ubuntu Server 20.04での確認 (2021年4月追記)
基本的に今までの方法が使えた。
差分は2点。
- /etc/fstabでの/boot/efiのマウントに、デフォルトでは/dev/disk/by-uuid/を使用していた
- -> /dev/disk/by-partuuid/を使用するように変えて、動作した
- GPTでLVMパーティションのType Codeが8E00ではなく8300になっている(バグ?)
- -> gdiskを使って手動で直した