Linux の LVM:物理ボリューム、ボリュームグループ、論理ボリューム
LVM(Logical Volume Manager)は、ディスクとファイルシステムの間に入る Linux の層です。ディスクは物理ボリューム(PV)になり、ボリュームグループ(VG)にまとめられ、そこから任意のサイズの論理ボリューム(LV)が切り出されます。最大の利点は、lvextend -r でボリュームをその場で拡張できること、ディスクをサービスを止めずにグループに追加できること、そして危険な操作の前にスナップショットを作れることです。
LVM(Logical Volume Manager)は、ファイルシステムを物理ディスクから切り離す Linux のボリュームマネージャーです。/var を /dev/sdb1 というパーティションに固定する代わりに、ディスクを共通のプールにまとめ、必要なサイズのボリュームを切り出します。容量が足りなくなったら、1つのコマンドでボリュームを拡張できます。再起動もサービスの停止も必要ありません。ここでは、Linux の LVM の仕組み、ゼロからのボリューム作成、拡張、スナップショットの取得、よくあるミスでデータを失わない方法を説明します。
通常のパーティションに加えて LVM が必要な理由
通常のパーティションは、1つのディスク上の連続した領域です。サイズはパーティション作成時に決まり、拡張できるのは直後に空き領域がある場合だけです。ディスクがいっぱいになると、新しいディスクを用意し、データを移し、/etc/fstab を書き換え、その間サービスを止める必要があります。
LVM は次の3つの課題を解決します。
- 柔軟なサイズ。論理ボリュームは、いつでも拡張できます(ext4 なら縮小も可能)。
- ディスクの結合。複数の物理ディスクが1つのプールになり、1つのボリュームを2つのディスクにまたがらせることもできます。
- スナップショット。アップデート、データベースの移行、その他の危険な操作の前に、ボリュームの瞬間的なコピーを取れます。
そのため、Ubuntu Server、RHEL、Rocky、AlmaLinux のインストーラーは既定で LVM を提案します。データを扱うサーバーでは、ほぼ必ず LVM を使います。
LVM の3つの階層:PV、VG、LV
LVM の仕組みは3つの概念で理解できます。たとえると、ディスクは小麦粉の袋、ボリュームグループは共有の倉庫、論理ボリュームは倉庫から量って取り出す分量です。
| 階層 | 意味 | 名前の例 | 作成コマンド |
|---|---|---|---|
| PV(Physical Volume) | LVM 用に準備されたディスクまたはパーティション | /dev/sdb、/dev/sdc1 | pvcreate |
| VG(Volume Group) | 1つ以上の PV をまとめたプール | data_vg | vgcreate |
| LV(Logical Volume) | VG から切り出したボリューム。ファイルシステムを作る対象 | /dev/data_vg/app | lvcreate |
VG の中の領域は、エクステント(PE、physical extents)と呼ばれる固定サイズのブロックに分けられます。既定のサイズは 4 MiB です。論理ボリュームは、エクステントの集まりにすぎません。エクステントは連続している必要がなく、異なるディスクに置かれていてもかまいません。そのためボリュームを簡単に拡張できます。LVM はどこからでも空いているエクステントを追加できるからです。
論理ボリュームには、同じものを指す2つのパスがあります:/dev/data_vg/app と /dev/mapper/data_vg-app。内部では、カーネルの device-mapper デバイスです。
現在の状態を確認する
まず、パッケージがインストールされているか確認します。Debian と Ubuntu では lvm2(sudo apt install lvm2)です。RHEL 系では標準で入っています。概要を確認するには、短い形式と詳しい形式のコマンドがあります。
$ sudo pvs
PV VG Fmt Attr PSize PFree
/dev/sdb data_vg lvm2 a-- <20.00g 0
/dev/sdc data_vg lvm2 a-- <20.00g <10.00g
$ sudo vgs
VG #PV #LV #SN Attr VSize VFree
data_vg 2 1 0 wz--n- 39.99g <10.00g
$ sudo lvs
LV VG Attr LSize Pool Origin Data% Meta%
app data_vg -wi-ao---- 30.00g
詳細は pvdisplay、vgdisplay、lvdisplay で確認できます。通常のパーティションと合わせた全体像は lsblk で見られます。論理ボリュームは、タイプ lvm として表示されます。
$ lsblk /dev/sdb /dev/sdc
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb 8:16 0 20G 0 disk
└─data_vg-app 253:0 0 30G 0 lvm /srv/app
sdc 8:32 0 20G 0 disk
└─data_vg-app 253:0 0 30G 0 lvm /srv/app
この例では、30 GB のボリューム app が、20 GB の2つのディスクにまたがっています。通常のパーティションではこれはできません。
ゼロから LVM を作る:未使用のディスクからマウントまで
サーバーに空のディスク /dev/sdb を追加し、アプリケーションのデータ用に 15 GB のボリュームが必要だとします。lsblk でディスク名を2回確認してください。以下のコマンドはすべて、指定したデバイス上のデータを消去します。
手順 1:物理ボリュームを作成する
$ sudo pvcreate /dev/sdb
Physical volume "/dev/sdb" successfully created.
ディスク全体を LVM に渡すこともできますし、先に fdisk や parted で「Linux LVM」タイプのパーティションを作り(/dev/sdb1)、それを指定することもできます。パーティションを使うと、ほかの管理者にも分かりやすく、LVM の上に誤ってディスクを再パーティションしてしまうことも防げます。クラウドでディスク全体を拡張する場合は、ディスク全体の方が簡単です。
手順 2:ボリュームグループを作成する
$ sudo vgcreate data_vg /dev/sdb
Volume group "data_vg" successfully created
手順 3:論理ボリュームを切り出す
$ sudo lvcreate -n app -L 15G data_vg
Logical volume "app" created.
-L は絶対サイズを指定します。-l はエクステント数またはパーセントで指定します。-l 100%FREE はグループの空き領域すべてを使い、-l 50%VG はグループの半分を使います。VG に空きを残しておくのは良い習慣です。後でどのボリュームにも追加でき、スナップショットにも使えます。
手順 4:ファイルシステムを作成してマウントする
$ sudo mkfs.ext4 /dev/data_vg/app
$ sudo mkdir -p /srv/app
$ sudo mount /dev/data_vg/app /srv/app
$ df -h /srv/app
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/data_vg-app 15G 24K 14G 1% /srv/app
再起動後もボリュームをマウントするには、/etc/fstab に行を追加します。論理ボリュームでは /dev/mapper/... のパスは安定しているので、それを使うか、blkid の UUID を使えます。
/dev/mapper/data_vg-app /srv/app ext4 defaults 0 2
再起動の前に sudo mount -a で記述を確認してください。fstab に誤りがあると、サーバーが緊急モードで起動することがあります。
サービスを止めずに LVM ボリュームを拡張する
これが LVM を使う最大の理由です。ボリュームは、マウントされたファイルシステムのまま拡張でき、アプリケーションはデータを書き込み続けられます。手順はグループに空きがあるかどうかで変わります。
VG に空き領域がある場合
$ sudo vgs data_vg
VG #PV #LV #SN Attr VSize VFree
data_vg 1 1 0 wz--n- <20.00g <5.00g
$ sudo lvextend -r -L +4G /dev/data_vg/app
Size of logical volume data_vg/app changed from 15.00 GiB to 19.00 GiB.
Logical volume data_vg/app successfully resized.
resize2fs 1.47.0
Filesystem at /dev/mapper/data_vg-app is mounted on /srv/app; on-line resizing required
重要なオプションは -r(--resizefs)です。ボリュームを拡張した直後に、ファイルシステムも拡張します。これを付けないと、ボリュームは大きくなりますが、ファイルシステムは新しい領域を認識しないため、df -h は古いサイズを表示します。これは最もよくあるミスです。その場合は、ext4 なら resize2fs、XFS なら xfs_growfs を手動で実行します。
$ sudo resize2fs /dev/data_vg/app # ext4 はデバイス名を指定
$ sudo xfs_growfs /srv/app # XFS はマウントポイントを指定
違いに注意してください。-L +4G は 4 GB を追加し、-L 4G は最終的なサイズを 4 GB にします。残りの空き領域すべてを使うには -l +100%FREE を使います。
VG の空き領域がなくなった場合:ディスクを追加する
新しいディスクを接続し(クラウドならボリュームをアタッチし)、lsblk で見つけて、グループに追加します。
$ sudo pvcreate /dev/sdc
$ sudo vgextend data_vg /dev/sdc
Volume group "data_vg" successfully extended
$ sudo lvextend -r -l +100%FREE /dev/data_vg/app
3つのコマンドで、停止時間はゼロです。ファイルシステムは2つのディスクにまたがるようになりますが、アプリケーションはそれに気づきません。
クラウドでディスクを拡張した場合
クラウドでは、ディスクを追加するよりも既存のディスクを大きくする方が簡単なことがよくあります。その場合、カーネルは新しいデバイスサイズを認識しますが、物理ボリュームを pvresize で広げる必要があります。
$ sudo pvresize /dev/sdb
Physical volume "/dev/sdb" changed
$ sudo lvextend -r -l +100%FREE /dev/data_vg/app
PV がパーティション(/dev/sdb1)上にある場合は、まず cloud-guest-utils パッケージの growpart /dev/sdb 1 でパーティションを広げ、その後で pvresize /dev/sdb1 を実行します。
LVM ボリュームを縮小できるか
縮小はできますが、すべてのファイルシステムで可能というわけではなく、稼働中には行えません。XFS は縮小できません。データを移して作り直すしかありません。ext4 は縮小できますが、アンマウントした状態でなければなりません。
$ sudo umount /srv/app
$ sudo lvreduce -r -L 10G /dev/data_vg/app
-r を付けると、LVM がファイルシステムの検査(e2fsck)を行い、ボリュームを縮める前にファイルシステムを縮めます。-r がないと、ファイルシステムより小さくなるように切り詰めてしまい、データを壊すおそれがあります。縮小の前には必ずバックアップを取ってください。
LVM スナップショット:危険な操作の前にボリュームのコピーを取る
スナップショットは論理ボリュームの瞬間的なコピーです。数分の一秒で作成され、データはすぐにはコピーされません。LVM は copy-on-write の仕組みで動きます。元のボリュームの内容が作成後に変わったブロックだけを、スナップショットに保存します。そのため、スナップショットに必要な領域は、ボリューム全体ではなく変更分だけです。
$ sudo lvcreate -s -n app_before_upgrade -L 2G /dev/data_vg/app
Logical volume "app_before_upgrade" created.
$ sudo lvs data_vg
LV VG Attr LSize Origin Data%
app data_vg owi-aos--- 19.00g
app_before_upgrade data_vg swi-a-s--- 2.00g app 0.01
Data% 列は、変更を保存する領域がどれだけ埋まっているかを示します。100% に達すると、従来型のスナップショットは無効になり、削除するしかなくなります。想定される変更量に余裕を持ったサイズを選び、長期間保持するスナップショットは lvs で監視するか、lvextend で拡張してください。
スナップショットへのロールバック
アップデートがうまくいかなかった場合は、ボリュームをスナップショットの時点に戻します。
$ sudo umount /srv/app
$ sudo lvconvert --merge /dev/data_vg/app_before_upgrade
Merging of volume data_vg/app_before_upgrade started.
$ sudo mount /srv/app
マージが終わるとスナップショットは消えます。ボリュームをアンマウントできない場合(たとえばシステムのルートの場合)、マージは次回のボリューム有効化、つまり再起動まで保留されます。
うまくいった場合
スナップショットは、書き込みを遅くしたり領域を取り続けたりしないように削除します。
$ sudo lvremove /dev/data_vg/app_before_upgrade
稼働中のシステムの整合性のあるバックアップを取るために、スナップショットを読み取り専用でマウントしてコピーする方法も便利です。mount -o ro でマウントし、rsync や tar でコピーします。XFS の場合は、元のボリュームと UUID が一致してマウントが拒否されないように、nouuid オプションを追加してください。
LVM と RAID:役割を混同しない
LVM だけではディスク故障から守れません。1つのボリュームが2つのディスクにまたがっていて、そのうち1つが壊れると、ボリューム全体が失われます。半分だけ失われるわけではありません。障害への耐性が必要な場合は、LVM の下に RAID(mdadm)を置くか、LVM に組み込まれたミラーを使います(lvcreate --type raid1 -m 1)。
RAID もスナップショットも、バックアップの代わりにはなりません。スナップショットは元のボリュームと同じディスクにあり、RAID は誤って実行した rm -rf もそのままミラーしてしまいます。別の媒体に別のコピーが必要です。
LVM コマンドの早見表
| 作業 | コマンド |
|---|---|
| PV、VG、LV の概要 | pvs、vgs、lvs |
| 物理ボリュームの作成 | pvcreate /dev/sdb |
| グループの作成 | vgcreate data_vg /dev/sdb |
| グループへのディスク追加 | vgextend data_vg /dev/sdc |
| ボリュームの作成 | lvcreate -n app -L 15G data_vg |
| ボリュームとファイルシステムの拡張 | lvextend -r -L +5G /dev/data_vg/app |
| ディスク拡張後に PV を広げる | pvresize /dev/sdb |
| スナップショット | lvcreate -s -n snap -L 2G /dev/data_vg/app |
| スナップショットへのロールバック | lvconvert --merge /dev/data_vg/snap |
| グループからディスクを外す | pvmove /dev/sdb の後、vgreduce data_vg /dev/sdb |
| ボリュームの削除 | lvremove /dev/data_vg/app |
よくあるミス
- ボリュームを拡張したのに df のサイズが変わらない。
-rを忘れています。resize2fsまたはxfs_growfsを実行してください。 - Insufficient free space。グループに空きエクステントがありません。
vgsで確認し、vgextendでディスクを追加するか、PV を広げてください。 - Device /dev/sdc excluded by a filter。ディスクに古いパーティションテーブルやファイルシステムの署名が残っています。データが不要であることを確かめたうえで、
wipefs -a /dev/sdcで消去してください。 - スナップショットが Invalid になった。変更を保存する領域が 100% になりました。復旧はできず、削除して、次回はより大きな領域を割り当てるしかありません。
まとめ
Linux の LVM は3つの層です。物理ボリューム(PV)がボリュームグループ(VG)にまとめられ、そこから論理ボリューム(LV)が切り出されます。これにより、通常のパーティションにはない機能が得られます。lvextend -r によるその場での拡張、停止なしでのディスク追加、危険な変更の前のスナップショットです。ただし LVM は RAID やバックアップの代わりにはならないことを忘れないでください。ディスクのパーティション、LVM、RAID、クォータは、Linux コースの講義で実践しながら解説しています。
よくある質問
稼働中のデータパーティションを LVM に移行できますか?
直接はできません。pvcreate はデバイスの先頭を上書きします。別のディスクに LVM を作り、rsync でデータをコピーし、fstab を修正してから古いパーティションを解放してください。
LVM は性能を落としますか?
スナップショットを使わない場合、device-mapper のオーバーヘッドはほとんど感じられません。有効な従来型スナップショットは copy-on-write のために元のボリュームへの書き込みを遅くするので、何週間も保持しないでください。
家庭用のパソコンやノートパソコンにも LVM は必要ですか?
必須ではありませんが、LUKS でディスクを暗号化する場合(LVM の中に LUKS を置く構成)や、パーティションを再作成せずにサイズを変えたい場合には便利です。データを扱うサーバーでは、LVM がほぼ標準です。
LVM のシンプロビジョニングとは何ですか?
シンボリューム(thin volume)のことです。シンプールを作成(lvcreate --type thin-pool)すると、そのプール内のボリュームは、データを書き込んだ分だけ実際の領域を使います。物理的な容量より大きなボリュームを割り当てられますが、プールの使用率を監視する必要があります。
データを失わずにディスクをボリュームグループから外すには?
pvmove /dev/sdb でエクステントを同じグループの別のディスクに移します(十分な空き領域が必要です)。その後、vgreduce data_vg /dev/sdb と pvremove /dev/sdb を実行します。