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:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# yum install -y libvirt | |
[root@host1 ~]# service libvirtd start |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# mkdir -p /containers/http1/etc | |
[root@host1 ~]# mkdir -p /containers/http1/var/www/html | |
[root@host1 ~]# mkdir -p /containers/http1/etc/httpd/conf | |
[root@host1 ~]# mkdir -p /containers/http1/etc/sysconfig |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# yum install -y httpd | |
[root@host1 ~]# cp -r /etc/httpd/conf /containers/http1/etc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# cp -r /etc/passwd /containers/http1/etc/ | |
[root@host1 ~]# cp -r /etc/shadow /containers/http1/etc/ | |
[root@host1 ~]# cp -r /etc/group /containers/http1/etc/ | |
[root@host1 ~]# cp -r /etc/mime.types /containers/http1/etc/ | |
[root@host1 ~]# cp -r /etc/sysconfig/network /containers/http1/etc/sysconfig/ | |
[root@host1 ~]# cp -r /etc/sysconfig/network-scripts /containers/http1/etc/sysconfig/ | |
[root@host1 ~]# cp -r /etc/init.d/ /containers/http1/etc/ | |
[root@host1 ~]# cp -r /etc/resolv.conf /containers/http1/etc/ | |
[root@host1 ~]# cp -r /etc/rc.d/ /containers/http1/etc/ | |
[root@host1 ~]# cp -r /etc/httpd/* /containers/http1/etc/httpd/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# cat /containers/http1/etc/sysconfig/network-scripts/ifcfg-eth0 | |
DEVICE=eth0 | |
BOOTPROTO=static | |
IPADDR=192.168.122.50 | |
NETMASK=255.255.255.0 | |
DEFROUTE=yes | |
GATEWAY=192.168.122.1 | |
DNS1=192.168.1 | |
ONBOOT=yes | |
NM_CONTROLLED=no | |
[root@host1 ~]# echo "nameserver 192.168.122.1" > /containers/http1/etc/resolv.conf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# echo "Apache in LXC" >> /containers/http1/var/www/html/index.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# cat http1.xml | |
<domain type='lxc'> | |
<name>http1</name> | |
<memory>102400</memory> | |
<os> | |
<type>exe</type> | |
<init>/bin/startup.sh</init> | |
</os> | |
<vcpu>1</vcpu> | |
<on_poweroff>destroy</on_poweroff> | |
<on_reboot>restart</on_reboot> | |
<on_crash>destroy</on_crash> | |
<devices> | |
<emulator>/usr/libexec/libvirt_lxc</emulator> | |
<filesystem type='mount'> | |
<source dir='/containers/http1/etc/httpd/conf/'/> | |
<target dir='/etc/httpd/conf'/> | |
</filesystem> | |
<filesystem type='mount'> | |
<source dir='/containers/http1/var/www/html/'/> | |
<target dir='/var/www/html'/> | |
</filesystem> | |
<filesystem type='mount'> | |
<source dir='/containers/http1/etc/'/> | |
<target dir='/etc'/> | |
</filesystem> | |
<interface type='network'> | |
<source network='default'/> | |
</interface> | |
<console type='pty'/> | |
</devices> | |
</domain> |
One important difference is the <init> tag. This tells the container to execute this script when LXC starts. The file contains the following:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# cat /bin/startup.sh | |
#!/bin/bash | |
export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin | |
export PS1="[\u@\h \W]\\$" | |
echo "Starting Networking" >> /var/log/messages | |
/etc/init.d/network start | |
echo "Starting httpd" >> /var/log/messages | |
/etc/init.d/httpd start | |
/bin/bash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# chmod u+x /bin/startup.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# virsh --connect lxc:/// define http1.xml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# /etc/init.d/cgconfig start | |
[root@host1 ~]# /etc/init.d/cgconfig status | |
Running | |
[root@host1 ~]# ls -la /cgroup/ | |
total 12 | |
drwxr-xr-x 10 root root 4096 Feb 4 18:59 . | |
drwxr-xr-x. 24 root root 4096 Feb 4 18:59 .. | |
drwxr-xr-x 3 root root 0 Feb 4 18:59 blkio | |
drwxr-xr-x 3 root root 0 Feb 4 18:59 cpu | |
drwxr-xr-x 3 root root 0 Feb 4 18:59 cpuacct | |
drwxr-xr-x 3 root root 0 Feb 4 18:59 cpuset | |
drwxr-xr-x 3 root root 0 Feb 4 18:59 devices | |
drwxr-xr-x 3 root root 0 Feb 4 18:59 freezer | |
drwxr-xr-x 3 root root 0 Feb 4 18:59 memory | |
drwxr-xr-x 2 root root 0 Feb 4 18:59 net_cls |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# virsh --connect lxc:/// start http1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# virsh --connect lxc:/// list --all | |
Id Name State | |
---------------------------------------------------- | |
1799 http1 running |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# virsh --connect lxc:/// console http1 | |
[root@host1 ~]# ps axf | |
PID TTY STAT TIME COMMAND | |
1 pts/3 Ss 0:00 /bin/bash /bin/startup.sh | |
201 ? Ss 0:00 /usr/sbin/httpd | |
204 ? S 0:00 \_ /usr/sbin/httpd | |
205 ? S 0:00 \_ /usr/sbin/httpd | |
206 ? S 0:00 \_ /usr/sbin/httpd | |
207 ? S 0:00 \_ /usr/sbin/httpd | |
208 ? S 0:00 \_ /usr/sbin/httpd | |
209 ? S 0:00 \_ /usr/sbin/httpd | |
210 ? S 0:00 \_ /usr/sbin/httpd | |
211 ? S 0:00 \_ /usr/sbin/httpd | |
203 pts/3 S 0:00 /bin/bash | |
218 pts/3 R+ 0:00 \_ ps axf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# tail -f /var/log/libvirt/lxc/http1.log | |
PATH=/sbin:/usr/sbin:/bin:/usr/bin LIBVIRT_DEBUG=3 LIBVIRT_LOG_OUTPUTS=3:stderr /usr/libexec/libvirt_lxc --name http1 --console 19 --handshake 23 --background --veth veth2 | |
PATH=/bin:/sbin TERM=linux container=lxc-libvirt LIBVIRT_LXC_UUID=333cce9a-047f-5e27-d2f0-3cd4e06dd182 LIBVIRT_LXC_NAME=http1 /bin/startup.sh |
You can see the running container process that was started by libvrit_lxc:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# ps axfw | |
[truncated] | |
1799 ? Ss 0:00 /usr/libexec/libvirt_lxc --name http1 --console 19 --handshake 23 --background --veth veth2 | |
1808 pts/6 Ss 0:00 \_ /bin/bash /bin/startup.sh | |
2122 ? Ss 0:00 \_ /usr/sbin/sshd | |
2131 pts/6 S+ 0:00 \_ /bin/bash | |
2878 ? Ss 3:30 \_ /usr/sbin/httpd | |
24010 ? S 0:02 \_ /usr/sbin/httpd | |
26204 ? S 0:02 \_ /usr/sbin/httpd | |
1466 ? S 0:02 \_ /usr/sbin/httpd | |
6785 ? S 0:01 \_ /usr/sbin/httpd | |
24968 ? S 0:01 \_ /usr/sbin/httpd | |
31661 ? S 0:01 \_ /usr/sbin/httpd | |
[truncated] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# cat /cgroup/memory/libvirt/lxc/http1/memory.limit_in_bytes | |
104857600 |
Apache should be accessible now in the container:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@host1 ~]# curl 192.168.122.50 | |
Apache in LXC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
''' | |
1. Install libvirt | |
2. Install libvirt-python (RedHat) python-libvirt(Debian) | |
3. Install haproxy | |
4. Create container file system that includes network configs, haproxy configs, | |
haproxy service | |
5. Change BASE_CONTAINER path to lcoation of the template file system | |
6. Change CONTAINER_PATH to the location where you want the lxc filesystem | |
to be. | |
''' | |
import libvirt | |
import os | |
import argparse | |
import random | |
class Paths(object): | |
CONTAINER_PATH = '/containers/{0}' | |
CONTAINER_ETC = CONTAINER_PATH + '/etc' | |
CONTAINER_INIT_D = CONTAINER_ETC + '/init.d' | |
CONTAINER_NETWORK = CONTAINER_ETC + '/network' | |
CONTAINER_HAPROXY = CONTAINER_ETC + '/haproxy' | |
BASE_CONTAINER = '~/containers_base' | |
def create_domain(name): | |
container_path = Paths.CONTAINER_PATH.format(name) | |
container_etc = Paths.CONTAINER_ETC.format(name) | |
os.system('mkdir -p {0}'.format(container_path)) | |
os.system('cp -r {0}/* {1}'.format(Paths.BASE_CONTAINER, container_etc)) | |
domain_xml = ''' | |
<domain type="lxc"> | |
<name>{0}</name> | |
<memory>102400</memory> | |
<currentmemory>102400</currentmemory> | |
<vcpu>1</vcpu> | |
<os> | |
<type arch="x86_64">exe</type> | |
<init>/bin/startup.sh</init> | |
</os> | |
<clock offset="utc"> | |
<on_poweroff>destroy</on_poweroff> | |
<on_reboot>restart</on_reboot> | |
<on_crash>destroy</on_crash> | |
<devices> | |
<emulator>/usr/lib/libvirt/libvirt_lxc</emulator> | |
<filesystem accessmode="passthrough" type="mount"> | |
<source dir="{1}/etc/network"></source> | |
<target dir="/etc/network"> | |
</target></filesystem> | |
<filesystem accessmode="passthrough" type="mount"> | |
<source dir="{1}/etc/init.d"></source> | |
<target dir="/etc/init.d"> | |
</target></filesystem> | |
<filesystem accessmode="passthrough" type="mount"> | |
<source dir="{1}/etc/haproxy"></source> | |
<target dir="/etc/haproxy"> | |
</target></filesystem> | |
<interface type="network"> | |
<source network="default"></source> | |
</interface> | |
<console type="pty"> | |
<target port="0" type="lxc"> | |
</target></console> | |
</devices> | |
</clock></domain> | |
''' | |
domain_xml = domain_xml.format(name, container_path) | |
lxc_conn = libvirt.open('lxc:///') | |
domain = lxc_conn.defineXML(domain_xml) | |
if domain.create() == 0: | |
print '{0} domain created successfully.'.format(name) | |
return domain | |
else: | |
print '{0} did NOT create successfully.'.format(name) | |
def delete_domain(domain): | |
try: | |
domain.destroy() | |
domain.undefine() | |
except Exception as destroy_exception: | |
try: | |
domain.undefine() | |
except Exception as undefine_exception: | |
print undefine_exception | |
print 'Could not clean up domain.' | |
def delete_domain_by_name(name): | |
lxc_conn = libvirt.open('lxc:///') | |
try: | |
domain = lxc_conn.lookupByName(name) | |
except: | |
print 'Failed to find the domain {0}'.format(name) | |
return | |
delete_domain(domain) | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('container_name', metavar='container_name', type=str, | |
help='Name of container to create.') | |
parser.add_argument('-d', '--delete', action='store_true', | |
help='Delete container name specified.') | |
args = parser.parse_args() | |
if args.delete: | |
delete_domain_by_name(args.container_name) | |
else: | |
create_domain(args.container_name) |
Resources:
[1] http://libvirt.org/