schedule2020-04-14

CentOS7(ファイルシステムxfs)のEBSのボリュームを小さくした

CentOS7のEBSのボリュームを小さくするのがかなり大変だったので、備忘録として残します。 ほぼEC2 EBS縮小 (というより CentOS ディスク縮小) の流れの通り進めています。 自分の知らなかった部分を補足しました。

EBSは簡単に大きくできるが小さくするのは大変

Elastic Block Store(EBS)はEC2の仮想的な記憶領域で、柔軟に容量を増やしたりスナップショットを取ってバックアップや複製が簡単に出来ます。 ただし、一度大きくしたEBSを小さくすることはできません。 これから新しく作成してAMIに登録する場合は、小さめのボリュームにしておくことをお勧めします。

ebs

では、どうやって小さくするかというと、新しく小さいボリュームのEBSを用意してそこにコピーすることでEBSのボリュームを小さくできます。 EC2のルートデバイスとして認識させる必要があるため、パーティションの設定も正しく行います。

標準ファイルシステム ext4とxfs

ボリュームのコピーは標準ファイルシステムによってコマンドが異なるので注意してください。

CentOS7のファイルシステムはxfsで、この記事はそのコピーの方法で進めます。 同じくxfsのOSはAmazon Linux2、Red Hat Enterprise Linux 7など。 対してext4のOSはCentOS6、Amazon Linux、そしてUbuntuです。

ext4のボリューム縮小は参考1: Amazon EC2ルートボリュームのサイズを縮小してみたを参照されると分かり安いと思います。

xfsはほぼ参考2: EC2 EBS縮小 (というより CentOS ディスク縮小) の流れの通り進めました。

CentOS7のEBSのボリュームを小さくする

AMIで利用しやすいように、200GBのボリュームから20GBへ小さくしました。 OS+ミドルウェアで4GB、swap領域で数GB使っていたので最小を20GBとしています。

参考1に倣って言葉の定義をします。

  • 新EBSボリューム:新規起動したEC2インスタンスのEBSルートボリューム
  • 旧EBSボリューム:縮小対象EC2インスタンスのEBSルートボリューム

手順は次の通り。

  1. 任意の作業用EC2インスタンスに新EBSボリュームと旧EBSボリュームをアタッチする
  2. 新EBSボリュームのパーティションを設定する
  3. 新旧EBSボリュームをマウントする
  4. 新EBSボリュームを旧EBSボリュームと同期する
  5. ボリュームを取り外す
  6. EC2にアタッチして起動する

1. 任意の作業用EC2インスタンスに新EBSボリュームと旧EBSボリュームをアタッチする

EBSをコピーするために新旧EBSボリュームを別の作業用EC2にアタッチします。 作業用EC2はOSがAmazon Linux2です。 インスタンスタイプはt3.microで十分でした。

アタッチ後のブロックデバイス一覧。

# lsblk
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  200G  0 disk <-旧EBSボリューム
└─xvdf1 202:81   0  200G  0 part
xvdg    202:96   0   20G  0 disk <-新EBSボリューム

xvdfが旧EBSボリュームでxvdgが新EBSボリュームです。

2. 新EBSボリュームのパーティションを設定する

新EBSボリュームにパーティションxvdg1を作ります。 (パーティション内状態でコピーしたら、EC2がルートデバイスとして認識してくれなかった)

# fdisk /dev/xvdg

fdisk (util-linux 2.30.2) へようこそ。
ここで設定した内容は、書き込みコマンドを実行するまでメモリのみに保持されます。
書き込みコマンドを使用する際は、注意して実行してください。

古い xfs 署名は write (書き込み)コマンドを実行すると消えてしまいます。

デバイスには認識可能なパーティション情報が含まれていません。
新しい DOS ディスクラベルを作成しました。識別子は 0x3800409a です。

コマンド (m でヘルプ): n
パーティションタイプ
   p   基本パーティション (0 プライマリ, 0 拡張, 4 空き)
   e   拡張領域 (論理パーティションが入ります)
選択 (既定値 p): p
パーティション番号 (1-4, 既定値 1): 1
最初のセクタ (2048-41943039, 既定値 2048):
最終セクタ, +セクタ番号 または +サイズ{K,M,G,T,P} (2048-41943039, 既定値 41943039):

新しいパーティション 1 をタイプ Linux、サイズ 20 GiB で作成しました。

コマンド (m でヘルプ): a
パーティション 1 を選択
パーティション 1 の起動フラグを有効にしました。

コマンド (m でヘルプ): p
ディスク /dev/xvdg: 20 GiB, 21474836480 バイト, 41943040 セクタ
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスクラベルのタイプ: dos
ディスク識別子: 0x3800409a

デバイス   起動 開始位置 最後から   セクタ サイズ Id タイプ
/dev/xvdg1 *        2048 41943039 41940992    20G 83 Linux

コマンド (m でヘルプ): w
パーティション情報が変更されました。

設定が日本語になっていた。 n -> p -> 1 -> a -> wでディスクサイズと同じ大きさのパーティションxvdg1ができる。 mでヘルプが見れます。

1度目はパーティション情報の書き込みで失敗している。 下はその時のログ。 再起動してもう一度実行したら成功しました。

コマンド (m でヘルプ): w
パーティション情報が変更されました。
ioctl() を呼び出してパーティション情報を再読み込みします。
パーティション情報の再読み込みに失敗しました。: Device or resource busy

カーネルは古い情報を使用しています。新しい情報を利用するには、システムを再起動するか、もしくは partprobe(8) または kpartx(8) を実行してください。

縮小前後(xvdf/xvdg)で同様の設定になっている事を確認します。

# fdisk -l
ディスク /dev/xvda: 8 GiB, 8589934592 バイト, 16777216 セクタ
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスクラベルのタイプ: gpt
ディスク識別子: 83181C97-6D5E-43C9-9EDE-E2F50EAD5338

デバイス     開始位置 最後から   セクタ サイズ タイプ
/dev/xvda1       4096 16777182 16773087     8G Linux ファイルシステム
/dev/xvda128     2048     4095     2048     1M BIOS 起動

パーティション情報の項目がディスクの順序と一致しません。


ディスク /dev/xvdg: 20 GiB, 21474836480 バイト, 41943040 セクタ
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスクラベルのタイプ: dos
ディスク識別子: 0x3800409a

デバイス   起動 開始位置 最後から   セクタ サイズ Id タイプ
/dev/xvdg1 *        2048 41943039 41940992    20G 83 Linux


ディスク /dev/xvdf: 200 GiB, 214748364800 バイト, 419430400 セクタ
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスクラベルのタイプ: dos
ディスク識別子: 0x000aec37

デバイス   起動 開始位置  最後から    セクタ サイズ Id タイプ
/dev/xvdf1 *        2048 419430366 419428319   200G 83 Linux

3. 新旧EBSボリュームをマウントする

# mkdir -p /mnt/old /mnt/new/boot
# mount -t xfs /dev/xvdf1 /mnt/old
# mount -t xfs /dev/xvdg1 /mnt/new

# lsblk
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  200G  0 disk
└─xvdf1 202:81   0  200G  0 part /mnt/old <-旧EBSボリューム
xvdg    202:96   0   20G  0 disk 
└─xvdg1 202:97   0   20G  0 part /mnt/new <-新EBSボリューム

4. 新EBSボリュームを旧EBSボリュームと同期する

この辺りから自分の言葉で表せない、申し訳ないが参考の手順とその時の出力をのせる。

xfs を扱うためのパッケージをインストールしておきます。

  • xfsdump: XFSファイルシステムをバックアップするために、指定した場所にコピーするコマンド
  • xfsprogs: xfsdumpのバックアップからファイルを復元するコマンド インストールコマンド: yum install xfsprogs xfsdump

容量により時間が掛かるのでバックグラウンド実行しておきます。

# cd /mnt/old/
( LANG=C date; nohup xfsdump -J - /mnt/old \
  | xfsrestore -J -p 60 - /mnt/new ; date \
) > /tmp/disk-sync.log 2>&1  < /dev/null &

# ログ
# tail -f /tmp/disk-sync.log
xfsrestore: media label: ""
xfsrestore: file system id: 0f790447-ebef-4ca0-b229-d0aa1985d57f
xfsrestore: session id: 606c299e-31bf-4de9-9bff-36538c642a89
xfsrestore: media id: dafc54f9-af51-4412-88d3-32cfe9298f5d
xfsrestore: searching media for directory dump
xfsrestore: reading directories
xfsdump: dumping non-directory files
xfsrestore: 21868 directories and 127203 entries processed
xfsrestore: directory post-processing
xfsrestore: restoring non-directory files
xfsrestore: status at 10:06:38: 42584/98461 files restored, 47.9% complete, 60 seconds elapsed
xfsdump: ending media file
xfsdump: media file size 4563930720 bytes
xfsdump: dump size (non-dir files) : 4521594712 bytes
xfsdump: dump complete: 111 seconds elapsed
xfsdump: Dump Status: SUCCESS
xfsrestore: restore complete: 112 seconds elapsed
xfsrestore: Restore Status: SUCCESS
202049日 木曜日 10:07:30 UTC


^C[1]+  終了                  ( LANG=C date; nohup xfsdump -J - /mnt/old | xfsrestore -J -p 60 - /mnt/new; date ) > /tmp/disk-sync.log 2>&1 < /dev/null
  1. grubインストール chroot OS起動時に作成されるディレクトリ群をマウントした後、 /mnt/new/ に対して chroot します。 (chroot した事を確認するためにログファイルコピーを行っていますが、必須ではありません。)
[root@ip-172-31-19-210 old]# cp -ip /tmp/disk-sync.log /mnt/new/var/log/
[root@ip-172-31-19-210 old]# gzip /mnt/new/var/log/disk-sync.log
[root@ip-172-31-19-210 old]# ls -l /mnt/new/var/log/disk-sync.log*
-rw-r--r-- 1 root root 820  49 10:07 /mnt/new/var/log/disk-sync.log.gz
[root@ip-172-31-19-210 old]# mount -t proc /proc /mnt/new/proc
[root@ip-172-31-19-210 old]# mount -t sysfs /sys /mnt/new/sys
[root@ip-172-31-19-210 old]# mount --bind /dev /mnt/new/dev
[root@ip-172-31-19-210 old]# chroot /mnt/new/
[root@ip-172-31-19-210 /]# ls -l /var/log/disk-sync.log.gz
-rw-r--r-- 1 root root 820  49 19:07 /var/log/disk-sync.log.gz
[root@ip-172-31-19-210 /]# 

grub xfs

[root@ip-172-31-19-210 /]# grub2-mkconfig -o /boot/grub2/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-3.10.0-1062.9.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-1062.9.1.el7.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-229.14.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-229.14.1.el7.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-229.4.2.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-229.4.2.el7.x86_64.img
Found linux image: /boot/vmlinuz-3.10.0-123.8.1.el7.x86_64
Found initrd image: /boot/initramfs-3.10.0-123.8.1.el7.x86_64.img
Found linux image: /boot/vmlinuz-0-rescue-f9afeb75a5a382dce8269887a67fbf58
Found initrd image: /boot/initramfs-0-rescue-f9afeb75a5a382dce8269887a67fbf58.img
done
[root@ip-172-31-19-210 /]# grub2-install /dev/xvdg
Installing for i386-pc platform.
Installation finished. No error reported.
  1. fstab/grub.conf 書き換え fstab 、grub.conf に UUID 指定がある場合は、書き換えを行います。 (CentOS6 には grub-mkconfig が無いようなので grub.conf は直接書き換えています。) xfs UUID指定部分を書き換えます。 CentOS7 では grub2 が導入済みのようなので /etc/grub/ ではなく、 /etc/grub2/ が使用されます。
[root@ip-172-31-19-210 /]# blkid | grep xvdg
/dev/xvdg1: UUID="80ef9b35-2d25-430c-a753-5f6bbc2955e5" TYPE="xfs"
[root@ip-172-31-19-210 /]#  cp -ip /etc/fstab /etc/fstab.org
[root@ip-172-31-19-210 /]# vi /etc/fstab
# diff /etc/fstab.org /etc/fstab
9c9
< UUID=0f790447-ebef-4ca0-b229-d0aa1985d57f /                       xfs     defaults        1 1
---
> UUID=80ef9b35-2d25-430c-a753-5f6bbc2955e5 /                       xfs     defaults        1 1

# chrootを抜ける
[root@ip-172-31-19-210 /]# exit
exit

5. ボリュームを取り外す

アンマウント

procsysdevもアンマウントしておく。

[root@ip-172-31-19-210 old]# cd /
[root@ip-172-31-19-210 /]# umount /mnt/old/
[root@ip-172-31-19-210 /]# umount /mnt/new/proc /mnt/new/sys /mnt/new/dev
[root@ip-172-31-19-210 /]# umount /mnt/new/
[root@ip-172-31-19-210 /]# mount -l | grep "old\|new"

ディスク内容の移行が完了したら、 作業用インスタンスから Volume をデタッチして後続作業を行います。

インスタンスを停止して、デタッチ。

6. EC2にアタッチして起動する

EC2の /dev/sda1 にアタッチする。

※ デバイス名が/dev/sdaだとエラーで/dev/sdfだとルートデバイスとして認識しなかった。

# sshでEC2に接続

$ df -h
df: `/s3': 通信端点が接続されていません
ファイルシス   サイズ  使用  残り 使用% マウント位置
devtmpfs         472M     0  472M    0% /dev
tmpfs            495M     0  495M    0% /dev/shm
tmpfs            495M   13M  482M    3% /run
tmpfs            495M     0  495M    0% /sys/fs/cgroup
/dev/xvda1        20G  4.5G   16G   23% /
tmpfs             99M     0   99M    0% /run/user/1001

いえーあー

AMIに登録して失くさないようにする。

参考