kvm and libvirtd networking cheat sheet

Home

1 kvm Kernel-based Virtual Machine

Virtualization solution for Linux kernels since Linux kernel 2.6.5 on x86 hardware. It uses the loadable linux kernel module, kvm.ko. Both Intel, kvm-intel.ko and AMD, kvm-amd.ko, are supported.

It allows the kernel itself act as a hypervisor, and with Intel VT-x or, AMD-V it also allows nested hypervisors. That means a guest vm, could itself run a hypervisor, and have guests of its own.

2 install kvm on CentOS8

2.1 Verify CPU support of Intel VT or AMD-V

Step 1: Verify your CPU support for Intel VT or AMD-V Virtualization extensions. In some systems, this is disabled on BIOS and you may need to enable it.

cat /proc/cpuinfo | egrep "vmx|svm" You can also do the same with lscpu command

lscpu | grep Virtualization Virtualization: VT-x

2.2 Fix for my VMWare fusion CentOS8

I was not seeing any output on "grep -E '(vmx|svm)' /proc/cpuinfo" so I suspected that the fusion settings on my CentOS8 host did not support hardware virtualization.

I was right:

CentOS-host-settings.png

Figure 1: Fusion VM host settings

2.3 Result:

I was now getting the responses I was looking for. For example:

modprobe -a kvm_intel
ls -l /sys/module/kvm/
ls -l /sys/module/kvm_intel/ 
cat /sys/module/kvm_intel/parameters/nested

2.4 For details on modprobe, see my own notes in linux.org

Step 2: ummmmm??? What happened to step 2 ?

Step 3: Install KVM / QEMU on RHEL/ CentOS 8 KVM packages are distributed on RHEL 8 via AppStream repository. Install KVM on your RHEL 8 server by running the following commands:

  • sudo dnf upgrade # like sudo yum update but better and newer.
  • sudo dnf install @virt

After installation, verify that Kernel modules are loaded

$ lsmod | grep kvm
kvm_intel 233472 0
kvm 737280 1 kvm_intel

3 libvirtd and manual/custom config of netorking.

With the installation of libvirtd and its services create a virtual bridge interface virbr0 with network 192.168.122.0/24. In your setup there might be requirements to use a different network. We will tune the virbr0 and eth1 ( eth1 is the base interface for virbr0).

Update the interface configuration files as below

  • /etc/sysconfig/network-scripts/ifcfg-eth1
TYPE=Ethernet
BOOTPROTO=none
NAME=eth1
ONBOOT=yes
BRIDGE=virbr0
HWADDR=00:0c:29:41:15:0a 

and

  • cat /etc/sysconfig/network-scripts/ifcfg-virbr0
TYPE=BRIDGE
DEVICE=virbr0
BOOTPROTO=none
ONBOOT=yes
IPADDR=192.168.1.10
NETMASK=255.255.255.0
GATEWAY=192.168.1.1

Note – Replace the IP Address / MAC/UUID Info with the appropriate in your setup.

Enable the IPv4 forwarding


# echo net.ipv4.ip_forward = 1 | tee /usr/lib/sysctl.d/60-libvirtd.conf
# /sbin/sysctl -p /usr/lib/sysctl.d/60-libvirtd.conf

Configure Firewall

firewall-cmd --permanent --direct --passthrough ipv4 -I FORWARD -i bridge0 -j ACCEPT
firewall-cmd --permanent --direct --passthrough ipv4 -I FORWARD -o bridge0 -j ACCEPT
firewall-cmd --reload

4 Overview of Virtualization Components in Linux

  • virt-manager
    • GUI tool
    • can use QEMU and/or can use KVM as its hypervisor
  • kvm (the actual hypervisor)
  • qemu The emulator that emulates VMs (pronounced keemu &/or queue-emu)
  • virt-viewer
  • virsh (the virtualization shell)
  • and a bunch of libraries…

See virt-tools.org for a good overview of what is what w.r.t. virtualization

virt-tools.png

Figure 2: virt-tools.org

5 Command Line control of VMM using virsh

virsh, or 'virtual shell' can be executed with command line arguments as described below. i.e. sudo virsh list --all However you can also enter a virsh shell, after which the command would simply be list --all.

Enter the shell with sudo virsh

5.1 virsh

sudo virsh list   # will only show active VMs
sudo virsh list --all
sudo virsh list --inactive

sudo virsh start vm1

sudo virsh edit vm1    # where vm1 is your vm's name 

5.1.1 virsh commands for network (the KVM internal virutal network that is)

The virtual network used by your VM may not be running. If so, you will get errors such as "Failed to add tap interface 'vnet%d' to bridge 'virbr0' No such file or directory" This is usually the 'default' network, which can be started with:

virsh net-start default    # to start the virtual default virtual network.
virsh net-start default    # to start the virtual default virtual network.
virsh net-destroy          # note net-stop is NOT a correct command
virsh net-destroy

sudo virsh net-edit OPS335-nat-dhcp

sudo virsh net-info <network>  # obvious

sudo virsh net-list --inactive
sudo virsh net-list --all
sudo virsh net-list --autostart
sudo virsh net-list --persistent
sudo virsh net-list --transient
sudo virsh net-list --name    # changes output so names are displayed?

sudo virsh net-undefine <network>  # undefine a config for a persistent net
                                   # if net is active, make it transient
sudo virsh net-update   # read man pages on how to make changes to live net

sudo virsh net-dhcp-leases <network> [mac]

net-dhcp-leases gets a list of dhcp leases for all net interfaces connected to the given virtual net or limited the output for one int if mac addr is specified

virsh dumpxml $your-vm-name | grep acpi
virsh dumpxml $your-vm-name | grep acpi
virsh dumpxml $your-vm-name > ~/backups/saved-your-vm-name

5.2 xml stored in /var/lib/libvirt/images? follow up with this.

Other than using the above "dumpxml" command to create a xml file wherever you want to put it, kvm itself stores its production xml from some directory. Investigate which one…

5.3 virsh commands to get infomation

sudo virsh info?
sudo virsh dominfo vm1
sudo virsh dominfo vm1 | grep mem   # result is in KiB

5.4 virsh commands to add more memory

sudo virsh setmaxmem vm1 --size 16777216 
sudo virsh setmaxmem vm1 --size 16777216 --live  # or --current
sudo virsh setmem    vm1 --size 8388608  --config
sudo virsh setmem    vm1 --size 8M  --config
sudo virsh setmem    vm1 --size 8G  --config

or use virsh edit vm1

when on vm1: free -m

5.5 KiB vs KB

Good to know specifics when sizing a VM and the difference between KiB and KB. KiB is the larger, while KB is a power of 10


1 KB = 1000 bytes  (MAC OSx and Linux)
1 KiB = 1024 bytes (universal)   2^10

Megabytes
1 MiB = 1,048,576 bytes  2^20

Gigabytes
1 GB =  1,000,000,000 bytes
1 GiB = 1,073,741,824 bytes   2^30
      ; almost 74 Megabytes larger.

Terabytes
1 TiB = 1,099,511,627,776 bytes  2^40  

Petabytes
PiB = 1,125,899,906,842,624   2^50

Exabytes
EiB = 1,152,921,504,606,847,000  2^60

Zettabytes  ZiB  2^70

Yottabytes  YiB   2^80

5.6 virsh add virtual CPU

sudo virsh edit vm1  then look for <vcpu placement='static'>4</vcpu>
sudo virsh dominfo vm1 | grep -i cpu

5.7 virsh to add virtual disk to a VM

There are two steps involved in creating and attaching a new storage device to Linux KVM guest VM:

  1. First, create a virtual disk image
  2. Attach the virtual disk image to the VM

Details from the two steps:

5.7.1 Create a disk image file using qemu-img create command

In the following example, we are creating a virtual disk image with 7GB of size. The disk images are typically located under /var/lib/libvirt/images/ directory. The command to use is qemu-img create

cd /var/lib/libvirt/images/

qemu-img create -f raw myRHELVM1-disk2.img 7G

See man qemu-img for details but the above example will create and image that

  • has a size=7516192768
  • a format of raw
  • an image name 'myRHELVM1-disk2.img'

5.7.2 Attach the virtual disk image to the VM

To attach the newly created disk image, use the virsh attach-disk command as shown below:

virsh attach-disk myRHELVM1 \
      --source /var/lib/libvirt/images/myRHELVM1-disk2.img \
      --target vdb --persistent
# If no errors, you will see: "Disk attached successfully"

The above virsh attach-disk command has the following parameters:

  • myRHELVM1 The name of the VM

source The full path of the source disk image. This is the one that we created using qemu-image command above. i.e: myRHELVM1-disk2.imgtarget This is the device mount point. In this example, we want to attach the given disk image as /dev/vdb. Please note that we don’t really need to specify /dev. It is enough if you just specify vdb. – persistent indicates that the disk that attached to the VM will be persistent.

As you see below, the new /dev/vdb is now available on the VM. using: fdisk -l | grep vd

5.8 virt-clone

To use the virt-clone command line to clone a virtual machine,

  1. make sure the virtual machine is shutdown
  2. run virt-clone
 → virt-clone 
--connect=qemu:///system 
--original pangaea 
--name australinea 
--file /var/lib/libvirt/images/austalinea.qcow2

If your virtual machine target name will match the file name, you can shorten the above to

  1. run virt-clone (short-cut)
→ virt-clone 
--connect=qemu:///system 
--original pangaea 
--name australinea 
--auto-clone

5.9 virt-clone to a remote system.

If you’re connection to remote KVM/QEMU Host machine, put url before /system It will look something like:

   → virt-clone
--connect=qemu://192.168.1.30/system
--original pangaea
--name australinea
--file /var/lib/libvirt/images/australinea.qcow2
  • pangaea: Name of VM from which you are cloning.
  • australinea: Name given to resulting VM after cloning
  • australinea.qcow2:! Image saved that australinea boots from.

Check to confirm that australinea.qcow2 file is successfully stored in /var/lib/libvirt/images folder.

5.10 virt-sysprep

virt-sysprep "resets" or "unconfigures" a virtual machine so that clones can be made from it. The "unconfiguring" just strips any machine specific customizations, like ssh keys, static ip addresses, etc, so that a clone will coexist with the source of the clone.

5.10.1 CentOS-8 EOL seems to be virt-sysprep EOL?

On my Alma-Linux image that was upgraded from CentOS-8, virt-sysprep was no longer found. Not sure what the replacement is as of <2022-03-07 Mon>

In fact on my Alma-Linux VM:


root@c8host /bin[1009]$
ls virt-
virt-clone          virt-install        virt-pki-validate   virt-xml            
virt-host-validate  virt-manager        virt-viewer         virt-xml-validate   

Interesting that man virt-clone pages on my Alma-Linux mention virt-sysprep but the tool simply was not anywhere on my Alma-Linux system. Looks like a bug.

I also found that I could not install it on Alma either:

sudo dnf install virt-sysprep
Last metadata expiration check: 0:02:47 ago on Mon 07 Mar 2022 03:54:18 PM EST.
No match for argument: virt-sysprep
Error: Unable to find a match: virt-sysprep

5.10.2 For my older CentOS-8 image this is what I ran with virt-sysprep:

virsh suspend ncbz01
virt-clone --original ncbz01 --name ncbz02
        --file /var/lib/libvirt/images/ncbz02-disk01.qcow2
virsh resume ncbz01
virt-sysprep -d ncbz02 --hostname ncbz02 --enable 
       user-account,ssh-hostkeys,net-hostname,net-hwaddr,machine-id
       --keep-user-accounts vivek --keep-user-accounts root
       --run 'sed -i "s/192.168.122.16/192.168.122.17/" 
       /etc/network/interfaces'

5.11 qemu-img info

You can run qemu-img info /var/lib/libvirt/images/vm2.qcow2 to get insight into the kvm image. Good when investigating an error with that image.

5.12 delete a VM

  1. shutdown the vm
  2. destroy the VM (and undefine it
  3. remove the disk image

5.12.1 1) virsh shutdown vm1

5.12.2 2) virsh destroy vm1

virsh undefine vm1

5.12.3 3) rm /var/lib/libvirt/images/vm1-disk1.img

5.12.4 3) rm /var/lib/libvirt/images/vm1-disk2.img

5.13 To disable virbr0, try:

> virsh net-destroy default

> virsh net-undefine default

> service libvirtd restart

> ifconfig

5.14 Behaviour before starting vm

sudo virsh list –all resultining in nothting, no vms active or inactive. This may have changed. I can see all the VMs "shut off" and all the VMs "running"

5.15 virsh console to a vm

virsh console vm1 virsh console –domain vm1 –safe

virsh help console

My issue is that the virtual serial console does NOT seem to have a login prompt. I can change that too. On the guest VM… sudo systemctl enable serial-getty@ttyS0.service sudo systemctl start serial-getty@ttyS0.service

5.15.1 what tty am I on?

tty # how logical is that???? Gotta love unix.

My kvm console is /dev/tty1 My ssh session is /dev/pts0

5.16 exit a virsh console using the ^] escape character.

To exit the virsh console session (not a trivial task), use CTRL-SHIFT ] Is that the same as C-} ????

Nope for me it was actually NOT shifted, i.e. just plain C-]

Can also try CTRL-SHIFT 5 (

Is that the same as C-% ??

5.17 Accessing (starting) VMM from the command line:

virt-manager

5.18 Allowing a tty login on the virsh console:

Once you can virsh console into a vm, say vm2, then you have to also enable that console tty to have a login.

Old way: On the virtual machine, add ‘console=ttyS0‘ at the end of the kernel lines in the /boot/grub2/grub.cfg file:

But grub.cfg should NOT be edited by hand. So the new way:

edit the /etc/default/grub file, add ‘console=ttyS0‘ to the GRUBCMDLINELINUX variable and execute ‘# grub2-mkconfig -o /boot/grub2/grub.cfg‘.

Now, reboot the virtual machine:

Connected to domain vm.example.com Escape character is ^]

Red Hat Enterprise Linux Server 7.0 (Maipo) Kernel 3.10.0-121.el7.x8664 on an x8664

vm login:

5.19 How I recovered / restored a VM from a backed up .qcow2 image

I had deleted the guest VM from VMM completely. I had a backup so I cp /backup/full/pangaea.qcow2 /var/lib/libvirt/images That was actually a gzip of the image so I had to run: cd /var/lib/libvirt/images gunzip pangaea.qcow2

That resulted in a proper .qcow2 images in the right location, but before I could run it via libvirt, I had to use VMM to import it. vi

  1. create a new VM
  2. import existing disk image
  3. browse to /var/lib/libvirt/images and select the pangaea.qcow2 file
  4. pick a name for the vm that is different from the image. I used "pan" This I found after twice trying to create the "new" vm as "pangaea" That did not work
  5. This booted and all the settings of "pangaea" were restored. Only VMM sees the "domain" as "pan" and not "pangaea".

6 KVM guest networking

If the guest VM is running KVM, then run it as bridged mode, so its "outside addapter" gets full LAN connectivity, as just another host on that LAN.

Then VMM guests can be configured using a NATed "bridge" network, say virbr0, on a separate ip subnet, say 192.168.111.0/24. All guests get a 111.x addr and can see each other, but when then talk to the outside, they get NAT'ed to the Fusion's guest VM's network, and all appear on the LAN as that guest host.

7 VMM on a KVM guest VM

7.1 Finding ip addr of KVM guest VM from the host

On a terminal session on the KVM host, type virsh net-list virsh net-dhcp-leases <networkname>

To delete a KVM guest use: virsh list virsh shutdown VM virsh undefine VM

7.2 KVM is both a Type-1 and Type-2 Hypervisor

KVM is not a clear case as it could be categorized as either one. The KVM kernel module turns Linux kernel into a type 1 bare-metal hypervisor, while the overall system could be categorized to type 2 because the host OS is still fully functional and the other VM's are standard Linux processes from its perspective.

8 libvirt Networking

This from: wiki.libvirt.org

8.1 Networking

  • What is libvirt doing with iptables?

By default, libvirt provides a virtual network named 'default' which acts as a NAT router for virtual machines, routing traffic to the network connected to your host machine. This functionality uses iptables.

For more info, see: https://wiki.libvirt.org/page/VirtualNetworking in particular the section on NAT forwarding.

- How can I make libvirt stop using iptables? WARNING: Any VMs already configured to use these virtual networks will need to be edited: simply removing the <interface> devices via 'virsh edit' should be sufficient. Not doing this step will cause starting to fail, and even after the editing step the VMs will not have network access.

You can remove all libvirt virtual networks on the machine:

Use 'virsh net-list --all' to see a list of all virtual networks Use 'virsh net-destroy $net-name' to shutdown each running network Use 'virsh net-undefine $net-name' to permanently remove the network

  • Why doesn't libvirt just auto configure a regular network bridge?

While this would be nice, it is difficult/impossible to do in a safe way that won't hit a lot of trouble with non trivial networking configurations. A static bridge is also not compatible with a laptop mode of networking, switching between wireless and wired. Static bridges also do not play well with NetworkManager as of this writing (Feb 2010).

You can find more info about the motivation virtual networks here: http://www.gnome.org/~markmc/virtual-networking.html

How do I manually configure a network bridge? See: Setting up a Host Bridge

How do I get my VM to use an existing network bridge? See: Configuring Guests to use a Host Bridge

How do I forward incoming connections to a guest that is connected via a NATed virtual network? = See: Forwarding Incoming Connections

8.2 Setting up RHEL using NetworkManager

This section for info purposes for now. (I did not use this for CentOS kvm configuration and setup.) This outlines how to setup briding using standard network initscripts and systemctl.

Using NetworkManager directly If your distro was released some time after 2015 and uses NetworkManager, it likely supports bridging natively. See these instructions for creating a bridge directly with NetworkManager:

Using nm-connection-editor UI:happyassassin.net

Using the command line:lukas sapletai blog on libvirt with bridge

8.3 Disabling NetworkManager

(for older distros. Otherwise leave it running. It is good.) If your distro was released before 2015, the NetworkManager version likely does not handle bridging, so it is necessary to use "classic" network initscripts for the bridge, and to explicitly mark them as independent from NetworkManager (the "NMCONTROLLED=no" lines in the scripts below).

If desired, you can also completely disable NetworkManager:

Creating network initscripts In the /etc/sysconfig/network-scripts directory it is neccessary to create 2 config files. The first (ifcfg-eth0) defines your physical network interface, and says that it will be part of a bridge:

   # cat > ifcfg-eth0 <<EOF
DEVICE=eth0
HWADDR=00:16:76:D6:C9:45
ONBOOT=yes
BRIDGE=br0
NM_CONTROLLED=no
EOF

Obviously change the HWADDR to match your actual NIC's address. You may also wish to configure the device's MTU here using e.g. MTU=9000.

The second config file (ifcfg-br0) defines the bridge device:

   # cat > ifcfg-br0 <<EOF
DEVICE=br0
TYPE=Bridge
BOOTPROTO=dhcp
ONBOOT=yes
DELAY=0
NM_CONTROLLED=no
EOF

WARNING: The line TYPE=Bridge is case-sensitive - it must have uppercase 'B' and lower case 'ridge'

After changing this restart networking (or simply reboot)

The final step is to disable netfilter on the bridge:

   # cat >> /etc/sysctl.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0
EOF
# sysctl -p /etc/sysctl.conf

It is recommended to do this for performance and security reasons. See Fedora bug #512206. Alternatively you can configure iptables to allow all traffic to be forwarded across the bridge:

You should now have a "shared physical device", to which guests can be attached and have full LAN access

# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.000000000000       yes
br0             8000.000e0cb30550       yes             eth0

Note how this bridge is completely independant of the virbr0. Do NOT attempt to attach a physical device to 'virbr0' - this is only for NAT connectivity

9 Recommendations in CentOS6 and CentOS7 using NetworkManager

This is for CentOS to prep and mod the KVM networking. For KVM's own internal virtual networking, see the section above called virsh commands for network

This from zapletalovi.com

yum -y install bridge-utils
yum -y groupinstall "Virtualization Tools"
export MAIN_CONN=enp8s0
bash -x <<EOS
systemctl stop libvirtd
nmcli c delete "$MAIN_CONN"
nmcli c delete "Wired connection 1"
nmcli c add type bridge ifname br0 autoconnect yes con-name br0 stp off
#nmcli c modify br0 ipv4.addresses 192.168.1.99/24 ipv4.method manual
#nmcli c modify br0 ipv4.gateway 192.168.1.1
#nmcli c modify br0 ipv4.dns 192.168.1.1
nmcli c add type bridge-slave autoconnect yes con-name "$MAIN_CONN" ifname "$MAIN_CONN" master br0
systemctl restart NetworkManager
systemctl start libvirtd
systemctl enable libvirtd
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-ipforward.conf
sysctl -p /etc/sysctl.d/99-ipforward.conf
EOS

10 libvirt config files:

/etc/libvirt/qemu/networks ( but do not edit these. They are controlled by kvm. If you want to make changes, use sudo virsh net-edit <name>

However, I found that the only way I could rename a network was to edit the files here… very carefully.

  • I had to virsh edit vm1 on all the vms I had, to manually match the new network name.
  • I had to rename the actual network file name too in /etc/libvirt/qemu/networks

10.0.1 See also: /org/virt-manager/virt-manager

for client information in ?dconf?

10.0.2 virt-manager config files

are in ~/.gconf/apps/virt-manager/

10.0.3

11 Changing vm1 from dhcp leased address to static using nmcli

The following instructions are for a subnet 192.168.111.0 Replace 111 with the last two digits of your student ID.

cd /etc/sysconfig/network-scripts sudo cp ifcfg-ens3 ifcfg-ens34.original cat ifcfg-ens3 ip -4 addr nmcli connection nmcli device nmcli connection modify Wired\ connection\ 1 connection.id ens3 nmcli connection modify ens3 ipv4.addr "192.168.111.12" cat ifcfg-Wired-connection_1

nmcli connection modify ens3 ipv4.gateway 192.168.111.1 ip -4 addr

nmcli connection modify ens3 ipv4.dns 192.168.111.1 nmcli connection modify ens3 ipv4.method manual cat ifcfg-Wired_connection_1

nmcli c mod ens3 ipv4.dns 192.168.111.1 # let c8host resolve for guest VMs

vir nmcli connection nmcli connection delete eth0

nmcli device

vi ls -lt ip -4 addr

nmcli network off nmcli network on

ip -4 addr

ping -c 3 -n cbc.ca

12 Changing ip address of virbr0 interface

Usually done through the GUI of VMM, but this may come in handy someday: circa 2015: If you change the virbr0 address manually, you may find it hasn't actually taken effect, even after a reboot.

That is becuase the proper way to change an ip address for virbr0 is through using virsh.

virsh net-destroy default    # to stop the network
virsh net-start default      # to start it

virsh net-edit default       # to edit the network settings.   

Note to self: I have NOT tried this as of Jan 2020.

13 Manually config KVM bridge networking

From access.redhat.com: For anyone interested in KVM bridge networking, it's quite simple if you follow Jamie's advices plus this couple of things:

  1. Stop Network Manager: service NetworkManager stop
  2. Disable Network Manager on boot: chkconfig NetworkManager off
  3. Create /etc/sysconfig/network-scripts/ifcfg-br0 (or whatever your interface name is)
  4. ifcfg-br0 file (this is for using DHCP, otherwise BOOTPROTO=none and add IPADDR=, MASK=, GATEWAY=):
    DEVICE br0
    ONBOOT=yes
    TYPE=Bridge
    BOOTPROTO=dhcp
    STP=on
    DELAY=0
    NM_CONTROLLED=no
    

One important thing is to note that TYPE parameter is case-sensitive. So Bridge != bridge != BRIDGE. Be damn sure you type Bridge. Another important thing is to prevent Network Manager from managing this interface by setting NMCONTROLLED param to "no". Although NM is disabled on boot, perhaps you need to enable it again for some other needs in the future.

  1. Modify /etc/sysconfig/network-scripts/ifcfg-eth0 to match your environment:
       DEVICE eth0
    HWADDR=
    UUID=
    ONBOOT=yes
    TYPE=Ethernet
    BOOTPROTO=dhcp
    BRIDGE=br0
    NM_CONTROLLED=no
    

Considerations about TYPE and NMCONTROLLED params also apply.

Same thing on br1 and eth1 interfaces.

So, basically, MAC address is specified on the eth interface, IP address is specified on the bridge interface. Network Manager not managing those interfaces.

14 Resizing a guest disk space in KVM

14.1 qemu-img

The steps here utilize the kvm utility qemu-img, from the host linux server. Shutdown the guest VM, in my example it is australinea. Then modify the KVM settings to allocate more disk space to the guest VM.

14.2 First allocate disk space to the guest VM

Get info on the qcow2 disk image with the command:

  • qemu-img info /var/lib/libvirt/images/australinea.qcow2
zintis@c8host ~[1004]$
sudo qemu-img info /var/lib/libvirt/images/australinea.qcow2 
image: /var/lib/libvirt/images/australinea.qcow2
file format: qcow2
virtual size: 5 GiB (5368709120 bytes)
disk size: 3.91 GiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true
    refcount bits: 16
    corrupt: false
zintis@c8host ~[1005]$

Notice that we have a virtual size of 5G, but a disk size of only 3.91G virtual size is the size of the virutal disk when creating or expanding the disk. The maximum size here is 5G. The disk size is the current size of the qcow2 file. How much is actually used by the host to store this vm.

We will be resizing the virtual size, adding 2 GB of space:

  • qemu-img resize /var/lib/libvirt/images/australinea.qcow2 +2G
sudo qemu-img resize /var/lib/libvirt/images/australinea.qcow2 +2G
Image resized.
zintis@c8host ~[1006]$

Check the new virtual size is recognized by using the info command again:

  • qemu-img info /var/lib/libvirt/images/australinea.qcow2
sudo qemu-img info /var/lib/libvirt/images/australinea.qcow2 

image: /var/lib/libvirt/images/australinea.qcow2
file format: qcow2
virtual size: 7 GiB (7516192768 bytes)
disk size: 3.91 GiB
cluster_size: 65536
Format specific information:
    compat: 1.1
    lazy refcounts: true
    refcount bits: 16
    corrupt: false
zintis@c8host ~[1007]$

You should now see the additional space as far as qemu-img is concerned.

Ensure that there is no snapshots for this guest, because the next command won't work if you have snapshots:

  • virsh snapshot-list australinea
 sudo virsh snapshot-list australinea   
 Name   Creation Time   State
-------------------------------

zintis@c8host ~[1008]$

I had none.

Finally, list the fdisk now visible to the guest:

  • sudo fdisk -l /var/lib/libvirt/images/australinea.qcow2
sudo fdisk -l /var/lib/libvirt/images/australinea.qcow2 
Disk /var/lib/libvirt/images/australinea.qcow2: 3.9 GiB, 4197646336 bytes, 8198528 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
zintis@c8host ~[1009]$

Notice that fdisk still shows the original size, 3.9 GiB in my case.

14.3 Second grow your partition to use this extra space on the guest VM

14.3.1 boot and check disk size has room to expand

a

Boot the guest, and login, and use sudo (root privileges) for these commands: Using lsblk should show you that vda has now grown from 5G to 7G in size.

  • lsblk
    lsblk
    NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTf
    sr0          11:0    1 1024M  0 rom  
    vda         252:0    0    7G  0 disk 
    ├─vda1      252:1    0    1G  0 part /boot
    └─vda2      252:2    0    4G  0 part 
      ├─cl-root 253:0    0  3.5G  0 lvm  /
      └─cl-swap 253:1    0  512M  0 lvm  [SWAP]
    

    But the logical volume (lvm) for / has not changed yet.

    • df -h
    df -h
    Filesystem           Size  Used Avail Use% Mounted on
    devtmpfs             388M     0  388M   0% /dev
    tmpfs                405M     0  405M   0% /dev/shm
    tmpfs                405M  5.6M  400M   2% /run
    tmpfs                405M     0  405M   0% /sys/fs/cgroup
    /dev/mapper/cl-root  3.4G  3.1G  101M  97% /
    /dev/vda1            976M  211M  699M  24% /boot
    tmpfs                 81M     0   81M   0% /run/user/1000
    

    So we have to repartition your /dev/vda so that vda2 gets to use the extra 2 GB of space we added to this guest. For this CentOS8 guest, I downloaded and installed growpart. The package is called cloud-utils-growpart

14.3.2 install growpart

If you do not yet have it, download and install growpart. The package is called cloud-utils-growpart

  • sudo dnf install cloud-utils-growpart
    zintis@australinea~[602] $
    sudo dnf install cloud-utils-growpart
    Last metadata expiration check: 1 day, 17:53:16 ago on Thu 02 Dec 2021 08:34:47 PM EST.
    Dependencies resolved.
    ================================================================================
     Package                   Architecture       Version      Repository       Size
      ================================================================================
    Installing:
    cloud-utils-growpart      noarch            0.31-3.el8     appstream        32 k
    
    Transaction Summary
    ================================================================================
    Install  1 Package
    
    Total download size: 32 k
    Installed size: 63 k
    Is this ok [y/N]: y
    Downloading Packages:
    cloud-utils-growpart-0.31-3.el8.noarch.rpm           13 kB/s |  32 kB      00:02    
    --------------------------------------------------------------------------------
    Total                                               7.9 kB/s |  32 kB      00:04     
    Running transaction check
    Transaction check succeeded.
    Running transaction test
    Transaction test succeeded.
    Running transaction
      Preparing        :                                                         1/1
      Installing       : cloud-utils-growpart-0.31-3.el8.noarch                  1/1 
      Running scriptlet: cloud-utils-growpart-0.31-3.el8.noarch                  1/1 
      Verifying        : cloud-utils-growpart-0.31-3.el8.noarch                  1/1 
    
    Installed:
      cloud-utils-growpart-0.31-3.el8.noarch                                                                                                                     
    s
    Complete!
    zintis@australinea~[603] $
    

    Next we have to use the newly downloaded utility, growpart, to grow the parttion. In my case it will be the vba partition. (See growpart -h) or man growpart, for more details on what growpart can do.

14.3.3 Run growpart

  • growpart /dev/vda 2
    zintis@australinea~[605] $
    sudo growpart /dev/vda 2
    CHANGED: partition=2 start=2099200 old: size=8386560 end=10485760 new: size=12580831 end=14680031
    

Now lsblk should show that our disk spake on vda2 has increased.

:   zintis@australinea~[606] $
   lsblk 
   NAME        MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
   sr0          11:0    1 1024M  0 rom  
   vda         252:0    0    7G  0 disk 
   ├─vda1      252:1    0    1G  0 part /boot
   └─vda2      252:2    0    6G  0 part 
     ├─cl-root 253:0    0  3.5G  0 lvm  /
     └─cl-swap 253:1    0  512M  0 lvm  [SWAP]
   zintis@australinea~[607] $

So we are nearly there. vda2 now shows 6G, but the logical volumes, lvm still show the original 3.5G in space.

14.3.4 Step 3

Resize root logical volume to occupy all space. There are several commands that are useful here. pvs for physical volume show, This shows what the physical volume size you have. Then you can use pvresize to resize the physical volume. Then, lvs for logical volume show. Notice that they both show which volume group, VG they belong to. You will need that info. In my case the VG is "cl".

First pvs and pvresize /dev/vda2

zintis@australinea~[608] $
sudo pvs
  PV         VG Fmt  Attr PSize  PFree
  /dev/vda2  cl lvm2 a--  <4.00g    0 
zintis@australinea~[609] $
sudo pvresize /dev/vda2
  Physical volume "/dev/vda2" changed
  1 physical volume(s) resized or updated / 0 physical volume(s) not resized
zintis@australinea~[610] $
sudo pvs
  PV         VG Fmt  Attr PSize  PFree
  /dev/vda2  cl lvm2 a--  <6.00g 2.00g
zintis@australinea~[611] $

Notice that now vda2 has 6G of space, with 2G free.

Second lvs to show the logical volume size.

sudo lvs
  LV   VG Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  root cl -wi-ao----  <3.50g                                                    
  swap cl -wi-ao---- 512.00m                                                    
zintis@australi 2nea~[614] $

Notice that still shows 3.5G, not the 6G we have available.

14.3.5 Step 4

Determine the volume group size. Remember in my Centos8 VM, the vg was "cl".

zintis@australinea~[614] $
sudo vgs
  VG #PV #LV #SN Attr   VSize  VFree
  cl   1   2   0 wz--n- <6.00g 2.00g
zintis@australinea~[615] $

Also determine the correct Filesystem to extend using the df -hT command. In my case it was /dev/mapper/cl-root

  • df -hT
zintis@australinea~[615] $
df -hT
Filesystem          Type      Size  Used Avail Use% Mounted on
devtmpfs            devtmpfs  388M     0  388M   0% /dev
tmpfs               tmpfs     405M     0  405M   0% /dev/shm
tmpfs               tmpfs     405M  5.6M  400M   2% /run
tmpfs               tmpfs     405M     0  405M   0% /sys/fs/cgroup
/dev/mapper/cl-root ext4      3.4G  2.7G  568M  83% /
/dev/vda1           ext4      976M  211M  699M  24% /boot
tmpfs               tmpfs      81M     0   81M   0% /run/user/1000
zintis@australinea~[616] $

Notice that / mount point still shows 3.4G size on /dev/mapper/cl-root

14.3.6 Step 5

Then resize logical volume used by the root file system using the extended volume group:

  • sudo lvextend -r -l +100%FREE /dev/name-of-volume-group/root

    -l to extend the logical volume size in units of logical extents

    -r resize underlying filesystem togeter with the logical volume.

  • sudo lvextend -r -l +100%FREE /dev/name-of-volume-group/root
sudo lvextend -r -l +100%FREE /dev/mapper/cl-root
Size of logical volume cl/root changed from <3.50 GiB (895 extents) to <5.50 GiB (1407 extents).
Logical volume cl/root successfully resized.
resize2fs 1.45.6 (20-Mar-2020)
Filesystem at /dev/mapper/cl-root is mounted on /; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 1
The filesystem on /dev/mapper/cl-root is now 1440768 (4k) blocks long.

zintis@australinea~[617] $
df -hT
Filesystem          Type      Size  Used Avail Use% Mounted on
devtmpfs            devtmpfs  388M     0  388M   0% /dev
tmpfs               tmpfs     405M     0  405M   0% /dev/shm
tmpfs               tmpfs     405M  5.6M  400M   2% /run
tmpfs               tmpfs     405M     0  405M   0% /sys/fs/cgroup
/dev/mapper/cl-root ext4      5.4G  2.7G  2.5G  52% /
/dev/vda1           ext4      976M  211M  699M  24% /boot
tmpfs               tmpfs      81M     0   81M   0% /run/user/1000
zintis@australinea~[618] $

Notice that the size went up by 2 GB. It is now 5.4G. That's it. Well, I did a reboot, but everything worked great.

15 Duplicating the above section using ansible.

See the file ansible.org for detail on ansible. Here I am simply including the three ansible playbooks I used to duplicate the above steps with my other four virtual servers.

15.0.1 Part 1 of 3

---
- name: Part 1 of 3 growing volumes by 2G
  hosts: continents

  tasks:
    - name: run lsblk to check partition sizes
      ansible.builtin.command: lsblk
      register: LSBLK

    - debug: msg=:{{LSBLK.stdout}}

    - name: run df -hT to confirm available disks
      ansible.builtin.command: df -hT
      register: DISKFREE

    - debug: msg=:{{DISKFREE.stdout}}

    - name: install growpart
      dnf:
        name: cloud-utils-growpart
        state: present
      become: true

    - name: Use growpart on vda2 to grow it by 2G 
      ansible.builtin.command: growpart /dev/vda 2
      become: true

    - name: run lsblk
      ansible.builtin.command: lsblk
      register: LSBLK

    - debug: msg=:{{LSBLK.stdout}}

15.0.2 Part 2 of 3

---
- name: Part 2 of 3 growing volumes by 2G
  hosts: continents

  tasks:
    - name: show physical volume size with pvs
      ansible.builtin.command: pvs
      become: true
      register: PVS

    - debug: msg=:{{PVS.stdout}}

    - name: resize vda2 physical volume with pvresize
      ansible.builtin.command: pvresize /dev/vda2
      become: true
      register: RESIZE

    - debug: msg=:{{RESIZE.stdout}}

    - name: show physical volume size with pvs
      ansible.builtin.command: pvs
      become: true
      register: PVS

    - debug: msg=:{{PVS.stdout}}

15.0.3 Part 2 of 3

---
- name: Part 3 of 3 growing volumes by 2G
  hosts: continents

  tasks:
    - name: show logical volume size with lvs
      ansible.builtin.command: lvs
      become: true
      register: LVS

    - debug: msg=:{{LVS.stdout}}


    - name: show volume group size with vgs
      ansible.builtin.command: vgs
      become: true
      register: VGS

    - debug: msg=:{{VGS.stdout}}

    - name: Extend logical volume cl-root with lvextend
      ansible.builtin.command: lvextend -r -l +100%FREE /dev/mapper/cl-root
      become: true
      register: LVEXT

    - debug: msg=:{{LVEXT.stdout}}

    - name: show resulting disk free.
      ansible.builtin.command: df -hT
      register: DISKFREE

    - debug: msg=:{{DISKFREE.stdout}}

15.1 Home