This tutorial will cover installation and basic configuration of libvirt and QEMU to a state where it's possible to easily provision new VMs with WebVirtMgr. It will be a minimalist install with as few dependencies as possible to keep the host easy to maintain. WebVirtMgr is not perfect, but is the best lightweight web GUI around at the moment. See the GitHub page for more information https://github.com/retspen/webvirtmgr.
libvirt provides a "default" virtual network which uses a NAT configuration. In most cases a bridge to the network the host is on will be preferred. More details on both can be found here http://libvirt.org/formatdomain.html#elementsNICS.
A bridge device can be configured on the command line with
brctl from the
bridge-utils package or with a
netctl config file to allow initialisation at boot. An example of the command line is here https://wiki.archlinux.org/index.php/Network_bridge#With_bridge-utils.
In this case a
netctl config file named
bridge0 is created. The bridge device will need to bind to an interface connected to the physical network and will become the interface which provides connectivity for both the host, and guest VMs (the physical interface it's self does not need an IP address). The configuration should be similar to bellow,
virbr0 is already created by libvirt, so use
virbr1 for the bridge name.
# nano /etc/netctl/bridge0
Description='Bridge device' Interface=virbr1 Connection=bridge IP=static Address=('192.168.1.100/24') Gateway=('192.168.1.1') DNS=('192.168.1.1') BindsToInterfaces=('enp2s0')
Set the bridge device to start at boot, then start it now.
# netctl enable bridge0 # netctl start bridge0
libvirt does provide functionality to create network devices on the host machine, however the libvirt Arch package has
netcf disabled which provides this (
netcf is Redhat developed and is very similar to
netctl). For Arch the bridge device must be created using the
Install libvirt and tools.
# pacman -S qemu libvirt libvirt-python openbsd-netcat bridge-utils dnsmasq ebtables dmidecode
libvirt configuration is documented in the Arch wiki and is more than enough to get up and running. The steps bellow are taken from the wiki for a file permissions based setup which is most simple https://wiki.archlinux.org/index.php/libvirt#Installation.
Create a user and group for libvirt.
# groupadd libvirt # useradd -m -g libvirt -G wheel,users -s /bin/bash libvirt # chfn libvirt # passwd libvirt
libvirt to the
kvm group. Then set QEMU to run under
libvirt and to listen on all interfaces.
# gpasswd -a libvirt kvm # nano /etc/libvirt/qemu.conf
vnc_listen = "0.0.0.0" user = "libvirt"
Allow non-root users to manage VMs with file-permission based access control.
# nano /etc/libvirt/libvirtd.conf
unix_sock_group = "libvirt" unix_sock_ro_perms = "0777" unix_sock_rw_perms = "0770" auth_unix_ro = "none" auth_unix_rw = "none"
Enable unencrypted TCP connections. This is for simplicity, in anything other than a testing environment SASL should be enabled.
listen_tls = 0 listen_tcp = 1 auth_tcp=none
libvirtd in listening mode by passing the
# nano /etc/conf.d/libvirtd
Enable and start the libvirt daemon.
# systemctl enable libvirtd # systemctl start libvirtd
Now the daemon can be tested with a
session connection via
virsh. When connecting to
system the libvirt daemon starts at boot with root permissions. A
session connection will launch a
libvirtd instance as the current user, taking that users permissions and some limitations compared to a
system connection. More details can be found on the libvirt wiki.
$ virsh -c qemu:///system virsh # exit $ virsh -c qemu:///session virsh # exit
The setup in this tutorial will use a
system connection while storing VHDs in the
home directory. This is because WebVirtMgr is currently only tested with (and hard coded to) a
system connection, also keeping user data out of the root file system is a good idea. For instance, a btrfs snapshot of root shouldn't be effecting VHDs.
A Python virtualenv will be used to install WebVirtMgr (currently v4.8.8) and it's dependencies. This makes maintenance easier as the application and packages are installed in their own virtual root environment separate from the system.
# pacman -S python2-pip python2-virtualenv git
Continue the setup as the
A virtualenv named
webvirtmgr is initialized in the home directory. The system
site-packages are exposed as well to make the
libvirt-python package available.
$ cd ~ $ virtualenv2 webvirtmgr --system-site-packages
Install the dependencies for Webvirtmgr, this must be done using the version of pip provided by virtualenv. The required versions are listed here, Django is the most important https://github.com/retspen/webvirtmgr/blob/master/requirements.txt.
$ ~/webvirtmgr/bin/pip2 install django==1.5.5 gunicorn==18.0 eventlet lockfile
Now clone WebVirtMgr from the git repository into
cd into the directory created.
$ cd ~/webvirtmgr/lib/python2.7/site-packages $ git clone git://github.com/retspen/webvirtmgr.git $ cd webvirtmgr
Initialise the Django site database. A superuser must be created for access to the site, using
libvirt is fine. Notice
webvirtmgr.sqlite3 is created.
$ ~/webvirtmgr/bin/python2 manage.py syncdb
local_settings.py file for Django must be enabled. Make a copy of the example, and then change the
STATIC_ROOT variable as bellow to fix a path bug present in v4.8.8.
$ cp webvirtmgr/local/local_settings.py.example webvirtmgr/local/local_settings.py $ nano webvirtmgr/local/local_settings.py
STATIC_ROOT = os.path.join(LOCAL_PATH, '..', 'static')
To check everything is setup correctly the site can be tested with the Django development server using the
$ ~/webvirtmgr/bin/python2 manage.py runserver 192.168.1.100:8000
Running as a service with Gunicorn
Gunicorn is a pure Python webserver so no extra dependencies are needed. The Gunicorn config file needs one edit to bind the correct IP address.
$ nano conf/gunicorn.conf.py
bind = '192.168.1.100:8000'
Then test the server with the config file just edited.
$ ~/webvirtmgr/bin/gunicorn webvirtmgr.wsgi:application -c conf/gunicorn.conf.py
If the server starts then this command can be used to create a systemd service file to start Gunicorn on boot. The only differences are the absolute paths and addition of the
--pythonpath attribute. Running Django with Gunicorn requires the project directory be on the Python path https://docs.djangoproject.com/en/1.5/howto/deployment/wsgi/gunicorn/.
A system service is created so this requires root permissions.
# nano /etc/systemd/system/webvirtmgr.service
[Service] User=libvirt Group=libvirt ExecStart=/home/libvirt/webvirtmgr/bin/gunicorn webvirtmgr.wsgi:application -c /home/libvirt/webvirtmgr/lib/python2.7/site-packages/webvirtmgr/conf/gunicorn.conf.py --pythonpath /home/libvirt/webvirtmgr/lib/python2.7/site-packages/webvirtmgr Type=simple Restart=on-failure [Install] WantedBy=multi-user.target
Start the service, if it starts without error then enable it for automatic startup on boot. To check the service log in real time use
# stystemctl start webvirtmgr # systemctl enable webvirtmgr # journalctl -fu webvirtmgr
With WebVirtMgr working there are some basic settings that are needed to get a VM running. Under the Interfaces tab the
virbr1 bridge interface created earlier should be visible. To make this available for a VM to use create a new network under the Networks tab using the
virbr1 interface in bridge mode.
A couple of storage pools will be needed for VHDs and ISOs. Under the Storages tab create a new "DIR" pool with the source as
/home/libvirt/vhd and an "ISO" pool with the source as
/home/libvirt/iso. Then it is simply a case of using sftp with the
libvirt user to upload an ISO to boot a VM from.
Because WebVirtMgr is using the
system connection to libvirt any VHD created here will owned by the
root account. Also it is highly recommended to disable copy-on-write (COW) for the VHD directory if using Btrfs, this can be done by enabling the C attribute.
# chattr +C /home/libvirt/vhd
Because of the amount of small random writes a VHD will receive over time, the file will become heavily fragmented and reduce the performance of the VM.
Thanks goes to the WebVirtMgr developers for taking the time to create a nice lightweight GUI.