Shrinking OS image manually

Recently I needed to customize the OS template used to deploy KVM guests and once it was ready I realized it could be a lot smaller – there was plenty of free space on the partition which made the image larger than necessary, therefore I decided to reduce the size to the minimum possible and while it could be done via tools such as GParted – I couldn’t miss the opportunity to explore how it’s done behind the scene.

The goal is to reduce the size of the image, removing all unused space but leaving 100MB of free space available (that is optional and if free space is not needed in your case, adjust the formulas described below), which allows for further small modifications in case it’s needed.

Here’s how I’ve done it – on an example of 3.5GB OS image with AlmaLinux – note: naturally it also applies to shrinking partitions located on physical disks.

 

Road map:
– Shrink filesystem
– Shrink partition
– Align SWAP partition
– Shrink the image

 

Examine the input image:

1. Show details of the partitions on the image:

 

2. Examine the image itself:

As can be seen above – there is a difference in size reported by ‘du’ and ‘ls’ tools which might be confusing – this is because ‘ls’ shows how big is the AlmaLinux-8.4.qcow2 as a file on disk which is just a container for underlying partitions, while ‘du’ tool by default prints data used by the image without holes, internal fragmentation, indirect blocks, etc., add ‘–apparent-size’ switch to change ‘du’ default behavior:

 

(Optional) Convert the image to raw format:

 

Map partitions on the image:

 

Now the image can be accessed via /dev/loop1 block device and the partitions are mapped via /dev/mapper:

 

Shrink the OS partition:

It’s important to run a filesystem check before examining and resizing the filesystem:

 

1. Get the count of free and used blocks on the filesystem, which is needed to calculate the reduced size of the partition:

 

2. Calculate minimum size for the /dev/mapper/loop1p1 filesystem using the following formula:

therefore:
(838656 – 343620) * 4096 / 1024 = 1980144 KiB

 

3. Reduce filesystem size based on the calculated result:

 

4. Reduce partition size, leaving ~100MB which will be free space for the underlying filesystem:

a) Get the filesystem block count after resizing:

b) Check current partitions layout:

c) Calculate the new size of the partition, including ~100MB of free space using the following formula:

therefore:
((495036 – 5458) + 25600) * 4096 / 512 = 4121424 sectors

 

5. With calculated new size of the partition in sectors we can now start resizing via fdisk (note: this is single fdisk session separated by comments).

It’s important not to delete the filesystem signature:

The first partition is with a new size now, so we can align the SWAP to it:

Use the first sector available – not the default one:

Set the OS partition as bootable and mark the second partition as SWAP type:

That’s it, the changes need to be written:

 

6. Refresh tables and update mappings:

 

7. Format new swap partition:

 

8. Expand OS partition to assign the ~100MB reserve from partition to the filesystem:

 

9. Check the changes and note the Sectors count, this will be needed to shrink the image:

 

10. At this point the image mapping can be removed:

 

Shrink the image using ‘dd’ tool:

The new size is the sum of Sectors from both partitions, the start size, and the reserve, the result is provided to ‘dd’ via ‘count’ option and the ‘bs’ value must equal to the size of one sector – formula:

therefore:
2048 + 4165089 + 262687 + 204800 = 4587520 sectors

 

Compare both images:

That’s it.

Leave a Reply

Your email address will not be published. Required fields are marked *