EC2でルートになっているEBSボリュームを縮小する

# 初めに
既に構築済みのLinuxにてルートを含むボリュームのサイズを縮小したい場合があります。
ボリューム全体の容量を増やしたり、パーティションのサイズを変更する場合は、```resize2fs```などを駆使することで対応できますが、ボリュームを縮小するには縮小したボリュームを作成してデータを移植(コピー)する手順が必要となります。

使用しているLinuxやパーティションの構成により方法は異なります。
本記事では以下の環境の場合の手順例をご紹介します。

* LVMを使用している
* ブートローダーはGRUB2(Stage1.5を使用している)
* OSはLinux (本記事では RedHatEnterpriseLinux 7.5)
* 作業用のEC2はt2インスタンス

# 大まかな流れ

* 縮小後サイズのEBSを作成
* ブートローダーをコピー
* パーティションを作成
    * 基本パーティションを作成
    * 論理ボリュームを作成
* サイズの変更を行わないパーティションをddコマンドでコピー
* サイズの変更を行うパーティションをcpコマンドでコピー
* 論理ボリューム名とUUIDを変更する

# 準備作業

ほとんどLinux上での作業となります。以下の例では root の状態で操作しています。
awsの操作もコマンドで実行していますが、Webのコンソールからでも問題ありません。

本記事ではt2インスタンスを使用しているため、ディスクのデバイス名を ```/dev/xvd***``` としていますが、
t3の場合ディスクのデバイス名が ```/dev/nvme***``` などになります。

## 縮小後サイズの見積もり

```lsblk```と```df``` コマンドでディスク容量と使用率を確認します。

```

$ lsblk
NAME          MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
xvda          202:0    0   120G  0 disk
|-xvda1       202:1    0   512M  0 part /boot
|-xvda2       202:2    0   256M  0 part
`-xvda3       202:3    0 119.3G  0 part
  |-vg00-LV01 253:0    0    20G  0 lvm  /
  |-vg00-LV02 253:1    0     8G  0 lvm  [SWAP]
  |-vg00-LV03 253:2    0    20G  0 lvm  /usr
  |-vg00-LV04 253:3    0    30G  0 lvm  /var
  `-vg00-LV05 253:4    0  41.3G  0 lvm  /home
```

```
$ df -hT
ファイルシス          タイプ   サイズ  使用  残り 使用% マウント位置
devtmpfs              devtmpfs   479M     0  479M    0% /dev
tmpfs                 tmpfs      496M     0  496M    0% /dev/shm
tmpfs                 tmpfs      496M  7.0M  489M    2% /run
tmpfs                 tmpfs      496M     0  496M    0% /sys/fs/cgroup
/dev/mapper/vg00-LV01 xfs         20G  6.3G   14G   32% /
/dev/mapper/vg00-LV03 xfs         20G  4.0G   17G   20% /usr
/dev/mapper/vg00-LV05 xfs         42G  2.6G   39G    7% /home
/dev/xvda1            xfs        509M  193M  317M   38% /boot
/dev/mapper/vg00-LV04 xfs         30G  2.0G   29G    7% /var
tmpfs                 tmpfs      100M     0  100M    0% /run/user/6032
```

今回は以下のようなパーティションで、50GBに縮小することにしました。

|デバイス|マウント先|容量|使用量|縮小後|
|:--|---|--:|--:|--:|
|/dev/mapper/vg00-LV01|/|20GB|6.3GB|12GB|
|/dev/mapper/vg00-LV02|swap|8GB|-|8GB|
|/dev/mapper/vg00-LV03|/usr|20GB|4.0GB|10GB|
|/dev/mapper/vg00-LV04|/var|30GB|2.0GB|10GB|
|/dev/mapper/vg00-LV05|/home|42GB|2.6GB|10GB|

## 作業用EC2を起動する

作業用のEC2インスタンスを起動します。
OSはLinux系で、インスタンスの種類は何でもよいと思います。
私はt2.nanoだと心もとないのでt2.microで、OSはAmazonLinux2にしました。

## 縮小元EBSのバックアップを取得

EBSの切断とスナップショットを取っておきます。

```
$ aws ec2 detach-volume --instance-id i-************ --volume-id <vol--縮小前ボリューム>
$ aws ec2 create-snapshot --volume-id <vol--縮小前ボリューム> --tag-specification "ResourceType=\"snapshot\",Tags=[{Key=\"Name\",Value=\"reduction-source\"}]" --description "add tag snapshot"
```

## 新しいEBSを作成
新しいEBSをサイズ、50GBで作成します。

```
$ aws ec2 create-volume --availability-zone ap-northeast-1d --size 50
```

# 縮小作業

## EBSをアタッチ

縮小元EBSと新しいEBSをアタッチします。

```
$ aws ec2 attach-volume --device /dev/sdf --instance-id i-***************** --volume-id <vol--縮小前ボリューム>
$ aws ec2 attach-volume --device /dev/sdg --instance-id i-***************** --volume-id <vol--縮小後ボリューム>
```

```lsblk -i``` で確認します。

```
$ lsblk -i
NAME          MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
xvda          202:0    0     8G  0 disk
`-xvda1       202:1    0     8G  0 part /
xvdf          202:80   0   120G  0 disk
|-xvdf1       202:81   0   512M  0 part
|-xvdf2       202:82   0   256M  0 part
`-xvdf3       202:83   0 119.3G  0 part
  |-vg00-LV01 253:0    0    20G  0 lvm
  |-vg00-LV02 253:1    0     8G  0 lvm
  |-vg00-LV03 253:2    0    20G  0 lvm
  |-vg00-LV04 253:3    0    30G  0 lvm
  `-vg00-LV05 253:4    0  41.3G  0 lvm
xvdg          202:96   0    50G  0 disk
```

縮小元EBS```xvdf```と新しいEBS```xvdg```がアタッチされました。

## 縮小元EBSの情報を確認

縮小後のEBS(論理ボリューム)に同じUUIDを設定するため、
```blkid``` でUUIDを確認しておきます。

```
$ blkid
/dev/xvda1: LABEL="/" UUID="afcf1342-1d40-9999-bde9-e4ea5d87e3b6" TYPE="xfs" PARTLABEL="Linux" PARTUUID="66ff2032-f8d8-4a9a-b3cb-e288fcf677f0"
/dev/xvdf1: UUID="89ac732f-ac71-4ca2-9999-b9be20dd4971" TYPE="xfs" PARTUUID="00029819-01"
/dev/xvdf2: SEC_TYPE="msdos" UUID="EC3E-257F" TYPE="vfat" PARTUUID="00029819-02"
/dev/xvdf3: UUID="Yw1Xkt-Jfzd-9999-lyUF-P1R4-k0CT-LVpouP" TYPE="LVM2_member" PARTUUID="00029819-03"
/dev/mapper/vg00-LV01: UUID="f1417da0-b039-9999-9db7-ce241ee16e1b" TYPE="xfs"
/dev/mapper/vg00-LV02: UUID="8c60f406-743d-9999-b7d9-91f2cbb8811f" TYPE="swap"
/dev/mapper/vg00-LV03: UUID="741063de-0f7c-9999-97d8-74f5966cb188" TYPE="xfs"
/dev/mapper/vg00-LV04: UUID="2876e402-35e0-9999-b3fb-375129dec539" TYPE="xfs"
/dev/mapper/vg00-LV05: UUID="c3972330-190a-9999-bd60-d738e60c1f56" TYPE="xfs"
```

## ブートローダーのコピー

MBR(Stage1)とStage1.5の部分(63セクタ)をコピーします。
パーティション情報も含んでいますが、パーティションは作り直しなので一緒にコピーしちゃいます。

```
dd if=/dev/xvdf of=/dev/xvdg bs=512 count=63
```

## 縮小後ボリュームに基本パーティションを作成

``` fdisk /dev/xvdf -l``` で縮小前のボリュームのパーティションを確認します。

```
$ fdisk /dev/xvdf -l
Disk /dev/xvdf: 120 GiB, 128849018880 bytes, 251658240 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
Disklabel type: dos
Disk identifier: 0x00029819

Device     Boot   Start       End   Sectors   Size Id Type
/dev/xvdf1 *       2048   1050623   1048576   512M 83 Linux
/dev/xvdf2      1050624   1574911    524288   256M  6 FAT16
/dev/xvdf3      1574912 251658239 250083328 119.3G 8e Linux LVM
```

```fdisk /dev/xvdg```で縮小後ボリュームの全てのパーティションを削除します。

```
$ fdisk /dev/xvdg

Welcome to fdisk (util-linux 2.30.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): d
Partition number (1,2,3, default 3): [Enter]

Partition 3 has been deleted.

Command (m for help): d
Partition number (1,2, default 2): [Enter]

Partition 2 has been deleted.

Command (m for help): d
Selected partition 1
Partition 1 has been deleted.

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```

```fdisk /dev/xvdg```で縮小後のボリュームにパーティションを作成します。

```
$ fdisk /dev/xvdg

Welcome to fdisk (util-linux 2.30.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x656aa6b5.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): [Enter]
First sector (2048-104857599, default 2048): [Enter]
Last sector, +sectors or +size{K,M,G,T,P} (2048-104857599, default 104857599): +512M

Created a new partition 1 of type 'Linux' and of size 512 MiB.
```
```
Command (m for help): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
   e   extended (container for logical partitions)
Select (default p):

Using default response p.
Partition number (2-4, default 2): [Enter]
First sector (1050624-104857599, default 1050624): [Enter]
Last sector, +sectors or +size{K,M,G,T,P} (1050624-104857599, default 104857599): +256M

Created a new partition 2 of type 'Linux' and of size 256 MiB.
```
```
Command (m for help): n
Partition type
   p   primary (2 primary, 0 extended, 2 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (3,4, default 3): [Enter]
First sector (1574912-104857599, default 1574912): [Enter]
Last sector, +sectors or +size{K,M,G,T,P} (1574912-104857599, default 104857599): [Enter]

Created a new partition 3 of type 'Linux' and of size 49.3 GiB.

```

パーティションのタイプを変更します。
今回は2番目のパーティションがFAT16、3番めのパーティションがLinux LVMなので、
それぞれ ```6``` と ```8e``` を指定します。

```
Command (m for help): t
Partition number (1-3, default 3): 2
Hex code (type L to list all codes): 6

Changed type of partition 'Linux' to 'FAT16'.

Command (m for help): t
Partition number (1-3, default 3): 3
Hex code (type L to list all codes): 8e

Changed type of partition 'Linux' to 'Linux LVM'.
```

```p``` で確認します。

```
Command (m for help): p
Disk /dev/xvdg: 50 GiB, 53687091200 bytes, 104857600 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
Disklabel type: dos
Disk identifier: 0x656aa6b5

Device     Boot   Start       End   Sectors  Size Id Type
/dev/xvdg1         2048   1050623   1048576  512M 83 Linux
/dev/xvdg2      1050624   1574911    524288  256M  6 FAT16
/dev/xvdg3      1574912 104857599 103282688 49.3G 8e Linux LVM
```

問題なければ ```w``` で保存！

```
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```
## 論理ボリュームを作成

縮小後サイズの見積もりで見積もった構成で論理ボリュームを作成します。
```vgcreate``` で論理ボリュームグループ、
```lvcreate``` で論理ボリュームを作成します。

ボリュームグループ名は仮の名前で作成します。
今回は ```vg00new``` にしています。

```
$ vgcreate vg00new /dev/xvdg3
$ lvcreate -n LV01 -L +12g vg00new 
$ lvcreate -n LV02 -L +8g vg00new 
$ lvcreate -n LV03 -L +10g vg00new 
$ lvcreate -n LV04 -L +10g vg00new 
$ lvcreate -n LV05 -l 100%FREE vg00new 
```

## 論理ボリュームをフォーマット
### SWAP領域以外
```
$ mkfs -t xfs /dev/mapper/vg00new-LV01
meta-data=/dev/mapper/vg00new-LV03 isize=512    agcount=4, agsize=655360 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0
data     =                       bsize=4096   blocks=2621440, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
```
```
$ mkfs -t xfs /dev/mapper/vg00new-LV03
meta-data=/dev/mapper/vg00new-LV03 isize=512    agcount=4, agsize=655360 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0
data     =                       bsize=4096   blocks=2621440, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
```
```
$ mkfs -t xfs /dev/mapper/vg00new-LV04
meta-data=/dev/mapper/vg00new-LV04 isize=512    agcount=4, agsize=655360 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0
data     =                       bsize=4096   blocks=2621440, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
```
```
$ mkfs -t xfs /dev/mapper/vg00new-LV05
meta-data=/dev/mapper/vg00new-LV05 isize=512    agcount=4, agsize=605952 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=1        finobt=1, sparse=0
data     =                       bsize=4096   blocks=2423808, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=1
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
```

### SWAP領域

SWAP領域の論理ボリュームはUUIDを指定しながら作成します。

```
$ mkswap -U "8c60f406-743d-9999-b7d9-91f2cbb8811f" /dev/mapper/vg00new-LV02
Setting up swapspace version 1, size = 8 GiB (8589930496 bytes)
no label, UUID=8c60f406-743d-9999-b7d9-91f2cbb8811f
```

### 作成したボリュームをアクティブにする

```vgchange``` でボリュームをアクティブにします。

```
$ vgchange -ay vg00new
  0 logical volume(s) in volume group "vg00" now active
```
## サイズ変更を行わないパーティションのコピー

サイズ変更を行わないパーティションは```dd```コマンドでコピーします。

```
$ dd if=/dev/xvdf1 of=/dev/xvdg1 bs=64k
8192+0 records in
8192+0 records out
536870912 bytes (537 MB) copied, 20.55 s, 26.1 MB/s
```
```
$ dd if=/dev/xvdf2 of=/dev/xvdg2 bs=64k
4096+0 records in
4096+0 records out
268435456 bytes (268 MB) copied, 9.6336 s, 27.9 MB/s
```

## サイズ変更を行うパーティションのコピー

サイズ変更を行うパーティションは```dd``` コマンドではなく、```cp``` コマンドなどで地道にコピーします。

マウントするディレクトリを作成します。

```
$ mkdir /mnt/from
$ mkdir /mnt/to
```

以下のコピーを LV01～LV05で繰り返します。
```/bin/cp -apr``` とすることで、所有者・権限を維持したままコピーを行います。

```
$ mount /dev/mapper/vg00-LV01 /mnt/from
$ mount /dev/mapper/vg00new-LV01 /mnt/to
$ /bin/cp -apr /mnt/from/. /mnt/to/
$ umount /dev/mapper/vg00-LV01
$ umount /dev/mapper/vg00new-LV01
```

## ボリュームグループ名とUUIDを変更する

縮小前のボリュームと同じVolumeGroup名とUUIDを、縮小後のボリュームに適用します。
※Linuxの構成(GRUB)上不要な場合もありますが、カーネルパラメータにボリュームのUUIDを指定している場合は、
ボリュームのUUIDやVG名を合わせるか、カーネルパラメータを合わせるかのいずれかの対応が必要になります。
これを実施しないとLinuxが起動できなくなります。

縮小前のボリュームグループをオフラインにしてEBSを取り外します。

```
$ vgchange -an vg00
```
```
$ aws ec2 detach-volume --instance-id i-************ --volume-id vol-***************
```

```vgrename``` でボリュームグループ名を変更します。

```
$ vgrename vg00new vg00
  Volume group "vg00new" successfully renamed to "vg00"
```

各LVMのUUIDを縮小前のEBSと同じUUIDに変更します。
SWAP領域についてはフォーマット時にUUIDを指定しているので、
それ以外の領域のボリュームのUUIDを変更します。

```
$ xfs_admin -U "f1417da0-b039-9999-9db7-ce241ee16e1b" /dev/mapper/vg00-LV01
Clearing log and setting UUID
writing all SBs
new UUID = f1417da0-b039-9999-9db7-ce241ee16e1b
```
```
$ xfs_admin -U "741063de-0f7c-9999-97d8-74f5966cb188" /dev/mapper/vg00-LV03
Clearing log and setting UUID
writing all SBs
new UUID = 741063de-0f7c-9999-97d8-74f5966cb188
```
```
$ xfs_admin -U "2876e402-35e0-9999-b3fb-375129dec539" /dev/mapper/vg00-LV04
Clearing log and setting UUID
writing all SBs
new UUID = 2876e402-35e0-9999-b3fb-375129dec539
```
```
$ xfs_admin -U "c3972330-190a-9999-bd60-d738e60c1f56" /dev/mapper/vg00-LV05
Clearing log and setting UUID
writing all SBs
new UUID = c3972330-190a-9999-bd60-d738e60c1f56
```

縮小後のボリュームグループをオフラインにしてEBSを取り外します。

```
$ vgchange -an vg00
```
```
$ aws ec2 detach-volume --instance-id i-0d31693fcfd15a78b --volume-id <vol--縮小後ボリューム>
```

# 起動して確認

縮小前のEBSを使用していたEC2インスタンスに縮小後EBSをアタッチして、起動してみます。
ログインできればとりあえずは縮小完了です！

ログインはできるけど、他のサービスが起動しないこともありますので、
起動後はEC2の状態をよく確認しましょう。