qcow2 をリサイズ(縮小)しメンテナンスやバックアップを行いやすくする。
qcow2 を必要以上にに巨大サイズで確保したので、とっても扱いにくい。qcow2 を小さくしたい。
今回やった手法は、ダイレクトにパーティションを書き換える方法だ。
ダイレクトにパーティションやイメージファイルを「縮小」(shrink)しようとするとLVMで引っかかってすごく大変だったのでメモとして残す。
前提
作業するファイル ubuntu.qcow2
ubuntu.qcow2はEFIパーティションを含むEFIブート用のGPTディスクである。
ubuntu.qcow2 はLVMで構成されている。
LVMは、ubuntu-vg/ubuntu-lv
の名前で構成している。
LVのubuntu-lv
には ubuntuがインストールされていて、4GBを消費している。LVのサイズは6GBで程度ある。
PVのサイズは8.5GBを確保している。
qcow2 のサイズは10GBである。
まとめると、10GBのディスクイメージに1.5Gのブート領域が確保され、残りの8.5GBでPVが構成され、PV内に6GB程度のLVが構成されている。LVはext4で4GBを消費している。つまり無駄が多い。適当なサイズで適当に作ったディスクイメージのため中途半端な容量になっていて、コピーやバックアップで無駄な時間を浪費するのが許せない。raspiのSDカード内部で使っているディスクイメージなので、少しでもサイズを減らせば作業時間が稼げる。
お急ぎの人は
LVMの構成があるので、ディスクイメージにをダイレクトに操作するのが、本当に面倒だった。お急ぎの人は、大小ディスクイメージを2つ接続してpvmoveするべき(記事末尾に記載)
実際の作業
## qcow2 を作業用に持ってくる。 pv ubuntu.qcow2 > work.qcow2 ## ループ・バックで接続する。 sudo qemu-nbd --connect=/dev/nbd0 ~/work.qcow2 ## ext4 をリサイズ(縮小) sudo fsck.ext4 -f /dev/mapper/ubuntu--vg-ubuntu--lv sudo resize2fs -p /dev/ubuntu-vg/ubuntu-lv 5G
リサイズ(resize2fs)は時間がかかるので、この状態を保存しておく
## mapper を確認 sudo dmsetup ls ## lvm を取り外し sudo dmsetup remove ubuntu--vg-ubuntu--lv ## nbd ループバックを取り外し sudo qemu-nbd --disconnect /dev/nbd0 ## ファイルをコピー pv work.qcow2 > work.resized.qcow2 ## 以降の作業でミスった場合はリサイズ後からやり直す ## やり直すばあい ## pv work.resized.qcow2 > work.qcow2 ## 再接続 / ループ・バックで接続する。 sudo qemu-nbd --connect=/dev/nbd0 ~/work.qcow2
LV を操作する
## LVS をリサイズ sudo lvresize ubuntu-vg/ubuntu-lv --resizefs -L 5G
--resizefs
は念の為。すでにresize2fsは済ませたので時間的ロスはないので、念の為に書いただけ。
VG/LVの状態を確認する。
## LVの状態 sudo lvs ubuntu-vg/ubuntu-lv LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert ubuntu-lv ubuntu-vg -wi-a----- 5.00g ## VGの状態 sudo vgs ubuntu-vg VG #PV #LV #SN Attr VSize VFree ubuntu-vg 1 1 0 wz--n- <8.50g <3.50g ## PVの状態 sudo pvs /dev/nbd0p3 PV VG Fmt Attr PSize PFree /dev/nbd0p3 ubuntu-vg lvm2 a-- <8.50g <3.50g
PVのサイズを変更する
PVのサイズは、自動的に決まるはずなので、自動的に決まらないようにする必要がある。
pvの状況を確認する PEは4MiBである
sudo pvdisplay /dev/nbd0p3 --- Physical volume --- PV Name /dev/nbd0p3 VG Name ubuntu-vg PV Size <8.50 GiB / not usable 2.00 MiB Allocatable yes PE Size 4.00 MiB Total PE 2175 Free PE 895 Allocated PE 1280 PV UUID YDqRlT-iObR-A8qn-Jhd9-QHno-Ivlb-Fi1lte
メタデータの量を確認
sudo pvck /dev/nbd0p3 Found label on /dev/nbd0p3, sector 1, type=LVM2 001 Found text metadata area: offset=4096, size=1044480
これらから、次のことがわかる。
PEは2175PEを確保している。メタデータは1044480バイトを確保されている。
PEのサイズとバイト数
PE( Physical Extent ) は4Mib ( 4* 1024 * 1024 ) で定義されている
1PE=4Mib
確保されているPEは 2175PEなので
2175PE ⇔ 2175*4*1024**2 bytes ⇔ 9122611200 bytes ⇔ ≒ 8.5Gb
これを5.4GBにリサイズしようと思うと1383PEが必要になる。
5.4GB ⇔ 5.4*1024**3 bytes ⇔ 1382.4 PE ⇔ ≒1383 PE
ただし、メタデータが含まれるため、メタデータ分だけ容量は減る。metadata の容量はpvck で確認した値である。
sudo pvck /dev/nbd0p3 Found label on /dev/nbd0p3, sector 1, type=LVM2 001 Found text metadata area: offset=4096, size=1044480
新しいPVのサイズを計算する。
PVサイズはディスクのパーティションのサイズですから、パーティションのサイズはセクタ単位で計算されるので、セクタ数を調べる。
sudo sgdisk -p /dev/nbd0
出力から、512 bytes=1セクタであるとわかる。
Disk /dev/nbd0: 20971520 sectors, 10.0 GiB Sector size (logical/physical): 512/512 bytes Disk identifier (GUID): BDA3DC0C-F094-455B-965F-6546444E422C Partition table holds up to 128 entries Main partition table begins at sector 2 and ends at sector 33 First usable sector is 34, last usable sector is 20971486 Partitions will be aligned on 2048-sector boundaries Total free space is 4029 sectors (2.0 MiB) Number Start (sector) End (sector) Size Code Name 1 2048 1050623 512.0 MiB EF00 2 1050624 3147775 1024.0 MiB 8300 3 3147776 20969471 8.5 GiB 8300
5.4G程度確保しようと思うと次のような計算になった
⇔ 確保したい容量+メタデータ量 ⇔ ((5*1024**3+410*1024**2)+1044480) bytes ⇔ 5799669760 ⇔ 11327480 sector ( 1 sector = 512 bytes )
この計算に沿ってgdisk で容量を変更する
sudo dmsetup remove ubuntu--vg-ubuntu--lv sudo gdisk /dev/nbd0
パーティションを+11327480セクタ
で作り直し
Command (? for help): p ## 確認 Disk /dev/nbd0: 20971520 sectors, 10.0 GiB Number Start (sector) End (sector) Size Code Name 1 2048 1050623 512.0 MiB EF00 2 1050624 3147775 1024.0 MiB 8300 3 3147776 20969471 8.5 GiB 8300 ## 削除 Command (? for help): d Partition number (1-3): 3 ## 作り直し Command (? for help): n Partition number (3-128, default 3): First sector (34-20971486, default = 3147776) or {+-}size{KMGTP}: Last sector (3147776-20971486, default = 20971486) or {+-}size{KMGTP}: +11327480 Current type is 8300 (Linux filesystem) Hex code or GUID (L to show codes, Enter = 8300): Changed type of partition to 'Linux filesystem' ## 確認 Command (? for help): p Number Start (sector) End (sector) Size Code Name 1 2048 1050623 512.0 MiB EF00 2 1050624 3147775 1024.0 MiB 8300 3 3147776 14475255 5.4 GiB 8300 Linux filesystem ## 書き込み Command (? for help): w
pvの設定サイズより小さくなったので、PEを読めなくてエラーになる。
sudo pvs /dev/nbd0p3 WARNING: Device /dev/nbd0p3 has size of 11327480 sectors which is smaller than corresponding PV size of 17821696 sectors. Was device resized? WARNING: One or more devices used as PVs in VG ubuntu-vg have changed sizes. PV VG Fmt Attr PSize PFree /dev/nbd0p3 ubuntu-vg lvm2 a-- <8.50g <3.50g
LVM の構造はキャッシュされるので一旦削除
ubuntu-vg という名前で /etc/lvm/{backup,archive}
されているので削除する。
## 切断する sudo qemu-nbd --disconnect /dev/nbd0 ## LVMの既知レイアウトのキャッシュ削除 sudo grep ubuntu-vg /etc/lvm -rl | xargs sudo rm ### 再接続する sudo qemu-nbd --connect=/dev/nbd0 ~/work.qcow2
これでもまだエラーになる場合
sudo pvs /dev/nbd0p3 WARNING: Device /dev/nbd0p3 has size of 11327480 sectors which is smaller than corresponding PV size of 17821696 sectors. Was device resized? WARNING: One or more devices used as PVs in VG ubuntu-vg have changed sizes. PV VG Fmt Attr PSize PFree /dev/nbd0p3 ubuntu-vg lvm2 a-- <8.50g <3.50g
PV のサイズを強制的に変更する
エラーメッセージから現在のPVサイズが分かる
Device /dev/nbd0p3 has size of 11327480 sectors which is smaller than corresponding PV size of 17821696 sectors.
現在のPVは11327480 sectors
であることがわかる。
セクタをバイト数に変換する。
11327480 sectrors ⇔ 11327480*512 bytes ⇔ 5799669760 bytes
バイト数で PVの設定を作り直し
sudo pvresize --setphysicalvolumesize=5799669760b /dev/nbd0p3
作り直したら読み込みし直す
sudo dmsetup remove ubuntu--vg-ubuntu--lv sudo qemu-nbd --disconnect /dev/nbd0 sudo qemu-nbd --connect=/dev/nbd0 ~/work.qcow2
pv を確認する。
sudo pvs /dev/nbd0p3 PV VG Fmt Attr PSize PFree /dev/nbd0p3 ubuntu-vg lvm2 a-- <5.40g 408.00m
細かい計算ミスをresize max で補う
LVとext4 は目標とするpvサイズより少量で確保したので、PVサイズに合わせてリサイズしておく。 現在のLVとPV
lsblk /dev/nbd0 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS nbd0 43:0 0 10G 0 disk ├─nbd0p1 43:1 0 512M 0 part ├─nbd0p2 43:2 0 1G 0 part └─nbd0p3 43:3 0 5.4G 0 part └─ubuntu--vg-ubuntu--lv 253:4 0 5G 0 lvm
最初に若干小さめにLVをリサイズしておいたので、PVよりLVが小さくなっており、500MB弱余っている。(512bytes=1sector 単位かつ、4Mib=1PEで整数倍のバイト数に揃える必要があり、計算が面倒になった。メタデータのこともあるので最初にLVを少なめにリサイズした。)
sudo lvresize -l +100%FREE ubuntu-vg/ubuntu-lv sudo fsck.ext4 -f /dev/mapper/ubuntu--vg-ubuntu--lv sudo resize2fs -p /dev/ubuntu-vg/ubuntu-lv
計算ミスを追いかけるのも面倒だし、メタデータのサイズも面倒なので、LV/ext4を小さくとって、PVを正しく設定した、PVはちゃんとLVを包含できたのを確認して、PVのサイズのMAXまでresize max して、無事に完了
PVチェック
lsblk /dev/nbd0 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS nbd0 43:0 0 10G 0 disk ├─nbd0p1 43:1 0 512M 0 part ├─nbd0p2 43:2 0 1G 0 part └─nbd0p3 43:3 0 5.4G 0 part └─ubuntu--vg-ubuntu--lv 253:4 0 5.4G 0 lvm
これで、PVは5.4Gに切りそろえることができた。
この状態を保存しておく
sudo dmsetup remove ubuntu--vg-ubuntu--lv sudo qemu-nbd --disconnect /dev/nbd0 pv work.qcow2 > work.PVresized.qcow2 ## 戻すときは # pv work.PVresized.qcow2 > work.qcow2
qcow2 を縮小する
新しいディスクに必要なサイズを計算する
sgdisk -p /dev/nbd0
一番うしろのパーティションのセクタ位置を確認する
Number Start (sector) End (sector) Size Code Name 1 2048 1050623 512.0 MiB EF00 2 1050624 3147775 1024.0 MiB 8300 3 3147776 14475255 5.4 GiB 8300 Linux filesystem
最終セクタまでのバイト数を見る
14475255 セクタ ⇔ 14475255 * 512 バイト ⇔ 7411330560.0 bytes
つまり、7411330560バイトのサイズにqcow2をリサイズすればいいとわかる。 ただ、バックアップパーティションテーブルも必要なので少し余裕をもたせておく。 7411330560は6.9GBなので、7GB(=7516192768b)確保することにする。
qemu-img resize --shrink work.qcow2 7516192768b
sudo qemu-nbd --connect=/dev/nbd0 ~/work.qcow2 sudo sgdisk -p /dev/nbd0
Warning! Disk size is smaller than the main header indicates! Loading secondary header from the last sector of the disk! You should use 'v' to verify disk integrity, and perhaps options on the experts' menu to repair the disk. Caution: invalid backup GPT header, but valid main header; regenerating backup header from main header. Warning! One or more CRCs don't match. You should repair the disk! Main header: OK Backup header: ERROR Main partition table: OK Backup partition table: ERROR **************************************************************************** Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk verification and recovery are STRONGLY recommended. **************************************************************************** Disk /dev/nbd0: 14680064 sectors, 7.0 GiB
パーティションテーブルを書き換える
Command (? for help): w Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING PARTITIONS!! Do you want to proceed? (Y/N): y OK; writing new GUID partition table (GPT) to /dev/nbd0. The operation has completed successfully.
書き換えたパーティションテーブルの値に沿ってPVを最終調整
sudo sgdisk -p /dev/nbd0 Number Start (sector) End (sector) Size Code Name 1 2048 1050623 512.0 MiB EF00 2 1050624 3147775 1024.0 MiB 8300 3 3147776 14680030 5.5 GiB 8300 Linux filesystem
パーティションのサイズからバイト数を計算
14680030-3147776 ⇔ 11532254 セクタ ⇔ 11532254 * 512 バイト ⇔ 5904514048 バイト
### リサイズ sudo pvresize --setphysicalvolumesize=5904514048b /dev/nbd0p3 ## 再接続 sudo dmsetup remove ubuntu--vg-ubuntu--lv sudo qemu-nbd --disconnect /dev/nbd0 sudo qemu-nbd --connect=/dev/nbd0 ~/work.qcow2 ## リサイズの結果を確認 sudo pvs
リサイズの結果、qemu-img resize で 100Mの余分が出ていた
PV VG Fmt Attr PSize PFree /dev/mapper/crypted-root vg.main lvm2 a-- <111.27g <46.27g /dev/nbd0p3 ubuntu-vg lvm2 a-- <5.50g 100.00m
resize max して反映する
sudo lvresize -l +100%free ubuntu-vg/ubuntu-lv sudo resize2fs -p /dev/ubuntu-vg/ubuntu-lv
最終チェック
ブロックデバイスの状況を見る。
lsblk /dev/nbd0 NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS nbd0 43:0 0 7G 0 disk ├─nbd0p1 43:1 0 512M 0 part ├─nbd0p2 43:2 0 1G 0 part └─nbd0p3 43:3 0 5.5G 0 part └─ubuntu--vg-ubuntu--lv 253:4 0 5.5G 0 lvm
LVMのPV / VG / LV を確認する。
$ sudo pvs /dev/nbd0p3 PV VG Fmt Attr PSize PFree /dev/nbd0p3 ubuntu-vg lvm2 a-- <5.50g 0 $ sudo vgs ubuntu-vg VG #PV #LV #SN Attr VSize VFree ubuntu-vg 1 1 0 wz--n- <5.50g 0 $ sudo lvs ubuntu-vg LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert ubuntu-lv ubuntu-vg -wi-a----- <5.50g
マウントしてみる。
$ sudo mount /dev/mapper/ubuntu--vg-ubuntu--lv /mnt $ df -h /mnt Filesystem Size Used Avail Use% Mounted on /dev/mapper/ubuntu--vg-ubuntu--lv 5.4G 4.0G 1.1G 79% /mnt $ sudo umount /mnt
サイズもマウントも、OKだった。
やってみて
正確に計算すると、ちゃんと確実に終わるんだろうけど、PEサイズやセクタサイズなど気にするところがあって、正確な計算やりきりるのは面倒だった。やりながら考えていると、計算が合わなくなったり、メタデータサイズに気づかなかったりパーティションのサイズとかでミスが頻発して心が折れそうになった。
なれないことは、やるもんじゃない。
別解
pvmove という便利なコマンドがある。
2つのディスクにまたがったシンプルボリュームをLVMで構成することができる。
2つのディスクを接続し、VGを構成しておけば、あとは pvmove で古いディスクを取り外すことができる。
これをつかえば、バイトやセクタのサイズを気にすることなく、LVを別ディスクに移動することができる。PVのディスクの縮小ではpvmoveを使うべき。
pvcreate /dev/nbd1p3 #新しいディスクをPVへ追加 pvmove /dev/nbd1p3 # 新しいディスクへデータを移動 vgreduce vg-name /dev/nbd0p3 # 古いディスクを除去 pvremove /dev/nbd0p3 # 古いディスクを除去 resize2fs /dev/mapper/vg-name-lvname
他に言えること。バックアップや移動がめんどくさいと思うようになったら、qcow2+kvm を諦めて、lxcに変えるべきなのかもしれない。lvmが面倒の原因なのでbtrfs にしてしまうのもありかもしれない。