LoginSignup
5
5

More than 3 years have passed since last update.

Ubuntu Server 16.04+UEFI+GPT+LVMで、ソフトウェアRAID1する

Last updated at Posted at 2017-12-28

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をミラーするかどうかも、議論がある。

  • こちらによると、意味はあまりない、とある
  • こちらArch Wikiでは、異常発生時のメリットが挙げられている

クリティカルな環境ではないので、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でパーティションを確認すると、

gdiskでpした結果(抜粋)
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は、gdiskDisk 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が書いてある。

/boot/grub/grub.cfg
  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
(以下略)

hd0hd1になっている。いい感じ。
cc044c77のUUIDは、/bootをddでコピーしているので、同じままでいいはず。

ただ、よく調べると、ESPにも/boot/efi/EFI/ubuntu/grub.cfgというファイルがある。

/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 SizeFree PEが増えていることを確認。

LVをミラー化

# lvconvert -m 1 /dev/hoge-vg/root /dev/sdb3
# lvs -a -o +devices

--alloc anywhereしなくても、2台でできるようだ。

lvsの結果(抜粋)
  [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_1Current 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…統一的管理の夢

宿題

  • grubとカーネルのアップデート時の、ESPと/bootの自動コピー
  • /bootのミラーリング
  • 性能測定

(おまけ)戻す時

# 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を使って手動で直した
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5