本記事には広告(アフィリエイトリンク)が含まれます。

LVM入門 論理ボリューム作成と拡張

Linuxエンジニア養成講座 第25回|全36回・フェーズ3「ネットワークとインフラ基盤」の10回目(10/12回目)です。
前回まで: 第16回でTCP/IPの基礎、第17回でnmcliによるIP設定と疎通確認、第18回でプロキシ・DNS・NTPのクライアント設定、第19回でパッケージ管理、第20回でfirewalldによる通信制御、第21回第22回で発展トピック(ボンディング・VLAN)、第23回でログ管理、第24回でcron / systemd timerを学びました。
今回学ぶこと: LVM(論理ボリュームマネージャ)を使ったストレージ管理を学びます。

前回の予告で「fdisk でディスクにパーティションを作成し、LVM で柔軟にストレージを管理する方法を学びます」とお伝えしました。今回は fdisk でディスクの状態を確認した上で、パーティションを作成せずにディスク全体を直接 LVM に登録する方式で、構成から拡張まで一連の操作を体験します。

この記事を読み終えると、以下のことができるようになります。

  • LVM の3層構造(PV → VG → LV)の役割と関係を説明できる
  • pvcreate / vgcreate / lvcreate で論理ボリュームを作成し、mkfs.xfs でフォーマットしてマウントできる
  • lvextend と xfs_growfs を組み合わせて、論理ボリュームとファイルシステムの両方を拡張できる
  • lsblk / pvs / vgs / lvs を使って現在のストレージ構成を把握できる
  • LVM のクリーンアップ(lvremove → vgremove → pvremove)の手順を説明できる

なぜ LVM が必要か

ストレージ管理の話に入る前に、「パーティション」という用語を押さえておきます。パーティションとは、1台の物理ディスクを論理的に区切った領域のことです。第6回で lsblk を使ったとき、sda1(/boot/efi)や sda2(/boot)が表示されていたことを覚えているでしょうか。あれが「sda というディスクをパーティションで区切った結果」です。

従来のパーティション管理には大きな問題があります。パーティションのサイズは作成時に決まり、後から拡張するのが困難です。ディスクの空き領域が隣接していなければ拡張できず、最悪の場合はバックアップ → パーティション再作成 → リストアが必要になります。本番サーバーで「/var が 100% になった」という状況を想像してみてください。サービスを止めてパーティションをやり直す — そんな対応は現実的ではありません。

LVM(Logical Volume Manager)は、この問題を解決する仕組みです。LVM を使えば、複数の物理ディスクをまとめて1つのプールとして扱い、そこから必要なサイズの論理ボリュームを切り出せます。容量が足りなくなったら、サービスを動かしたまま論理ボリュームを拡張できます。

現場では、第32回で学ぶ監視ツールが「ディスク使用率 90% 超過」のアラートを上げ、それを受けてインフラエンジニアが LVM の拡張コマンドを実行する — という流れが日常的に発生します。LVM はインフラエンジニアにとって必須のスキルです。

LVM の3層構造

LVM は次の3つの層で構成されています。下から順に積み上がるイメージです。

名前略称役割
1(最下層)物理ボリュームPV物理ディスクやパーティションを LVM で使えるように登録する
2(中間層)ボリュームグループVG複数の PV をまとめて1つの「ディスクプール」にする
3(最上層)論理ボリュームLVVG から必要なサイズを切り出した領域。ファイルシステムを作成してマウントする対象

言葉だけではイメージしにくいので、検証環境の既存 LVM 構成を見てみます。alma-main の OS はインストール時から LVM で管理されています。

具体的には、物理ディスク sda の3番目のパーティション sda3 が PV として登録され、「almalinux」という VG にまとめられ、そこから root(/)、swap、home(/home)の3つの LV が切り出されています。この構造を lsblk の出力から読み取れるようになるのが、この節のゴールです。

現在のディスク構成を確認する

ここから実機で操作していきます。alma-main に SSH で接続してください。

lsblk で全体を把握する

まず lsblk でディスクの全体像を確認します。alma-mainで実行してください。

実行コマンド:

$ lsblk

実行結果:

NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda                  8:0    0  100G  0 disk
├─sda1               8:1    0  600M  0 part /boot/efi
├─sda2               8:2    0    1G  0 part /boot
└─sda3               8:3    0 98.4G  0 part
  ├─almalinux-root 253:0    0 63.5G  0 lvm  /
  ├─almalinux-swap 253:1    0  3.9G  0 lvm  [SWAP]
  └─almalinux-home 253:2    0   31G  0 lvm  /home
sdb                  8:16   0   10G  0 disk
sdc                  8:32   0   10G  0 disk
sr0                 11:0    1 1024M  0 rom  

出力を読み解きます。

  • sda(100GB) — OS 用ディスク。sda1(/boot/efi)、sda2(/boot)、sda3(98.4GB)の3つのパーティションに分かれている
  • sda3 の配下 — TYPE 列が「lvm」になっている行が3つある。これが LVM の論理ボリューム。sda3 → almalinux VG → root/swap/home LV という3層構造になっている
  • sdb(10GB) — 検証用ディスク。配下にパーティションが表示されていない = 空のディスク
  • sdc(10GB) — 検証用ディスク。同じく空
  • sr0 — CD/DVD ドライブ(仮想)。今回は使わない

sdb と sdc が空であることを確認できました。今回はこの2台の検証用ディスクを使って LVM を構成します。

LVMの3層構造。物理ディスクsdb(10GB)とsdc(10GB)をPVとして登録し、datavgというVG(約20GB)にまとめる。そのVGからdatalv(5GB)を切り出し、残り約15GBは空き領域として追加のLV作成や既存LVの拡張に使える

fdisk でディスクの詳細を確認する

sdb が本当に未フォーマットかどうか、fdisk -l で確認してみます。

実行コマンド:

$ sudo fdisk -l /dev/sdb

実行結果:

ディスク /dev/sdb: 10 GiB, 10737418240 バイト, 20971520 セクタ
ディスク型式: Virtual Disk
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 4096 バイト
I/O サイズ (最小 / 推奨): 4096 バイト / 4096 バイト

ディスクのサイズやセクタ情報は表示されますが、パーティションテーブルの情報がありません。これは sdb がまだパーティションも作成されていない空のディスクであることを意味します。LVM では、パーティションを作成せずにディスク全体を直接 PV として登録することもできます。今回はその方式で進めます。

既存の LVM 構成を確認する

LVM の状態を確認する専用コマンドが用意されています。pvs(PV の一覧)、vgs(VG の一覧)、lvs(LV の一覧)の3つです。

実行コマンド:

$ sudo pvs

実行結果:

  PV         VG        Fmt  Attr PSize  PFree
  /dev/sda3  almalinux lvm2 a--  98.41g    0 

PV は /dev/sda3 が1つだけ登録されており、almalinux という VG に所属しています。PFree が 0 なので、この VG の空き容量はありません(全容量が LV に割り当て済み)。

実行コマンド:

$ sudo vgs

実行結果:

  VG        #PV #LV #SN Attr   VSize  VFree
  almalinux   1   3   0 wz--n- 98.41g    0 

#PV=1(PV が1つ)、#LV=3(LV が3つ)、VFree=0(空き容量なし)です。

実行コマンド:

$ sudo lvs

実行結果:

  LV   VG        Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  home almalinux -wi-ao---- 30.99g
  root almalinux -wi-ao---- 63.47g
  swap almalinux -wi-ao---- <3.95g                                                    

root(63.47GB)、home(30.99GB)、swap(3.95GB)の3つの LV が almalinux VG に存在しています。lsblk で見た almalinux-root、almalinux-swap、almalinux-home と対応していることが分かります。

LVM 関連のコマンドは多いですが、すべて暗記する必要はありません。man lvm を実行すると、LVM コマンドの一覧と概要が確認できます。

LVM を構成する

ここからが本題です。空の sdb と sdc を使って、新しい LVM 構成を作っていきます。手順は「PV 作成 → VG 作成 → LV 作成 → ファイルシステム作成 → マウント」の順です。3層構造を下から積み上げるイメージで進めます。

手順1: PV を作成する

pvcreate コマンドで、sdb と sdc を PV(物理ボリューム)として LVM に登録します。alma-mainで実行してください。

実行コマンド:

$ sudo pvcreate /dev/sdb

実行結果:

  Physical volume "/dev/sdb" successfully created.

実行コマンド:

$ sudo pvcreate /dev/sdc

実行結果:

  Physical volume "/dev/sdc" successfully created.

pvs で確認します。

実行コマンド:

$ sudo pvs

実行結果:

  PV         VG        Fmt  Attr PSize  PFree
  /dev/sda3  almalinux lvm2 a--  98.41g     0
  /dev/sdb             lvm2 ---  10.00g 10.00g
  /dev/sdc             lvm2 ---  10.00g 10.00g

sdb と sdc が PV として登録されました。VG 列が空欄なのは、まだどの VG にも所属していないためです。PFree が 10.00g なので、各ディスクの全容量が使用可能な状態です。

手順2: VG を作成する

vgcreate コマンドで、sdb と sdc の2つの PV をまとめて「datavg」という名前の VG を作成します。

実行コマンド:

$ sudo vgcreate datavg /dev/sdb /dev/sdc

実行結果:

  Volume group "datavg" successfully created

vgs で確認します。

実行コマンド:

$ sudo vgs

実行結果:

  VG        #PV #LV #SN Attr   VSize  VFree
  almalinux   1   3   0 wz--n- 98.41g     0
  datavg      2   0   0 wz--n- 19.99g 19.99g

datavg が作成されました。#PV=2(sdb と sdc の2つ)、VSize=19.99g(10GB × 2 から管理領域を引いた値)、VFree=19.99g(まだ LV を切り出していないので全容量が空き)です。2台の物理ディスクが1つのプールにまとまったことが確認できます。

手順3: LV を作成する

lvcreate コマンドで、datavg から 5GB の論理ボリューム「datalv」を切り出します。-n でLV名、-L でサイズを指定します。

実行コマンド:

$ sudo lvcreate -n datalv -L 5G datavg

実行結果:

  Logical volume "datalv" created.

lvs で確認します。

実行コマンド:

$ sudo lvs

実行結果:

  LV     VG        Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  home   almalinux -wi-ao---- 30.99g
  root   almalinux -wi-ao---- 63.47g
  swap   almalinux -wi-ao---- <3.95g
  datalv datavg    -wi-a-----  5.00g                                                    

datalv が datavg に 5.00GB で作成されました。VG の合計約 20GB のうち、5GB だけを切り出した状態です。残りの約 15GB は将来の拡張に使えます。これが LVM の柔軟性です。

各コマンドのオプション詳細は man pvcreate、man lvcreate で確認できます。

手順4: ファイルシステムを作成する

LV はまだ「空の箱」の状態です。ファイルを保存するには、ファイルシステムを作成する必要があります。AlmaLinux 9 の標準ファイルシステムである XFS でフォーマットします。

実行コマンド:

$ sudo mkfs.xfs /dev/datavg/datalv

実行結果:

meta-data=/dev/datavg/datalv     isize=512    agcount=4, agsize=327680 blks
         =                       sectsz=4096  attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1    bigtime=1 inobtcount=1 nrext64=0
data     =                       bsize=4096   blocks=1310720, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=16384, version=2
         =                       sectsz=4096  sunit=1 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
Discarding blocks...Done.

LV のデバイスパスは /dev/VG名/LV名 の形式で指定します。今回は /dev/datavg/datalv です。mkfs.xfs の出力には XFS の内部構造に関する詳細が表示されますが、すべてを理解する必要はありません。「Discarding blocks…Done.」が表示されればフォーマット完了です。

手順5: マウントする

マウントポイント(ファイルシステムをアクセスするためのディレクトリ)を作成し、マウントします。第6回で学んだ mount コマンドの実践です。

実行コマンド:

$ sudo mkdir -p /data

実行コマンド:

$ sudo mount /dev/datavg/datalv /data

df -h でマウントされたことを確認します。

実行コマンド:

$ df -h /data

実行結果:

ファイルシス              サイズ  使用  残り 使用% マウント位置
/dev/mapper/datavg-datalv   5.0G   68M  4.9G    2% /data

5.0GB のファイルシステムが /data にマウントされています。使用 68MB はファイルシステム自体の管理領域です。

なお、今回は /etc/fstab への追記は行いません。通常の運用では /etc/fstab にマウント情報を記載して再起動後も自動マウントされるようにしますが、今回は演習後にスナップショット(SP5)へ復元するため、永続化は不要です。

手順6: lsblk で全体を確認する

最後に lsblk で全体像を確認します。

実行コマンド:

$ lsblk

実行結果:

NAME               MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
sda                  8:0    0  100G  0 disk
├─sda1               8:1    0  600M  0 part /boot/efi
├─sda2               8:2    0    1G  0 part /boot
└─sda3               8:3    0 98.4G  0 part
  ├─almalinux-root 253:0    0 63.5G  0 lvm  /
  ├─almalinux-swap 253:1    0  3.9G  0 lvm  [SWAP]
  └─almalinux-home 253:2    0   31G  0 lvm  /home
sdb                  8:16   0   10G  0 disk
└─datavg-datalv    253:3    0    5G  0 lvm  /data
sdc                  8:32   0   10G  0 disk
sr0                 11:0    1 1024M  0 rom  

sdb の配下に datavg-datalv(5GB、/data にマウント)が表示されています。sdc にも datavg の一部として領域が割り当て可能ですが、現時点では 5GB しか使っていないため sdb 側のみに表示されています。

ここまでの操作で、PV → VG → LV → ファイルシステム → マウントという一連の流れが完了しました。

LV を拡張する

LVM の真価は「後からサイズを変更できる」ことにあります。5GB の datalv を 8GB に拡張してみます。ただし、拡張は「LV(ブロックデバイス)の拡張」と「ファイルシステムの拡張」の2段階が必要です。

LVの拡張は2段階。まずlvextendでLV(ブロックデバイス)を5GBから8GBに拡張し、次にxfs_growfsでファイルシステムを8GBに拡張する。lvextendだけではファイルシステムは5GBのままで、df -hで確認すると容量が増えていない

lvextend でブロックデバイスを拡張する

lvextend コマンドで LV のサイズを拡張します。-L オプションには「+3G」のように相対値で増分を指定する方法と、「8G」のように絶対値で最終サイズを指定する方法の2つがあります。現場では「あと何GB足りない」という状況が多いため、相対指定のほうが直感的です。

実行コマンド:

$ sudo lvextend -L +3G /dev/datavg/datalv

実行結果:

  Size of logical volume datavg/datalv changed from 5.00 GiB (1280 extents) to 8.00 GiB (2048 extents).
  Logical volume datavg/datalv successfully resized.

5GB → 8GB に拡張されたと表示されています。lvs で確認します。

実行コマンド:

$ sudo lvs

実行結果(datalv 行のみ抜粋):

  datalv datavg    -wi-ao----  8.00g

LV は 8GB になりました。では df -h で確認してみます。

実行コマンド:

$ df -h /data

実行結果:

ファイルシス              サイズ  使用  残り 使用% マウント位置
/dev/mapper/datavg-datalv   5.0G   68M  4.9G    2% /data

サイズがまだ 5.0GB のままです。これはバグではありません。lvextend が拡張したのは「ブロックデバイス」(LV)のサイズであり、その上に載っている「ファイルシステム」(XFS)はまだ旧サイズのままだからです。

xfs_growfs でファイルシステムを拡張する

XFS ファイルシステムを拡張するには xfs_growfs コマンドを使います。引数にはマウントポイントを指定します。

実行コマンド:

$ sudo xfs_growfs /data

実行結果:

meta-data=/dev/mapper/datavg-datalv isize=512    agcount=4, agsize=327680 blks
         =                       sectsz=4096  attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=1, rmapbt=0
         =                       reflink=1    bigtime=1 inobtcount=1 nrext64=0
data     =                       bsize=4096   blocks=1310720, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0, ftype=1
log      =internal log           bsize=4096   blocks=16384, version=2
         =                       sectsz=4096  sunit=1 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 1310720 to 2097152

最終行の「data blocks changed from 1310720 to 2097152」がポイントです。ブロック数が増えた = ファイルシステムが拡張されたことを意味します。df -h で改めて確認します。

実行コマンド:

$ df -h /data

実行結果:

ファイルシス              サイズ  使用  残り 使用% マウント位置
/dev/mapper/datavg-datalv   8.0G   90M  7.9G    2% /data

8.0GB に拡張されました。LV の拡張は「lvextend でブロックデバイスを広げる → xfs_growfs でファイルシステムを広げる」の2段階の操作が必要です。

ヒヤリハット: lvextend だけで終わりにしてしまう

「LV を拡張したのに、df -h でサイズが変わらない」 — これは現場でもよく起きるミスです。lvextend を実行して「successfully resized」と表示されると、つい「完了した」と思ってしまいます。しかし、ファイルシステムの拡張(xfs_growfs や resize2fs)を忘れると、ブロックデバイスは広がっているのにファイルシステムが旧サイズのまま、という状態になります。

先輩エンジニアに「拡張したのに容量が増えません」と報告して、「xfs_growfs は打った?」と聞かれる — 新人が通る道です。LV の拡張は常に2段階、と覚えておいてください。

やってみよう

ここまでの手順を理解できたか、一人で最初からやり直して確認してみてください。

課題: LVM の構成から拡張・クリーンアップまでを一人で完了する

以下の流れを、記事を見返さずに実行してみてください。途中で詰まったら該当のセクションを確認して構いません。

  1. まず、次のセクション「LVM をクリーンアップする」の手順に従って、現在の LVM 構成を削除する
  2. pvs / vgs / lvs / lsblk で sdb/sdc が空に戻ったことを確認する
  3. sdb と sdc を PV として登録する
  4. 2つの PV をまとめて datavg(VG)を作成する
  5. datavg から 5GB の datalv(LV)を作成する
  6. XFS でフォーマットし、/data にマウントする
  7. df -h で 5GB であることを確認する
  8. lvextend で +5G 拡張し、10GB にする
  9. df -h で「まだ 5GB」であることを確認する(ここが重要)
  10. xfs_growfs でファイルシステムを拡張する
  11. df -h で 10GB になったことを確認する
  12. クリーンアップ(umount → lvremove → vgremove → pvremove)を行う

手順 8 と 9 の間で「まだ 5GB のまま」であることを自分の目で確認するのがこの演習のポイントです。lvextend と xfs_growfs が別の操作であることを体で覚えてください。

LVM をクリーンアップする

演習が終わったら、LVM 構成を削除して sdb/sdc を元の空の状態に戻します。削除は作成と逆の順序(上の層から順に)で行います。alma-mainで実行してください。

実行コマンド:

$ sudo umount /data

実行コマンド:

$ sudo lvremove -f /dev/datavg/datalv

実行結果:

  Logical volume "datalv" successfully removed.

実行コマンド:

$ sudo vgremove datavg

実行結果:

  Volume group "datavg" successfully removed

実行コマンド:

$ sudo pvremove /dev/sdb /dev/sdc

実行結果:

  Labels on physical volume "/dev/sdb" successfully wiped.
  Labels on physical volume "/dev/sdc" successfully wiped.

pvs で PV が OS 用の sda3 だけに戻ったことを確認します。

実行コマンド:

$ sudo pvs

実行結果:

  PV         VG        Fmt  Attr PSize  PFree
  /dev/sda3  almalinux lvm2 a--  98.41g    0 

sdb/sdc が元の状態に戻りました。クリーンアップの順序は「umount → lvremove → vgremove → pvremove」です。作成の逆順と覚えてください。

クリーンアップが完了したら、スナップショット SP5 に復元して VM を演習前の状態に戻してください。ホストPCで実行してください。

実行コマンド:

PS> Stop-VM -Name 'alma-main' -Force
PS> Restore-VMSnapshot -VMName 'alma-main' -Name 'SP5_pre-storage' -Confirm:$false
PS> Start-VM -Name 'alma-main'

まとめと次回予告

今回のポイントを3つにまとめます。

  • LVM は PV → VG → LV の3層構造で、物理ディスクをまたいだ柔軟なストレージ管理を実現する。 pvcreate → vgcreate → lvcreate の順で構成し、削除は逆順(lvremove → vgremove → pvremove)で行う
  • LV の拡張は「lvextend + xfs_growfs」の2段階。 lvextend だけではファイルシステムのサイズは変わらない。xfs_growfs(またはext4ならresize2fs)でファイルシステム側も拡張する必要がある
  • pvs / vgs / lvs / lsblk で現在の LVM 構成を把握する。 ストレージのトラブル対応は「まず現状を正確に把握する」ことから始まる

次回の第26回「シェルスクリプト実践」では、フェーズ3のまとめ演習を兼ねて、ネットワーク疎通チェックやログ解析、ディスク使用率チェックなどをシェルスクリプトで自動化します。今回学んだ df コマンドの出力をスクリプトで解析する場面も登場します。

理解度チェック

以下の文が正しければ ○、誤りであれば × を答えてください。

Q1. LVM の3層構造は、下から順に PV(物理ボリューム)→ VG(ボリュームグループ)→ LV(論理ボリューム)である。

Q2. 1つの VG には1つの PV しか登録できない。

Q3. lvcreate で作成した LV は、mkfs でファイルシステムを作成しなくてもすぐにファイルを保存できる。

Q4. lvextend -L +3G は「現在のサイズに 3GB を追加する」という意味である。

Q5. lvextend で LV を拡張すれば、ファイルシステムのサイズも自動的に拡張される。

Q6. LVM の削除は、作成と同じ順序(pvremove → vgremove → lvremove)で行う。

以下、解答です。

Q1. ○ — PV が最下層、VG が中間層、LV が最上層です。物理ディスクを PV として登録し、PV をまとめて VG を作り、VG から LV を切り出します。

Q2. × — 1つの VG に複数の PV を登録できます。今回の演習でも sdb と sdc の2つの PV を datavg にまとめました。これが LVM の「複数ディスクをプール化する」利点です。

Q3. × — LV はブロックデバイスであり、ファイルを保存するにはファイルシステム(XFS や ext4 など)を作成する必要があります。mkfs.xfs 等でフォーマットしてからマウントします。

Q4. ○ — -L +3G は相対指定で、現在のサイズに 3GB を加算します。-L 8G のように + を付けない場合は、最終サイズを絶対値で指定する意味になります。

Q5. × — lvextend はブロックデバイス(LV)のサイズを拡張するだけです。ファイルシステムは別途 xfs_growfs(XFS の場合)や resize2fs(ext4 の場合)で拡張する必要があります。

Q6. × — 削除は作成の逆順で行います。正しい順序は lvremove → vgremove → pvremove です。上の層(LV)から順に削除しないと、下の層(VG や PV)が使用中のため削除できません。

シリーズ一覧

フェーズ1: エンジニアのいろは(第1回〜第3回)

フェーズ2: Linux基礎(第4回〜第15回)

フェーズ3: ネットワークとインフラ基盤(第16回〜第27回)

フェーズ4: サーバー構築と運用(第28回〜第36回)