Book Image

KVM Virtualization Cookbook

Book Image

KVM Virtualization Cookbook

Overview of this book

Virtualization technologies such as KVM allow for better control over the available server resources, by deploying multiple virtual instances on the same physical host, or clusters of compute resources. With KVM it is possible to run various workloads in isolation with the hypervisor layer providing better tenant isolation and higher degree of security. This book will provide a deep dive into deploying KVM virtual machines using qemu and libvirt and will demonstrate practical examples on how to run, scale, monitor, migrate and backup such instances. You will also discover real production ready recipes on deploying KVM instances with OpenStack and how to programatically manage the life cycle of KVM virtual machines using Python. You will learn numerous tips and techniques which will help you deploy & plan the KVM infrastructure. Next, you will be introduced to the working of libvirt libraries and the iPython development environment. Finally, you will be able to tune your Linux kernel for high throughput and better performance. By the end of this book, you will gain all the knowledge needed to be an expert in working with the KVM virtualization infrastructure.
Table of Contents (15 chapters)
Title Page
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Resizing an image


In this recipe, we are going to examine how to resize an existing raw image, the partitions hosted on it and the filesystem on top of the partitions. We are going to be using the raw image that we build in the previous recipes, which contains a swap and a root partition with an EXT4 filesystem formatted on it.

Getting ready

For this recipe, we are going to use the following tools:

  • qemu-img
  • losetup
  • tune2fs
  • e2fsck
  • kpartx
  • fdisk
  • resize2fs

Most of the utilities should already be installed on Ubuntu with the exception of kpartx. To install it, run the following:

root@kvm:~# apt install kpartx

How to do it...

The next steps demonstrate how to add additional space to the raw image we created earlier, extend the root partition, and resize the filesystem. By the end of this recipe, the original raw image filesystem size should have changed from 10G to 20G.

  1. Obtain the current size of the image:
root@kvm:~# qemu-img info debian.img    
image: debian.img
file format: raw
virtual size: 10G (10737418240 bytes)
disk size: 848M    
root@kvm:~#
  1. Add additional 10 GB to the image:
root@kvm:~# qemu-img resize -f raw debian.img +10GB    
Image resized.    
root@kvm:~#

Note

Please note that not all image types support resizing. In order to resize such an image, you will need to convert it to raw image first using the qemu-img convert command.

  1. Check the new size of the image:
root@kvm:~# qemu-img info debian.img    
image: debian.img
file format: raw
virtual size: 20G (21474836480 bytes)
disk size: 848M   
root@kvm:~#
  1. Print the name of the first unused loop device:
root@kvm:~# losetup -f 
/dev/loop0    
root@kvm:~#
  1. Associate the first unused loop device with the raw image file:
root@kvm:~# losetup /dev/loop1 debian.img    
root@kvm:~#
  1. Read the partition information from the associated loop device and create the device mappings:
root@kvm:~# kpartx -av /dev/loop1    
add map loop1p1 (252:0): 0 1024 linear 7:1 2048    
add map loop1p2 (252:1): 0 20967424 linear 7:1 4096
root@kvm:~#


  1. Examine the new device maps, representing the partitions on the raw image:
root@kvm:~# ls -la /dev/mapper    
total 0    
drwxr-xr-x 2 root root 100 Mar 9 19:10 .    
drwxr-xr-x 20 root root 4760 Mar 9 19:10 ..    
crw------- 1 root root 10, 236 Feb 10 23:25 control    
lrwxrwxrwx 1 root root 7 Mar 9 19:10 loop1p1    
lrwxrwxrwx 1 root root 7 Mar 9 19:10 loop1p2    
root@kvm:~#
  1. Obtain some information from the root partition mapping:
root@kvm:~# tune2fs -l /dev/mapper/loop1p2    
tune2fs 1.42.13 (17-May-2015)    
Filesystem volume name: <none>    
Last mounted on: /    
Filesystem UUID: 96a73752-489a-435c-8aa0-8c5d1aba3e5f    
Filesystem magic number: 0xEF53    
Filesystem revision #: 1 (dynamic)    
Filesystem features: has_journal ext_attr resize_inode dir_index filetype needs_recovery extent flex_bg sparse_super            large_file huge_file uninit_bg dir_nlink extra_isize    Filesystem flags: signed_directory_hash    
Default mount options: user_xattr acl    
Filesystem state: clean    
Errors behavior: Continue    
Filesystem OS type: Linux    
Inode count: 655360    
Block count: 2620928    
Reserved block count: 131046    
Free blocks: 2362078    
Free inodes: 634148    
First block: 0    
Block size: 4096    
Fragment size: 4096    
Reserved GDT blocks: 639    
Blocks per group: 32768    
Fragments per group: 32768    
Inodes per group: 8192    
Inode blocks per group: 512    
Flex block group size: 16    
Filesystem created: Fri Feb 10 23:29:01 2017    
Last mount time: Thu Mar 9 19:09:25 2017    
Last write time: Thu Mar 9 19:08:23 2017    
Mount count: 12    
Maximum mount count: -1    
Last checked: Fri Feb 10 23:29:01 2017    
Check interval: 0 (<none>)    
Lifetime writes: 1621 MB    
Reserved blocks uid: 0 (user root)    
Reserved blocks gid: 0 (group root)    
First inode: 11    
Inode size: 256    
Required extra isize: 28    
Desired extra isize: 28    
Journal inode: 8    
Default directory hash: half_md4    
Directory Hash Seed: f101cccc-944e-4773-8644-91ebf4bd4f2d    
Journal backup: inode blocks    
root@kvm:~#
  1. Check the filesystem on the root partition of the mapped device:
root@kvm:~# e2fsck /dev/mapper/loop1p2    
e2fsck 1.42.13 (17-May-2015)    
/dev/mapper/loop1p2: recovering journal    Setting free blocks count to 2362045 (was 2362078)    /dev/mapper/loop1p2: clean, 21212/655360 files, 258883/2620928 blocks    
root@kvm:~#
  1. Remove the journal from the root partition device:
root@kvm:~# tune2fs -O ^has_journal /dev/mapper/loop1p2    
tune2fs 1.42.13 (17-May-2015)    
root@kvm:~#
  1. Ensure that the journaling has been removed:
root@kvm:~# tune2fs -l /dev/mapper/loop1p2 | grep "features"    
Filesystem features: ext_attr resize_inode dir_index filetype extent flex_bg sparse_super large_file huge_file uninit_bg     dir_nlink extra_isize    
root@kvm:~#
  1. Remove the partition mappings:
root@kvm:~# kpartx -dv /dev/loop1    
del devmap : loop1p2    
del devmap : loop1p1    
root@kvm:~#


  1. Detach the loop device from the image:
root@kvm:~# losetup -d /dev/loop1    
root@kvm:~#
  1. Associate the raw image with the network block device:
root@kvm:~# qemu-nbd --format=raw --connect=/dev/nbd0 debian.img  root@kvm:~#
  1. Using fdisk, list the available partitions, then delete the root partition, recreate it, and write the changes:
root@kvm:~# fdisk /dev/nbd0    

Command (m for help): p

Disk /dev/nbd0: 21.5 GB, 21474836480 bytes
255 heads, 63 sectors/track, 2610 cylinders, total 41943040 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
Disk identifier: 0x00000000

 Device Boot Start End Blocks Id System
/dev/nbd0p1 1 16450559 8225279+ 82 Linux swap / Solaris
/dev/nbd0p2 16450560 20964824 2257132+ 83 Linux

Command (m for help): d
Partition number (1-4): 2

Command (m for help): n
Partition type:
 p primary (1 primary, 0 extended, 3 free)
 e extended
Select (default p): p
Partition number (1-4, default 2): 2
First sector (16450560-41943039, default 16450560):
Using default value 16450560
Last sector, +sectors or +size{K,M,G} (16450560-41943039, default 41943039):
Using default value 41943039

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
root@kvm:~#
  1. Associate the first unused loop device with the raw image file, like we did in step 5:
root@kvm:~# losetup /dev/loop1 debian.img
  1. Read the partition information from the associated loop device and create the device mappings:
root@kvm:~# kpartx -av /dev/loop1    
add map loop1p1 (252:2): 0 1024 linear 7:1 2048    
add map loop1p2 (252:3): 0 41938944 linear 7:1 4096    
root@kvm:~#
  1. After the partitioning is complete, perform a filesystem check:
root@kvm:~# e2fsck -f /dev/mapper/loop1p2    
e2fsck 1.42.13 (17-May-2015)    
Pass 1: Checking inodes, blocks, and sizes    
Pass 2: Checking directory structure    
Pass 3: Checking directory connectivity    
Pass 4: Checking reference counts    
Pass 5: Checking group summary information    
/dev/mapper/loop1p2: 21212/655360 files (0.2% non-contiguous), 226115/2620928 blocks    
root@kvm:~#
  1. Resize the filesystem on the root partition of the mapped device:
root@kvm:~# resize2fs /dev/nbd0p2 
resize2fs 1.42.13 (17-May-2015) 
Resizing the filesystem on /dev/mapper/loop1p2 to 5242368 (4k) blocks. 
The filesystem on /dev/mapper/loop1p2 is now 5242368 (4k) blocks long. 
root@kvm:~#
  1. Create the filesystem journal because we removed it earlier:
root@kvm:~# tune2fs -j /dev/mapper/loop1p2    
tune2fs 1.42.13 (17-May-2015)    
Creating journal inode: done    
root@kvm:~#


  1. Remove the device mappings:
root@kvm:~# kpartx -dv /dev/loop1    
del devmap : loop1p2    
del devmap : loop1p1    
root@kvm:~# losetup -d /dev/loop1    
root@kvm:~#

How it works...

Resizing an image for VM can be somewhat involving, as we saw from all the steps in the previous section. Things can get complicated when there are multiple Linux partitions inside the same image, even more so if we are not using Logical Volume Management (LVM). Let's step through all the commands we ran earlier and explain in more details why we ran them and what they do.

In step 1, we confirmed the current size of the image being 10 GB.

In step 2, we added 10 GB at the end of the image and confirm the new image size in step 3.

Recall that the image we built from earlier recipes contains two partitions, swap and root. We need a way to manipulate them individually. Particularly, we would like to allocate the extra space we added in step 2 to the root partition. To do that we need to expose it as a block device that we can easily manipulate with standard disk and filesystem utilities. We accomplished that using the losetup command in step 5, resulting in a mapping between the image and a new block device named /dev/loop1. In step 6, we exposed the individual partitions as two new device mappings. The /dev/mapper/loop1p2 is the root partition that we would like to append the unused disk space to.

Before we can resize the partitioned on the loop device, we need to check the integrity of the filesystem on it, and this is what we did in step 9. Because we are using a journaling filesystem, we need to remove the journal prior to resizing. We do that in step 10 and made sure that the has_journal attribute is not showing after running the tune2fs command in step 11.

Now, we need to work directly on the main block device and not the individual partitions. We remove the mappings in steps 12 and 13 and associated a new block device with the image file using the qemu-nbd command in step 14. The new /dev/nbd0 block device now represents the entire disk of the guest VM and it's a direct mapping to what's inside the raw image. We can use this block device just like any other regular disk, most importantly we can use tools such as fdisk to examine and manipulate the partitions residing on it.

In step 15, we use the fdisk utility to delete the root partition and recreate it. This does not destroy any filesystem data, but changes the metadata, allocating the extra space we added earlier as part of the root partition.

Now that the block device has all the disk space allocated to the root partition, we need to extend the filesystem that is on top of it. We do that by first recreating the individual partition mappings like we did earlier, to expose the root partition directly so that we can yet again manipulate it. We do that in steps 16 and 17.

In steps 18 and 19, we check the integrity of the root file system, then we resize it to the maximum available disk space on the root partition that it resides.

Finally, in step 20, we remove the mappings again. Now the image, the root partition inside the image, and the EXT4 filesystem on top of the Linux partition have been resized to 20 GB.

You can check the new root partition size by starting a new QEMU instance using the image. We are going to do just that in a separate recipe in this chapter.