# How to shrink Byteplus EBS system volume

As almost every cloud engineer knows, cloud instance EBS storage volume is only easily expandable, but not allowed to shrink, but still, there are actually some way to achieve this, if you think the process is more worth it than reinstall everything on a new instance ^\_^

OK, about how to shrink a EBS root volume on AWS Amazon Linux 2 / 2023 with default disk format XFS, Benedikt Langens already shared [here on medium](https://medium.com/%40benedikt.langens/how-to-shrink-an-ebs-root-volume-xfs-on-amazon-linux-2-2023-a7705c16e839) 3 years ago and I verified it's working on Amazon Linux 2 last year.

But for Byteplus, unlike AWS, EBS storage volume is separated into system volume and data volume, you can't attach a data volume to an instance to boot it up.

Byteplus default system volume format is ext4, and they allow export to and import from qcow2 virtual disk format for custom images, so how to manipulate the partition / GPT data of the qcow2 file would be the trick.

## create qcow2 file of the system volume

create snapshot from system volume

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/94039ab5-8e9f-42e4-82fa-0a1d640362b7.png align="center")

then create custom image from the snapshot

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/9f8b3426-1e0e-4f10-a0f4-6ecd39b0b940.png align="center")

then export the image to a TOS bucket

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/87ff2c9d-a4a7-4d6f-99d4-d22febd2af62.png align="center")

and we got the qcow2 virtual image

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/72586d70-6cd8-4385-bff0-9d2522a74f63.png align="center")

the origin volume is 40GB, the qcow2 file exported to TOS is around 16GB size, our target is making it as a 20GB volume, which is smallest size Byteplus EBS volume allows.

## manipulating the qcow2 file

First we can download the qcow2 to a linux instance (I am using centos9) with AWS CLI, we can install qemu tools then check the info of the qcow2 file

```bash
sudo dnf install qemu-kvm
qemu-img info test.qcow2
```

Here we can see "virtual size: 40GiB"

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/855549d8-87f3-4eca-8584-5b4b7e550a28.png align="center")

Next we are gonna connect the qcow2 to the linux instance with network block device

```bash
modprobe nbd
lsblk
```

In lsblk will see /dev/nbd0, /dev/nbd1, etc, these are network block devices.

connect the qcow2 image file to /dev/nbd0 so we can check the detail of partition and GPT.

```bash
qemu-nbd --connect=/dev/nbd0 test.qcow2
lsblk
lsblk -f /dev/nbd0
parted /dev/nbd0 unit MiB print
```

lsblk will show 2 partitions appear under /dev/nbd0, it's a GPT disk and come with 2 partition , one is EFI and another is ext4

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/9422e488-bbf7-497a-9f4b-27be78207482.png align="center")

### Calculate the new size of the volume

With the information we got above, now we are gonna calculate the new size for new virtual image file, we gonna wize d

```bash
dumpe2fs -h /dev/nbd0p2  | grep 'Block'
```

We got

```text
Block count:              10434299
Block size:               4096
```

10434299 \* 4096 / 1024^3 = 39.8 GiB, this is our origin volume size 40GB, now we know each Block is 4096 Byte on this volume.

Now we want to know how many data actually on the volume

```bash
resize2fs -P /dev/nbd0p2
```

We got

```text
Estimated minimum size of the filesystem: 2836637
```

2836637 \* 4096 / 1024^3 = 10.82 GiB,

so here are what we gonna do:

- the new volume size will be 20 GiB = 20\* 1024 = 20480 MiB
- resize the ext4 filesystem to 18 GiB = 18 \* 1024 = 18432 MiB, larger than 10.82 GiB from "resize2fs -P" above
- Since EFI partition size 200MiB, 2 partition total will be 200 + 18432 = 18632 MiB
- The end position of partition 2 will be set to 20300MiB , because backup GPT header will be at the last sector of the disk, so as long as it is larger than the last block of ext4 partition and smaller than the volume size , we should be safe.
- 20480 MiB - 20300 MiB = 180 MiB, this will be free space including GPT header backup at the last sector.

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/000cf780-78df-49dc-a749-58e388e1231c.png align="center")

### Resize the ext4 partition

First we check the partition

```bash
e2fsck -f /dev/nbd0p2
```

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/2e1ff53e-90df-4814-bffa-bfdf1511a65d.png align="center")

The error is because of we create the snapshot when instance still running, safe to fix.

then we resize with

```bash
resize2fs /dev/nbd0p2 18G
```

This 18G here default unit meaning is GiB

```bash
dumpe2fs -h /dev/nbd0p2  | grep 'Block'
```

the result change to

```text
Block count:              4718592
Block size:               4096
```

4718592 \* 4096 / 1024^3 = 18 GiB

### resize the GPT part

```bash
parted /dev/nbd0
```

these the command we will use

```text
unit MiB
print
resizepart 2 20300MiB
```

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/1ac660b1-d0d9-43e0-bd07-afa15a872744.png align="center")

Notice, the default unit of "parted" is MB/GB, which is 1000x1000 and allow fuzzy, MiB and GiB is 1024x1024, which is more accurate in "parted" tool for disk exact location.

after that, we can run

```bash
partprobe /dev/nbd0
sync
```

to make sure the change take effect and written to disk

check again with

```bash
lsblk -o NAME,SIZE,FSTYPE,TYPE,MOUNTPOINTS /dev/nbd0
e2fsck -f /dev/nbd0p2
```

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/f085d5af-cfca-4037-bdc9-a902dd5d8697.png align="center")

### Change qcow2 image virtual size

first we disconect it

```bash
qemu-nbd --disconnect /dev/nbd0
lsblk /dev/nbd0
```

resize

```bash
qemu-img resize --shrink -f qcow2 test.qcow2 20G
```

the 20G here default unit is 20GiB.

check again with "qemu-img info test.qcow2".

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/fd3bf119-7146-40a0-b9d2-4b6d9b8c4981.png align="center")

### rebuild the GPT backup header

Because last step we shrink the virtual size of the qcow2 image, GPT backup header at the last sector of the disk would be gone, we would need to rebuild it

Connect the qcow2 again, because we used /dev/nbd0 earlier, I suggest using /dev/nbd1 this time, to avoid any info conflict in system.

```bash
qemu-nbd --connect=/dev/nbd1 test.qcow2
sgdisk -v /dev/nbd1
sgdisk -p /dev/nbd1
```

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/4d179b41-2504-4bb5-8b9d-8917303472ee.png align="center")

sgdisk -v will report problem

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/0849a5e4-d4f1-4220-b309-5e635925846f.png align="center")

sgdisk -p will show us there are total 41943040 sector with the last sector of partition 2 is 41574399, we are safe to rebuild the GPT backup header.

let sgdisk fix the GPT backup header

```bash
sgdisk -e /dev/nbd1
```

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/f0a34ec3-1f78-49d8-a7ce-f264f01c0b04.png align="center")

now we are done , we can run any checking command we used earluer to confirm the result

```bash
parted /dev/nbd1 unit MiB print
sgdisk -p /dev/nbd1
e2fsck -fn /dev/nbd1p2
lsblk -f /dev/nbd1
sgdisk -v /dev/nbd1
```

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/c62bbedf-4e32-4dbb-bd49-bc148b1b7854.png align="center")

Now we can disconnect the qcow2 with "qemu-nbd --disconnect /dev/nbd1" and upload it again to TOS bucket.

## import the new qcow2 file

Copy the qcow2 https:// address from file detail in the TOS console,

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/af5287bf-80f6-4565-9a08-fd322dcc5016.png align="center")

Remember to choose "UEFI" startup mode when importing.

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/289f3eb5-95cf-40a5-a89e-fe7f66bb0bda.png align="center")

The image size showing 20GB now.

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/26cc8c12-1c95-4e66-82d4-d61f21383f38.png align="center")

Next we can create instance with this new custom image

If the new instance can not connect with SSH after boot up, check the VNC, it may showing this,

![](https://cdn.hashnode.com/uploads/covers/6abb8716f8723f611bf052fc/0a4e2103-e93a-495e-82d1-e47e559fcfa8.png align="center")

that is because the new custom image startup mode chosen as "BIOS", which is a default option,

Click the image name, change startup mode to UEFI, re-create a new instance from it, all should be fine now.

Above is the disk info in new instance, can see all disk usage are normal as new, so don't worry about the process wasted some space there, and I tried volume expanding working as usual too.

## Summary

In short, with exporting / manipulating / importing qcow2 virtual image files, we can shrink a EBS volume which doesn't provided by the cloud provider.

In fact, there was a case of an instance failed to boot up because of initramfs file missing after resize instance, I used the same way fix it while Byteplus support tell me have to copy everything out to new instance from snapshot.

BTW, this way should also works for Alibaba Cloud EBS too, they same support qcow2 images export/import.
