【shell】vCenter を題材にした LVM のお勉強


# LVM について

Linux のディスクを操作する際に扱うことになる LVM ですが、頻繁に扱うわけではないので個人的には詳細を忘れてしまいがちです。
vSphere 環境 を管理するために必要な vCenter Server は phothon os と呼ばれる Linux ベースのアプライアンス製品ですが、この vCenter も LVM によってディスクが管理されています。今回は vCenter を題材に LVM の動作について復習してみようと思います。
インターネット上の記事ですが、LVM の概要などについては以下のリンクの記事がとても分かりやすくまとまっていますので、こちらをご一読ください。

[LVMで論理ボリューム拡張 -4ステップで設定できる](https://isleofhoso.com/linux-lvm-extend/)

# vCenter における LVM のディスク拡張

### vCenter のディスクレイアウト

冒頭にも記載した通り、多くの Linux の製品と同じく vCeneter のディスクの管理にも LVM が利用されています。KB:78515 に詳細がありますが、以下の表にまとめられている通り、vCenter は 16 個のディスクを持っていて、ディスク毎に用途が細かく決められています(ディスクサイズは Tiny を指定して vCenter をデプロイした時のものです)。
![ディスクレイアウト](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3547196/8109baf7-0696-c6ad-3781-0406d0cde6a9.png)
[参考：List of VMDKs/Partitions for a vCenter Server 7.0 - Size Mount point and Purpose (78515)](https://kb.vmware.com/s/article/78515?lang=en_us)

### ディスク拡張方法
それぞれのディスクを拡張する必要がある場合は、KB:2145603 の手順を参照します。
KB には色々と書いてありますが、要は vSphere Client から対象となるディスクのサイズを拡張した後、BASH Shell から「/usr/lib/applmgmt/support/scripts/autogrow.sh」の Shell スクリプトを実行するだけで拡張作業は完了します。本来であれば LVM に関係するいくつもの操作を行いディスクを拡張する必要がりますが、一連の操作は「autogrow.sh」によりスクリプト化されている為、簡単に拡張出来てしまいます。
[参考：Increasing the disk space for the vCenter Server Appliance in vSphere 6.5, 6.7, 7.0 and 8.0 (2145603)](https://kb.vmware.com/s/article/2145603?lang=en_us)

# 拡張時に利用する Shell スクリプトの中身を紐解く
### autogrow.sh をのぞいてみる
せっかくなので「autogrow.sh」で何をやっているのかスクリプトの中身をのぞいてみたいと思います。利用したのは手元にあった「VMware vCenter Server 7.0 Update 3c」です。

```shell
root@vc70 [ ~ ]# vpxd -v
VMware VirtualCenter 7.0.3 build-19234570
```

中身は「/usr/sbin/disk_utils.sh」を読み込んで関数「lvm_autogrow」を実行しているだけの至ってシンプルなものでした。
「lvm_autogrow」の内容は呼び出し元の「/usr/sbin/disk_utils.sh」を確認する必要がありそうですね。

```shell:autogrow.sh
root@vc70 [ ~ ]# cat /usr/lib/applmgmt/support/scripts/autogrow.sh
#!/bin/bash
#
# Copyright 2016-2020  VMware, Inc.  All rights reserved.
#
# autogrow    Grow all partitions to 100%

# /usr/lib/applmgmt/support/scripts/resize-root.py
. /usr/sbin/disk_utils.sh
lvm_autogrow
```

### さらに disk_utils.sh の中身をのぞいてみる

次に「disk_utils.sh」の中身を確認します。このスクリプトはそれなりに長いので、先ず「autogrow.sh」で呼び出される関数「lvm_autogrow」の定義を見てみます。
関数「lvm_autogrow」内では「resize_lvm_vg」が呼ばれています。

```shell:disk_utils.sh - lvm_autogrow
lvm_autogrow()
{
   # we don't handle brand new disks
   # The user has to manually do vgcreate
   # or vgextend to add it to existing VG

   # For existing VGs just call resize_lvm_vg
   resize_lvm_vg
   return $?
}
※ return $? は直前実行したコマンドの終了値（0は成功、1は失敗）を返している
```

次は「resize_lvm_vg」の定義を確認します。
最初に local で宣言した変数「VGLIST」へコマンド「lvdisplay」の3番目のフィールドの結果を代入しています。

```shell:disk_utils.sh - resize_lvm_vg
# Following routine resizes all VGs
resize_lvm_vg()
{
   local VGLIST=`lvdisplay | grep "LV Path"|awk '{print $3}'`
   # Call resize PVs (Doesn't hurt if called multiple times)
   resize_lvm_pv
   # Now resize all LVM LVs
   for v in $VGLIST; do
     tlog "INFO: LV Resizing $v"
     lvresize --resizefs -l +100%FREE "$v" 2>&1
   done
   return 0
}
```
ちなみに vCenter 上でこのコマンドを個別で実行した場合は以下のようになり、lvm のそれぞれのパスが返されることが分かります。

```shell
root@vc70 [ ~ ]# lvdisplay | grep "LV Path"|awk '{print $3}'
/dev/seat_vg/seat
/dev/archive_vg/archive
/dev/netdump_vg/netdump
/dev/imagebuilder_vg/imagebuilder
/dev/log_vg/log
/dev/vg_lvm_snapshot/lv_lvm_snapshot
/dev/swap_vg/swap1
/dev/db_vg/db
/dev/autodeploy_vg/autodeploy
/dev/updatemgr_vg/updatemgr
/dev/core_vg/core
/dev/dblog_vg/dblog
/dev/lifecycle_vg/lifecycle
/dev/vtsdb_vg/vtsdb
/dev/vtsdblog_vg/vtsdblog
/dev/vg_root_0/lv_root_0
```
次は関数「resize_lvm_vg」 が実行されます。「rezsize_lvm_vg」も「disk_utils.sh」内に定義があります。先ず「rescan-scsi-bus.sh」によりディスクをスキャンして物理的に拡張されたことをカーネルに認識させています。

```shell:disk_utils.sh - resize_lvm_pv
# Following routine resizes all PVs in LVM called by resize_lvm_vg
resize_lvm_pv()
{
   # Add a force rescan of scsi bus to allow hotadd changed disk size
   # Note the following command is SuSE / SLES specific
   tlog "INFO: Scanning Hard disk sizes"
   rescan-scsi-bus.sh -w --forcerescan 2>&1
   # Now resize all LVM PVs
   local DEVLIST=`ls /sys/block/ | grep sd[a-z]`
   for d in $DEVLIST; do
      local DEV=/dev/${d}
      # check for partitions, filesystem, swap directly on the device and LVM.
      tlog "INFO: Resizing PV $DEV"
      if  file -s $DEV | grep -q "LVM2"; then
         pvresize $DEV 2>&1
      fi
   done
}
```
「rescan-scsi-bus.sh」は以下のパスにあります。
```shell
root@vc70 [ ~ ]# which rescan-scsi-bus.sh
/usr/bin/rescan-scsi-bus.sh
```
また、「if  file -s $DEV | grep -q "LVM2"; then」の箇所でデバイスタイプが LVM であるか否かを判定しています。LVM2 であればデバイスにコマンド「pvresize」を実行して物理領域を拡張します。

ちなみに、file コマンドはファイルの属性を確認するコマンドです。
先ほどの if 文の中では /dev 配下のデバイスファイルのタイプを確認しているのですね。
個別で実行してみると以下の様になりますが、1つ目の sda のデバイスは boot sector で使われていて、LVM ではないので先ほどの if 文では false となり、処理は実行されません。
2つ目は LVM ですので true となり処理が実行されます。

```shell
root@vc70 [ ~ ]# file -s /dev/sda
/dev/sda: DOS/MBR boot sector, extended partition table (last)
root@vc70 [ ~ ]# file -s /dev/sdc
/dev/sdc: LVM2 PV (Linux Logical Volume Manager), UUID: ONb1Oz-iPJv-LE6x-pZJJ-QIYA-P3rY-XUclyc, size: 26843545600
```
最後に呼び出し元の「resize_lvm_vg」に戻ってコマンド「lvresize」によって拡張された PV を基に lvm を拡張します。

```shell:disk_utils.sh - resize_lvm_vg
# Following routine resizes all VGs
resize_lvm_vg()
{
   local VGLIST=`lvdisplay | grep "LV Path"|awk '{print $3}'`
   # Call resize PVs (Doesn't hurt if called multiple times)
   resize_lvm_pv
   # Now resize all LVM LVs
   for v in $VGLIST; do
     tlog "INFO: LV Resizing $v"
     lvresize --resizefs -l +100%FREE "$v" 2>&1
   done
   return 0
}
```




# スクリプトの内容を手動で実行して vCenter のディスクを拡張してみる

### 実行前のディスク容量を確認
今回は /storage/log 領域を初期状態から2倍の20 GB に容量を拡張してみたいと思いますが、「df」コマンドで事前の容量を確認しておきます(容量は 9.8 GB)。
また、vSphere client から該当ディスクを事前に拡張しておきます、物理的に拡張しただけでは OS 上での容量はまだ増えません。

```shell
root@vc70 [ ~ ]# df -h | grep log_vg-log
/dev/mapper/log_vg-log                       9.8G  2.7G  6.7G  29% /storage/log
```

### 物理ディスクの拡張をカーネルに認識させる
スクリプトにあった「rescan-scsi-bus.sh」を実行し、ディスクをスキャンします。スキャンが完了すると物理ディスクの容量が増えます。
増えたことは「fdisk」のコマンドなどで確認できます(下記の実行結果では /dev/sde のディスクが 20GiB となっていることが確認できます)。


```shell
root@vc70 [ ~ ]# rescan-scsi-bus.sh -w --forcerescan
Syncing file systems
which: no multipath in (/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/java/jre-vmware/bin:/opt/vmware/bin:/opt/vmware/bin)
Scanning SCSI subsystem for new devices and remove devices that have disappeared
Scanning host 0 for  SCSI target IDs  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15, all LUNs
 Scanning for device 0 0 0 0 ...
OLD: Host: scsi0 Channel: 00 Id: 00 Lun: 00
      Vendor: NECVMWar Model: VMware IDE CDR00 Rev: 1.00
      Type:   CD-ROM                           ANSI SCSI revision: 05
Scanning host 1 for  SCSI target IDs  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15, all LUNs
Scanning host 2 for  SCSI target IDs  0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15, all LUNs
 Scanning for device 2 0 0 0 ...
OLD: Host: scsi2 Channel: 00 Id: 00 Lun: 00
      Vendor: VMware   Model: Virtual disk     Rev: 1.0
      Type:   Direct-Access                    ANSI SCSI revision: 02
 Scanning for device 2 0 1 0 ...
OLD: Host: scsi2 Channel: 00 Id: 01 Lun: 00
      Vendor: VMware   Model: Virtual disk     Rev: 1.0
      Type:   Direct-Access
・・・
root@vc70 [ ~ ]# fdisk -l
・・・
Disk /dev/sde: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
・・・
```

### PV(physical volume)を拡張する
スクリプトでは resize_lvm_pv 関数内で実行されていた pvresize を拡張した /dev/sde に対して実行します。これによりフィジカルボリュームが増えます。

```shell
root@vc70 [ ~ ]# pvresize /dev/sde
  Physical volume "/dev/sde" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
```

### LV(logical volume)のサイズを拡張する

最後に lvresize でロジカルボリュームを拡張します。コマンドの引数に与えるディスクのパスは lvdisplay の実行結果に含まれる LV Path を指定します。

```shell
root@vc70 [ ~ ]# lvdisplay
・・・
  --- Logical volume ---
  LV Path                /dev/log_vg/log
  LV Name                log
  VG Name                log_vg
  LV UUID                N8Ch6t-zKpA-dw6k-IFyj-siHV-zw0A-AvqGe9
  LV Write Access        read/write
  LV Creation host, time vc70.mydomain.internal, 2023-06-07 04:04:42 +0000
  LV Status              available
   open                 1
  LV Size                9.99 GiB
  Current LE             1279
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           254:11
・・・

root@vc70 [ ~ ]# lvresize --resizefs -l +100%FREE /dev/log_vg/log
  Size of logical volume log_vg/log changed from 9.99 GiB (1279 extents) to 19.99 GiB (2559 extents).
  Logical volume log_vg/log successfully resized.
resize2fs 1.45.5 (07-Jan-2020)
Filesystem at /dev/mapper/log_vg-log is mounted on /storage/log; on-line resizing required
old_desc_blocks = 2, new_desc_blocks = 3
The filesystem on /dev/mapper/log_vg-log is now 5240832 (4k) blocks long.
```

### 作業完了後の確認
df コマンドディスクが拡張されたかを確認します、以下の通り無事に /storage/log が 20GB に拡張されました。

```shell
root@vc70 [ ~ ]# df -h | grep log_vg-log
/dev/mapper/log_vg-log                        20G  2.8G   16G  15% /storage/log
```