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.
Network Setup
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 netctl
profile.
libvirt Installation
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
Add 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
Start libvirtd
in listening mode by passing the --listen
argument.
# nano /etc/conf.d/libvirtd
LIBVIRTD_ARGS="--listen"
Enable and start the libvirt daemon.
# systemctl enable libvirtd
# systemctl start libvirtd
Now the daemon can be tested with a system
or 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 libvirt
user's 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.
WebVirtMgr Setup
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 libvirt
user.
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 site-packages
and 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
The 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 runserver
command.
$ ~/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 journalctl
.
# 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.
Finished
Thanks goes to the WebVirtMgr developers for taking the time to create a nice lightweight GUI.
Comments
comments powered by Disqus