Configuring LXC using libvirt

In a previous post I showed how to configure LXC and cgroups by using user-space tools, a rather laborious process. In this post I'll demonstrate a much easier way of say running Apache in a container by using libvirt.
libvirt is a toolkit to interact with the virtualization capabilities of recent versions of Linux [1] and a set of API bindings for common languages like Python. It is widely used for managing KVM and XEN instances, but it can be used with the same success by LXC, though still not quite secure as it should be, but something that can be worked around by using SELinux.
For this example I'll be using CentOS 6.3, but I've tested this on Debian derivatives and it should works just the same.
First let's install and run the libvirt package and daemon, if not done so already:
Next lets create the file-system for the container. In this example I'll use a custom /etc and /var/www, the / and all other directories will be visible and used from the host OS - not the most secure way, but it's the simplest:
Install Apache on the host system, but don't run it, then copy the config file to the /etc in the container:
To be able to run Apache in the container, or any other services that requite networking, we need to copy few more files:
Configure your networking:
Create an index page for the web server, if desired:
Now that we have the file system laid out for the container, let's create the XML file for libvirt to use:
This is a pretty standard libvirt configuration file if you are already familiar with XEN, or KVM in libvirt. We define the name, how many CPU cores and memory to be allocated to the container (managed by cgroups), along with what file-system resources to mount inside the container. In the <emulator> element at line 14, be sure you specify the correct path to libvirt_lxc, if it does not live in /usr/libexec on your system.
One important difference is the <init> tag. This tells the container to execute this script when LXC starts. The file contains the following:

Make sure it's executable:
It basically starts the networking, Apache and gives you back a bash shell to work with. Save the file and define the container:
The libvirt LXC driver requires that certain cgroups controllers are mounted on the host OS. The minimum required controllers are 'cpuacct', 'memory' and 'devices', while recommended extra controllers are 'cpu', 'freezer' and 'blkio'. The /etc/cgconfig.conf & cgconfig init service used to mount cgroups at host boot time. Make sure the cgconfig daemon is runnig and the /cgroup is mounted. In some cases you have to reboot the server to make cgroups work:
To start the container execute:
To list all available containers run:
To login to the container using the console run:
Logs go to:
One thing to note is that after you exit the console the container will terminate. You can work around this by either starting SSH in the container in a similar way Apache is started, or just disconnect from the session.

You can see the running container process that was started by libvrit_lxc:
To see the memory limit for the container we just created execute:
You can change this on the fly as well. To read more about cgroups you can read my previous post on that topic.

Apache should be accessible now in the container:
Here's a python example creating a container with HAProxy in it: