How to: libvirt & kvm

After my virtualbox post I decided I would try the RHEL standard for virtualization, KVM. In this little scribble I'll be using the libvirt interface via the command line, as I don't feel that a GUI is acceptable on any server install.

I will be taking advantage of the RHEL 7 clone, CentOS 7, and all the standard packages that come with it, notably, the networkmanager command line.

Libvirt stores all it'c configuration in '/var/lib/libvirt/' by default.

Requirments

The first step will be to install the required packages. This will install everything we require, so let the dependencies fly.

yum install libvirt-daemon-kvm virt-install  

Services

Now we need to set the service to automatically start on boot and start it now:

systemctl enable libvirtd.service  
systemctl start libvirtd.service  

Network

Next you will need to examine some of the network configuration possibilities. There are multiple methods of getting your virtual machine on-line or on your network. Most of which are described here but for the purposes of this article I will be creating a network bridge and directly attaching the virtual machine(s) to the local network. In order for that to happen we need to create the network bridge on the host machine:

nmcli con add type bridge ifname br0  
nmcli con modify bridge-br0 bridge.stp no  
nmcli con modify bridge-br0 connection.autoconnect yes  
nmcli con modify bridge-br0 ipv4.method auto  
nmcli con add type bridge-slave ifname <ethernet device> master bridge-br0  
nmcli con delete <ethernet device>  
nmcli connection reload  

If you would like details on what the above commands do you can examine the official RedHat documentation here. My network takes advantage of DHCP, so I won't have to assign IP addresses. If your network configuration uses statically assigned IP addresses, you will have to apply those addresses to your new bridge. Please note that the last command will essentially remove the network connection you are effectively using if you are connecting remotely. You will need to either reload the network configuration at the terminal, schedule it to restart after you have finished reconfiguring the network, or restart the system to regain access.

Now we have to create a libvirt network our virtual machine can use. This is done via xml. I will create a file named '/var/lib/libvirt/network/virtual':

<network>  
  <name>virtual</name>
  <bridge name='br0'/>
  <forward mode='bridge'/>
</network>  

Now we need to load that configuration into libvirt:

virsh net-define /var/lib/libvirt/network/virtual  
virsh net-autostart virtual  
virsh net-start virtual  

The first line creates a persistent virtual network called 'virtual'. The second line sets it to automatically start, and the third starts it now.

Storage

Next we need to create a virtual drive to store our data. There are a few different formats to choose from each with their own advantages and disadvantages. You can read about them all here. For now, I'm going to take advantage of the 'qcow2' format. So let's go ahead and create our storage:

qemu-img \  
create \  
-f qcow2 \
/var/lib/libvirt/images/CentOS.qcow2 \
250G  

We will also have to have some media to boot from to install our operating system. I like to create a directory called /var/lib/libvirt/isos and copy my install media there, but if you do, you need to set the proper selinux context to give libvirt access. Luckily, this is not an un-common practice and a proper context is already configured you just have to restore it on your newly created directory.

mkdir /var/lib/libvirt/isos  
restorecon /var/lib/libvirt/isos  

Go ahead and copy your install media to the new directory.

Creating the Virtual Machine

Finally, we are ready to define the virtual machine. There are a BUNCH of command line options, don't be overwhelmed, a simple 'virt-install help' is a great place to start, but you can also examine the documentation here. I learn by example, so let's get started.

The command I'm going to use is:

virt-install \  
--name="CentOS" \
--ram="4096" \
--vcpus="1,maxvcpus=2" \
--os-variant="rhel7.1" \
--disk="path=/var/lib/libvirt/images/CentOS.qcow2,format=qcow2,bus=sata" \
--disk="/var/lib/libvirt/isos/CentOS-7-x86_64-DVD-1511.iso,device=cdrom,bus=sata" \
--network="network=virtual" \
--graphics="spice,listen=0.0.0.0" \
--hvm \
--autostart \
--noautoconsole"

Let's go through that line by line:
- name = This is the name I have given to the VM.
- ram = Amount of ram dedicated to the VM. With the host being linux here you can overcommit memory, but your experience may vary.
- vcpus = On boot I'm assigning 1 CPU at start and giving it the ability to grow dynamically to 2.
- os-variant = There are some optimal pre-configured settings we can take advantage of by defining this. Use the command 'osinfo-query os' to get a list of supported systems. If your system is not listed choose the one with the closest architecture.
- disk = The file for the virtual storage system. I like the SATA bus, so I'm defining it here.
- network = This is the name of the network we configured earlier.
- graphics = What protocol the VM will have it's output attached to. In this example I am using spice but you can just as easily specify VNC as well.
- hvm = Turn on hypervisor support
- autostart = Set the VM to automatically start with the host operating system.
- noautoconsole = The default behavior is to launch the VM and display the graphical console, but we don't want that to happen in a console only environment.

Controlling your VM

Edit VM: 'virsh edit '
List VMs: 'virsh list --all'
Stop VM: 'virsh destroy '
Start VM: 'virsh start '
Un-register VM: 'virsh undefine '

Example

virt-install \  
--name="Windows7" \
--ram="8192" \
--vcpus="1,maxvcpus=4" \
--os-variant="win7" \
--disk="path=/var/lib/libvirt/images/Windows7.qcow2,bus=virtio,size=250,format=qcow2" \
--disk="path=/var/lib/libvirt/isos/Windows7.iso,device=cdrom,bus=sata" \
--disk="path=/var/lib/libvirt/isos/virtio-win.iso,device=cdrom,bus=sata" \
--network="network=virtual,model=virtio,mac=RANDOM" \
--graphics="spice,listen=0.0.0.0" \
--hvm \
--autostart \
--noautoconsole \
--video="model=cirrus"

In this example I used the virtio driver for as many devices as possible. Because I used it for the storage device I needed to also supply the drivers in the form of an iso so that I could load them during the install. Also tak note that I had to use the cirrus video driver. This is required to move past the "Starting Windows" screen, the default video driver causes the windows 7 install to stall or hang.

Notes

If you want a Windows 10 VM you have to add '--cpu="core2duo"' to the install command or edit the xml to not advertise the virtual processor architecture to the guest system. This tells Winodws 10 that the cpu is not a virtual machine.

A lot of help for these commands can be found by examining the man pages for virsh and virt-install.