KVM and Libvirt on Ubuntu 20.04
Turns out booting virtual machines from scratch using the KVM hypervisor with the virtualization manager Libvirt has some gotchas! We'll dispel any of that with this guide. We'll also show you how to expose your virtual machine to the public internet with an elastic IP.
All of Equinix Metal's hardware can be virtualized but for this guide, we'll be deploying an Entry Level & All-Arounder server with Ubuntu 20.04 installed.
Note: This installation is completed entirely using the command line (no GUI!). Also, you will need a public /29 IPv4 block assigned to your account if you plan to route public traffic to your virtual machine. You can request the IP block from our portal.
Deploying The Server and Installing Virtualization Software
Once you're logged into your Equinix Metal Dashboard navigate to deploy a new c3.small.x86 server in the region that suits you best. Do not add the /29 IPv4 block to the server at this point, we will assign it later on. The server will automatically be assigned one public IPv4 and one public IPv6 address which we'll use as the management addresses for the KVM host itself. The elastic IPs are entire reserved for the virtualization layer.
Once you're SSH'd into your server as root you'll need to install several packages to create and properly manage virtual machines.
- qemu-kvm: the hypervisor and emulator.
- virtinst: a suite of command line tools for installing and managing virtual machines with the operating system of your choosing.
- bridge-utils: used to create and manage bridge networks.
- libvirt: The system daemon managing your VMs for you
Good idea to do this...
$ apt update && apt upgrade -y
Then install the packages...
$ apt install bridge-utils qemu-kvm virtinst libvirt-daemon virt-manager -y
Once you're done you can verify the install is successful by running
Configuring the Network
When configuring the network for your virtual machines you can choose to run in NAT mode or in Route mode.
In NAT mode, each virtual machine gets a private IP and communicates with the public internet via the host's public IP.
In Route mode, each virtual machine gets their own public IP.
With either configuration, you'll need to create a bridge network. By default, libvirt comes with a preconfigured NATed network. It will usually assign 192.168.x.x IPs to the virtual machines you create. But we're not doing that here! We want our virtual machines to have their own public IPs so we will define our own network in an XML file.
In your Packet dashboard click on your KVM's host name, select
Network on the left hand menu and then select the
+ Assign New Elastic button on the right.
We'll be using the net-define command to configure the virtual machine.
The configuration needs to be in XML; for this example, we're creating a .xml file called network.xml in our root directory. The order in which we add our IPs matters! So have a look at the screenshot above to see which IP goes where in the configuration.
For subnets of size
/30 or greater, there are 3 IPs that cannot be used for your VMs, the network address (first IP), the gateway (this is the host bridge), and the broadcast address (last IP). So if we were using the subnet
188.8.131.52/29 which has 8 total IPs, the IP allocation would be as follows.
184.108.40.206 - Network address
220.127.116.11 - Gateway for the VMs / KVM host bridge address
18.104.22.168-150 - Range of usable IPs for VMs (5 in the case of a /29)
22.214.171.124 - Broadcast address
Run the following command to create the
network.xml file. You will need to adjust the IPs and subnet mask for this to fit your subnet.
A IPv4 netmask cheat sheet can be found here. The first IP you'll have to alter in the XML file is the one for KVM host which will act as a virtual network gateway for your VMs. If it ends in an even number like it does in our example the KVM host gateway address has to be odd, if it ends in an odd number it has to be an even number. In our case it's the latter case since the network ends in
.144. Therefore our KVM host gateway address has to be
The other two IP addresses to change are the ones defining the useable IP space in our network. In this case we'll have 5 useable IP addresses which we can assign to our VMs. The broadcast address does not need to set explicitly.
echo '<network> <name>vmbr0</name> <forward mode="route"/> <bridge name="vmbr0" stp="on" delay="0"/> <ip address="126.96.36.199" netmask="255.255.255.248"> <dhcp> <range start="188.8.131.52" end="184.108.40.206"/> </dhcp> </ip> </network>' >> network.xml
The following commands will define, create, and start our new network.
virsh net-define /root/network.xml virsh net-autostart vmbr0 virsh net-start vmbr0
These next commands will delete the default private network, this is not required but you can if you prefer to delete it.
virsh net-destroy default virsh net-undefine default
Lastly, restart the libvirt daemon.
systemctl restart libvirtd.service
Now if you look at your interfaces you'll see a new interface named vmbr0 with our 220.127.116.11/29 IP.
Lastly, don't forget to enable IPv4 and IPv6 packet forwarding!
sed -i "/net.ipv4.ip_forward=1/ s/# *//" /etc/sysctl.conf sed -i "/net.ipv6.conf.all.forwarding=1/ s/# *//" /etc/sysctl.conf
Reload sysctl for the packet forwarding changes to be applied.
Installing a Virtual Guest Machine
To install a virtual machine we'll run virt-install. Feel free to configure some of those parameters such as the RAM amount, vCPUs, OS, etc.. The following will install an Ubuntu 18.04 Bionic VM.
virt-install --name ubuntu18 \ --ram 4096 \ --disk path=/var/lib/libvirt/images/ubuntu18.img,size=8 \ --vcpus 2 \ --os-type linux \ --os-variant ubuntu18.04 \ --network bridge=vmbr0 \ --graphics none \ --console pty,target_type=serial \ --location 'http://us.archive.ubuntu.com/ubuntu/dists/bionic/main/installer-amd64/' \ --extra-args 'console=ttyS0,115200n8 serial'
The Ubuntu installer will hijack your console at some point soon after running the command and guide you through the rest of the install. You will be prompted to create a user which you will need to remember the credentials for in order to access the VM later.
The important part comes up during the end of the install where you'll be prompted with the option of installing additional software. We will need to install the OpenSSH Server package in order to access the VM once the installation is completed.
[!] Software selection At the moment, only the core of the system is installed. To tune the system to your needs, you can choose to install one or more of the following predefined collections of software. Choose software to install: [ ] Manual package selection [ ] Ubuntu Cloud Image (instance) [ ] DNS server [ ] Edubuntu desktop [ ] Kubuntu desktop [ ] Kubuntu full [ ] LAMP server [ ] Lubuntu minimal installation [ ] Lubuntu Desktop
Very important that you scroll all the way down using your arrow keys and select "OpenSSH Server" using the space bar before continuing. That's how we'll access the VM once it's up.
Accessing Your VM
To access your VM you can SSH into it from the host machine.
To view the IP address/MAC address of your VM have virsh list the DHCP leases for the virtual bridge network we setup: (ubuntu18 is the name of the VM)
virsh net-dhcp-leases vmbr0
Then, SSH into the VM with the user name of the account that we created during the OS installation process: