CUBE SUGAR CONTAINER

技術系のこと書きます。

LVM (Logicl Volume Manager) を使ってみる

LVM (Logicl Volume Manager) はブロックデバイスを VG (Volume Group) という単位で束ねた上で、そこから LV (Logical Volume) という論理的なボリュームで切り出して使うことで柔軟性の高い管理を実現できる機能。 今回は、その LVM の基本的な使い方について確認してみる。

検証に使う環境は CentOS7 にした。

$ cat /etc/redhat-release 
CentOS Linux release 7.1.1503 (Core) 
$ uname -r
3.10.0-229.14.1.el7.x86_64

LVM をインストールする

LVM のユーティリティが入っていない場合には、インストールした上で再起動しておく。

$ sudo yum -y install lvm2
$ sudo shutdown -r now

ブロックデバイスを用意する

LVM の検証のためにハードディスクを用意するのは面倒なので、今回はループデバイスで代用することにする。 ループデバイスは通常のファイルをブロックデバイスとして読み書きできるようにする機能。 詳細は以下に書いた。

blog.amedama.jp

あらかじめ 100MB の容量を持ったループデバイスをふたつ用意しておく。

$ dd if=/dev/zero of=/var/tmp/loopfile0 bs=1M count=100
$ dd if=/dev/zero of=/var/tmp/loopfile1 bs=1M count=100
$ sudo losetup /dev/loop0 /var/tmp/loopfile0
$ sudo losetup /dev/loop1 /var/tmp/loopfile1
$ losetup -a
/dev/loop0: []: (/var/tmp/loopfile0)
/dev/loop1: []: (/var/tmp/loopfile1)

PV (Physical Volume) を作る

LVM では物理的なハードディスクなどを PV という単位で管理する。 今回は先ほど作ったブロックデバイスを丸ごとそのまま PV として使ってるけど、特定のパーティションだけを LVM の PV として扱うこともできるっぽい。

pvcreate コマンドでブロックデバイスを PV として扱えるようにする。

$ sudo pvcreate -v /dev/loop0 /dev/loop1
    Set up physical volume for "/dev/loop0" with 204800 available sectors
    Zeroing start of device /dev/loop0
    Writing physical volume data to disk "/dev/loop0"
  Physical volume "/dev/loop0" successfully created
    Set up physical volume for "/dev/loop1" with 204800 available sectors
    Zeroing start of device /dev/loop1
    Writing physical volume data to disk "/dev/loop1"
  Physical volume "/dev/loop1" successfully created

PV の情報は pvdisplay コマンドで確認できる。

$ sudo pvdisplay /dev/loop0 /dev/loop1
  "/dev/loop0" is a new physical volume of "100.00 MiB"
  --- NEW Physical volume ---
  PV Name               /dev/loop0
  VG Name               
  PV Size               100.00 MiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               CDt1W3-ErgE-TB97-BqOl-7FSZ-Txzi-i7o5Ow
   
  "/dev/loop1" is a new physical volume of "100.00 MiB"
  --- NEW Physical volume ---
  PV Name               /dev/loop1
  VG Name               
  PV Size               100.00 MiB
  Allocatable           NO
  PE Size               0   
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa

VG (Volume Group) を作る

作成した PV は VG という単位で束ねて使う。 もちろん、別に束ねなくても問題はない。

vgcreate コマンドで先ほど作った PV を束ねた新しい VG を作る。

$ sudo vgcreate -v vg0 /dev/loop0 /dev/loop1
    Adding physical volume '/dev/loop0' to volume group 'vg0'
    Adding physical volume '/dev/loop1' to volume group 'vg0'
    Archiving volume group "vg0" metadata (seqno 0).
    Creating volume group backup "/etc/lvm/backup/vg0" (seqno 1).
  Volume group "vg0" successfully created

作成した VG は vgscan コマンドで確認できる。

$ sudo vgscan
  Reading all physical volumes.  This may take a while...
  Found volume group "vg0" using metadata type lvm2

VG の情報は vgdisplay コマンドで確認できる。

$ sudo vgdisplay -v vg0
    Using volume group(s) on command line.
  --- Volume group ---
  VG Name               vg0
  System ID             
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               192.00 MiB
  PE Size               4.00 MiB
  Total PE              48
  Alloc PE / Size       0 / 0   
  Free  PE / Size       48 / 192.00 MiB
  VG UUID               HEXmQd-eBbN-geXc-bMHA-PCow-E8Q3-L7LNTS
   
  --- Physical volumes ---
  PV Name               /dev/loop0     
  PV UUID               CDt1W3-ErgE-TB97-BqOl-7FSZ-Txzi-i7o5Ow
  PV Status             allocatable
  Total PE / Free PE    24 / 24
   
  PV Name               /dev/loop1     
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa
  PV Status             allocatable
  Total PE / Free PE    24 / 24
   

上記の vgdisplay コマンドの表示の中には PE という表示があって、何やら容量を表しているっぽいように見える。 これは PE (Physical Extend) というもので、LVM では VG をこの PE という単位を使って容量の管理をしている。

ひとつの VG の中には最大で 64k 個の PE が入る。 VG の中身が PE という均一の大きさで仕切られていて、その仕切りの数の最大が 64k 個というのをイメージするといい。

ひとつの PE のサイズは可変で、デフォルトでは 4MiB に設定されている。 つまり、デフォルトではひとつの VG で扱える最大のサイズは 4MiB * 64k PE = 256GiB ということになる。 この値は vgcreate コマンドの -s オプションで変更することができる。 簡単に計算するには PE のサイズ 1MiB 毎に 64GiB ずつ扱えるサイズが大きくなると覚えておけばよさそう。 例えば -s 32m とすれば、PE のサイズが 32MiB なので扱える最大サイズは 32 * 64 = 2048GiB (2TiB) になる。

pvdisplay コマンドを使うと PV で使われている PE のサイズが確認できる。

$ sudo pvdisplay /dev/loop0 /dev/loop1
  --- Physical volume ---
  PV Name               /dev/loop0
  VG Name               vg0
  PV Size               100.00 MiB / not usable 4.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              24
  Free PE               24
  Allocated PE          0
  PV UUID               CDt1W3-ErgE-TB97-BqOl-7FSZ-Txzi-i7o5Ow
   
  --- Physical volume ---
  PV Name               /dev/loop1
  VG Name               vg0
  PV Size               100.00 MiB / not usable 4.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              24
  Free PE               24
  Allocated PE          0
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa

LV (Logical Volume) を作る

さて、VG まで作ることができたので、そこから論理的なボリュームである LV を切り出すことができる。 これが従来のパーティションに相当すると考えればいいかな。

lvcreate コマンドを使ってサイズを指定した上で VG から LV を切り出す。

$ sudo lvcreate -L 16M -n lv0 vg0
  Logical volume "lv0" created.

すると LV のデバイスができる。

$ ls /dev/vg0/lv0 
/dev/vg0/lv0

LV の情報は lvdisplay コマンドで確認できる。

$ sudo lvdisplay /dev/vg0/lv0
  --- Logical volume ---
  LV Path                /dev/vg0/lv0
  LV Name                lv0
  VG Name                vg0
  LV UUID                vzd56T-b6uU-v8pY-ysNn-Y6EH-pY7w-etAinX
  LV Write Access        read/write
  LV Creation host, time localhost.localdomain, 2015-09-21 22:16:10 +0900
  LV Status              available
  # open                 0
  LV Size                16.00 MiB
  Current LE             4
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     8192
  Block device           253:0
   

vgdisplay コマンドを確認すると、LV を切り出した分だけ /dev/loop0 から利用可能な PE が減っている。

$ sudo vgdisplay -v vg0 | tail -n 12
    Using volume group(s) on command line.
   
  --- Physical volumes ---
  PV Name               /dev/loop0     
  PV UUID               CDt1W3-ErgE-TB97-BqOl-7FSZ-Txzi-i7o5Ow
  PV Status             allocatable
  Total PE / Free PE    24 / 20
   
  PV Name               /dev/loop1     
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa
  PV Status             allocatable
  Total PE / Free PE    24 / 24
   

LV を使うために、まずは XFS でフォーマットする。

$ sudo mkfs.xfs /dev/vg0/lv0
meta-data=/dev/vg0/lv0           isize=256    agcount=1, agsize=4096 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=4096, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=853, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

あとは適当な場所にマウントするだけ。

$ mkdir /tmp/mnt0
$ sudo mount -t xfs /dev/vg0/lv0 /tmp/mnt0

df コマンドでマウントされていることが確認できる。

$ df | grep mnt
/dev/mapper/vg0-lv0       12972     880    12092    7% /tmp/mnt0

VG に PV を追加する

例えば VG の容量が足りなくなってきた場合などには、ハードディスクを新たに追加する必要がありそう。

まずは先ほどと同様に、追加するための PV をループデバイスで作っておく。

$ dd if=/dev/zero of=/var/tmp/loopfile2 bs=1M count=100
100+0 レコード入力
100+0 レコード出力
104857600 バイト (105 MB) コピーされました、 0.0550698 秒、 1.9 GB/秒
$ sudo losetup /dev/loop2 /var/tmp/loopfile2
$ sudo pvcreate /dev/loop2
  Physical volume "/dev/loop2" successfully created

既存の VG に PV を追加する場合は vgextend コマンドを使う。

$ sudo vgextend vg0 /dev/loop2
  Volume group "vg0" successfully extended

これで VG に PV が追加された。

$ sudo vgdisplay -v vg0 | tail -n 16
    Using volume group(s) on command line.
  --- Physical volumes ---
  PV Name               /dev/loop0     
  PV UUID               CDt1W3-ErgE-TB97-BqOl-7FSZ-Txzi-i7o5Ow
  PV Status             allocatable
  Total PE / Free PE    24 / 20
   
  PV Name               /dev/loop1     
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa
  PV Status             allocatable
  Total PE / Free PE    24 / 24
   
  PV Name               /dev/loop2     
  PV UUID               gqsmNX-v23C-F7IU-IsCa-qlfX-wsQ2-ywIvzy
  PV Status             allocatable
  Total PE / Free PE    24 / 24
      

LV のサイズを増やす

LV の容量を増やすには lvextend コマンドを使う。 これはもちろん VG に空きがなければいけない。

$ sudo lvextend -L +16MB /dev/vg0/lv0
  Size of logical volume vg0/lv0 changed from 16.00 MiB (4 extents) to 32.00 MiB (8 extents).
  Logical volume lv0 successfully resized

vgdisplay コマンドを確認すると、おかわりした分だけ /dev/loop0 から利用可能な PE が減っている。

$ sudo vgdisplay -v vg0 | tail -n 16
    Using volume group(s) on command line.
  --- Physical volumes ---
  PV Name               /dev/loop0     
  PV UUID               CDt1W3-ErgE-TB97-BqOl-7FSZ-Txzi-i7o5Ow
  PV Status             allocatable
  Total PE / Free PE    24 / 16
   
  PV Name               /dev/loop1     
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa
  PV Status             allocatable
  Total PE / Free PE    24 / 24
   
  PV Name               /dev/loop2     
  PV UUID               gqsmNX-v23C-F7IU-IsCa-qlfX-wsQ2-ywIvzy
  PV Status             allocatable
  Total PE / Free PE    24 / 24

LV の情報をみてもサイズが 16MiB から 32MiB に倍増している。

$ sudo lvdisplay /dev/vg0/lv0
  --- Logical volume ---
  LV Path                /dev/vg0/lv0
  LV Name                lv0
  VG Name                vg0
  LV UUID                vzd56T-b6uU-v8pY-ysNn-Y6EH-pY7w-etAinX
  LV Write Access        read/write
  LV Creation host, time localhost.localdomain, 2015-09-21 22:16:10 +0900
  LV Status              available
  # open                 1
  LV Size                32.00 MiB
  Current LE             8
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     8192
  Block device           253:0
   

よーし、ばっちりだーと思って df しても、実はこの時点ではまだ容量は増えていない。 ファイルシステム的には、まだ使える領域が増えたことを認識できていない。

$ df | grep mnt0
/dev/mapper/vg0-lv0       12972     880    12092    7% /tmp/mnt0

この LV は XFS でフォーマットしてあるので、サイズを増やすには xfs_growfs コマンドを使う。

$ sudo xfs_growfs /tmp/mnt0
meta-data=/dev/mapper/vg0-lv0    isize=256    agcount=1, agsize=4096 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=4096, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal               bsize=4096   blocks=853, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 4096 to 8192

これでやっと空き容量が増えた。

$ df | grep mnt0
/dev/mapper/vg0-lv0       29356     912    28444    4% /tmp/mnt0

尚、ファイルシステムに ext* を使っている場合は resize2fs コマンドを使うようだ。

PV のデータを移動する

メンテナンスなどで、ある PV のデータを別の PV に移すことも考えられる。

そうした場合には pvmove コマンドを使って PV から PV にデータを移動できる。

$ sudo pvmove /dev/loop0 /dev/loop2
  /dev/loop0: Moved: 75.0%
  /dev/loop0: Moved: 100.0%

データが移ったので /dev/loop0 が空いた代わりに /dev/loop2 の利用可能 PE が減った。

$ sudo vgdisplay -v vg0 | tail -n 16
    Using volume group(s) on command line.
  --- Physical volumes ---
  PV Name               /dev/loop0     
  PV UUID               CDt1W3-ErgE-TB97-BqOl-7FSZ-Txzi-i7o5Ow
  PV Status             allocatable
  Total PE / Free PE    24 / 24
   
  PV Name               /dev/loop1     
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa
  PV Status             allocatable
  Total PE / Free PE    24 / 24
   
  PV Name               /dev/loop2     
  PV UUID               gqsmNX-v23C-F7IU-IsCa-qlfX-wsQ2-ywIvzy
  PV Status             allocatable
  Total PE / Free PE    24 / 16
   

使わなくなった PV は vgreduce コマンドで外すことができる。

$ sudo vgreduce vg0 /dev/loop0
  Removed "/dev/loop0" from volume group "vg0"

これで VG に参加している PV が 2 台に戻った。

$ sudo vgdisplay -v vg0 | tail -n 12
    Using volume group(s) on command line.
   
  --- Physical volumes ---
  PV Name               /dev/loop1     
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa
  PV Status             allocatable
  Total PE / Free PE    24 / 24
   
  PV Name               /dev/loop2     
  PV UUID               gqsmNX-v23C-F7IU-IsCa-qlfX-wsQ2-ywIvzy
  PV Status             allocatable
  Total PE / Free PE    24 / 16

データを冗長化する

VG が複数の PV を束ねて使う場合、そのままでは耐障害性という意味でソフトウェア RAID0 に近いように思える。 そのため LVM には PV の片系故障でデータが消えるのを防ぐため、複数の PV にデータをミラーリングする機能があるようだ。 ソフトウェア RAID1 に近い機能かな。

lvcreate コマンドで LV を作る際に、-m オプションを付けた上でミラーリングする先の PV を指定する。

$ sudo lvcreate -L 16M -m 1 -n lv1 vg0 /dev/loop1 /dev/loop2
  Logical volume "lv1" created.

容量を確認すると、両方の PV から均等に利用可能な PE が減っている。

$ sudo vgdisplay -v vg0 | tail -n 12
    Using volume group(s) on command line.
   
  --- Physical volumes ---
  PV Name               /dev/loop1     
  PV UUID               Kia26d-4T5B-dnqn-6AYU-Wz2Q-lmnq-Q9uLxa
  PV Status             allocatable
  Total PE / Free PE    24 / 19
   
  PV Name               /dev/loop2     
  PV UUID               gqsmNX-v23C-F7IU-IsCa-qlfX-wsQ2-ywIvzy
  PV Status             allocatable
  Total PE / Free PE    24 / 11
   

LV の情報を見ると Mirrored Volumes という項目が増えて、データが複数の PV に冗長化されていることがわかる。

$ sudo lvdisplay /dev/vg0/lv1
  --- Logical volume ---
  LV Path                /dev/vg0/lv1
  LV Name                lv1
  VG Name                vg0
  LV UUID                6ArEdr-EDSx-JAr0-xFkB-MTx5-7nO7-Infe4Y
  LV Write Access        read/write
  LV Creation host, time localhost.localdomain, 2015-09-21 22:31:50 +0900
  LV Status              available
  # open                 0
  LV Size                16.00 MiB
  Current LE             4
  Mirrored volumes       2
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     8192
  Block device           253:5
   

とはいえ個人的にはハードウェア RAID で冗長化したボリュームの上で LVM を使いたいかな。

まとめ

今回は CentOS7 とループデバイスを使って簡単に LVM の動作を試してみた。 物理的なブロックデバイスを LVM というレイヤーを挟んで使うのは確かに便利だけど、上手に使うためには事前知識やノウハウがたくさん必要になりそうだと感じた。