LXC Configure Ubuntu Lucid Containers

February 2nd, 2010 by bodhi.zazen

In this post I will demonstrate how to use Ubuntu 10.04 as a Linux Container.

This post assumes you have configured your host, see my previous post if you need assistance configuring your host node.

This post has been updated. Since the original post I have learned a bit about the init scripts, learned about lxc, and ubuntu 10.04 was released. I found the majority of the problems with using LXC are with the boot scripts.

In this example I am installing LAMP, openssh-server, and UFW as I imagine these are popular options.You are free to install more or less , but these common tools serve as common examples and should allow you to adapt if you need additional or different services.

Basically we need to take 3 steps:

1. Use debootstrap install a (minimal) base system to be used as a container – use debootstrap to make a root file system (rootfs) for a LXC container using Ubuntu Lucid (10.04).

2. Generate a set of configuration files on the host.

3. Clean up the boot scripts within the container.

Note: Commands in this tutorial are run as root, so to obtain a root shell use:

sudo -i

Note: The working directory for this tutorial is /lxc , so config.ubuntu, fstab.ubuntu, and rootfs.ubuntu are both located in /lxc.

Make a rootfs via debootstrap

sudo -i
cd /lxc
debootstrap --variant=minbase --arch i386 lucid rootfs.ubuntu

Change “--arch i386″ to “--arch amd64″ for a 64 bit container.

Configure the container

Fix devices in rootfs.ubuntu/dev

This step is OPTIONAL !!. Use this script if you wish to minimize the devices in rootfs.ubuntu/dev (the defaults created with debootstrap work without any adjustments).


#!/bin/bash

# bodhi.zazen's lxc-config
# Makes default devices needed in lxc containers
# modified from http://lxc.teegra.net/

ROOT=$(pwd)
DEV=${ROOT}/dev
if [ $ROOT = '/' ]; then
printf "\033[22;35m\nDO NOT RUN ON THE HOST NODE\n\n"
tput sgr0
exit 1
fi
if [ ! -d $DEV ]; then
printf "\033[01;33m\nRun this script in rootfs\n\n"
tput sgr0
exit 1
fi
rm -rf ${DEV}
mkdir ${DEV}
mknod -m 666 ${DEV}/null c 1 3
mknod -m 666 ${DEV}/zero c 1 5
mknod -m 666 ${DEV}/random c 1 8
mknod -m 666 ${DEV}/urandom c 1 9
mkdir -m 755 ${DEV}/pts
mkdir -m 1777 ${DEV}/shm
mknod -m 666 ${DEV}/tty c 5 0
mknod -m 666 ${DEV}/tty0 c 4 0
mknod -m 666 ${DEV}/tty1 c 4 1
mknod -m 666 ${DEV}/tty2 c 4 2
mknod -m 666 ${DEV}/tty3 c 4 3
mknod -m 666 ${DEV}/tty4 c 4 4
mknod -m 600 ${DEV}/console c 5 1
mknod -m 666 ${DEV}/full c 1 7
mknod -m 600 ${DEV}/initctl p
mknod -m 666 ${DEV}/ptmx c 5 2

exit 0

The script is very slightly modified from This page and is saved in /usr/local/bin/lxc-config .

Make it executable :

chmod u+x /usr/local/bin/lxc-config

Run the script in rootfs.ubuntu

cd /lxc/rootfs.ubuntu
/usr/local/bin/lxc-config # fix /dev

Modify the rootfs

Edit the sources. Using any editor open /lxc/rootfs.ubuntu/etc/apt/sources.list and edit the contents to look like this :

deb http://us.archive.ubuntu.com/ubuntu/ lucid main universe multiverse
deb http://us.archive.ubuntu.com/ubuntu/ lucid-security main universe multiverse

chroot into rootfs.ubuntu and configure the container:

chroot /lxc/rootfs.ubuntu /bin/bash

Run the following commands in the chroot.

apt-get install --force-yes -y gpgv
apt-get update

# set locales
apt-get -y install language-pack-en
locale-gen en_US.UTF-8
/usr/sbin/update-locale LANG="en_US.UTF-8" LANGUAGE="en_US.UTF-8" LC_ALL="en_US.UTF-8" LC_CTYPE="C"

# Add to the installed applications
apt-get install -y adduser apt-utils console-setup iproute iptables mysql-server nano netbase openssh-blacklist openssh-blacklist-extra openssh-server php5 php5-mysql iputils-ping rsyslog sudo ufw vim

#Set a root passwd
passwd

# As an alternate to setting a root password, you may of course add a new user and configure sudo.

# Configure the hostname of the container and /etc/hosts
# Change "host_name" to your desired host name
# Change "192.168.0.60" to the ip address you wish to assign to the container
echo "host_name" > /etc/hostname
echo "127.0.0.1 localhost host_name" > /etc/hosts
echo "192.168.0.60 host_name" >> /etc/hosts

# Fix mtab
rm /etc/mtab
ln -s /proc/mounts /etc/mtab

Next edit /etc/environment and define your environmental variables:

LANG="en_US.UTF-8"
LANGUAGE="en_US.UTF-8"
LC_ALL="en_US.UTF-8"
LC_CTYPE="C"

Exit the chroot

#exit chroot
exit

Generate the HOST LXC configuration files

This is done on the host node and will set the container resources, networking, and confinement.

I call it config.ubuntu . Make sure the following information is accurate:

container name (lxc.utsname)
network (lxc.network.ipv4)
rootfs (lxc.rootfs)
fstab (lxc.mount)

/lxc/config.ubuntu

lxc.utsname = ubuntu
lxc.tty = 4
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.name = eth0
lxc.network.mtu = 1500
lxc.network.ipv4 = 192.168.0.10/24
lxc.rootfs = /lxc/rootfs.ubuntu
lxc.mount = /lxc/fstab.ubuntu
lxc.cgroup.devices.deny = a
# /dev/null and zero
lxc.cgroup.devices.allow = c 1:3 rwm
lxc.cgroup.devices.allow = c 1:5 rwm
# consoles
lxc.cgroup.devices.allow = c 5:1 rwm
lxc.cgroup.devices.allow = c 5:0 rwm
lxc.cgroup.devices.allow = c 4:0 rwm
lxc.cgroup.devices.allow = c 4:1 rwm
# /dev/{,u}random
lxc.cgroup.devices.allow = c 1:9 rwm
lxc.cgroup.devices.allow = c 1:8 rwm
# /dev/pts/* - pts namespaces are "coming soon"
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm

The following lines are critical !
lxc.network.ipv4 = 192.168.0.10/24
lxc.rootfs = /lxc/rootfs.ubuntu
lxc.mount = /lxc/fstab.ubuntu
lxc.cgroup.xxx

lxc.network.ipv4 sets the container ip address (192.168.0.10) and netmask ( /24 ).

lxc.rootfs instructs lxc-create to use pivot root rather then chroot and this is important for containment.

lxc.mount is a replacement for rootfs.ubuntu/etc/fstab . Use this file to define mount points in your container. This sample configuration file is the minimum, you may use bind to add shared directories.

lxc.cgroup.foo These lines define the resources available to the container (via cgroup).

Make a fstab for lxc

Do not confuse this with the host fstab !!

This file is used in place of rootfs.ubuntu/etc/fstab.

I call it fstab.ubuntu . Make sure the following information is accurate (use the full path):

/lxc/fstab.lucid

none /lxc/rootfs.ubuntu/dev/pts devpts defaults 0 0
none /lxc/rootfs.ubuntu/proc proc defaults 0 0
none /lxc/rootfs.ubuntu/sys sysfs defaults 0 0
none /lxc/rootfs.ubuntu/var/lock tmpfs defaults 0 0
none /lxc/rootfs.ubuntu/var/run tmpfs defaults 0 0
/etc/resolv.conf /lxc/rootfs.ubuntu/etc/resolv.conf none bind 0 0

Note: I am suggesting binding the host /etc/resolv.conf in the container for convenience. You may chattr +i /etc/resolv.conf if you wish.

Mount a shared directory: For example, to share /home between the host and your container add this line to fstab.ubuntu:

/home /lxc/rootfs.ubuntu/home none bind 0 0

Be sure to understand the security implications of sharing directories between the host and your containers.

Modify the init scripts

Many of the init (upstart) scripts are not necessary in LXC containers and will either fail, cause delays in starting your container, or send error messages (or all of the above).

Replacement init script

This script is essential. Starting a container (lxc-start) is NOT the same process as booting a computer. We have defined the mount points and networking in config.ubuntu and fstab.ubuntu . We need minimal boot scripts in our container.

In the case of Ubuntu the critical file we need to replace is rootfs.ubuntu/etc/init/rc-sysinit

rm -f /lxc/rootfs.ubuntu/etc/init/rc-sysinit
cat << EOF > /lxc/rootfs.ubuntu/init/rc-sysinit
#!/bin/bash
# Whatever is needed to clear out old daemon/service pids from your container
rm -f $(find /var/run -name '*pid')
rm -f /var/lock/apache/*

route add default gw 192.168.0.1

exit 0

EOF

chmod a+x /lxc/rootfs.ubuntu/etc/init/rc-sysinit

This script is modified from Here .

If you wish to use dhcp in your containers you will need to get the networking init scripts working and configure rootfs.ubuntu/etc/network/interfaces. It can be done, but IMO it is more hassle then using a static IP as the static IP is set in config.ubuntu as a “one liner” (see above).

Remove as many init scripts as possible

MAKE SURE YOU RUN THESE COMMANDS IN THE LXC ROOTFS

cd /lxc/rootfs.ubuntu/etc/init
rm -f console* control* hwclock* module* mount* network-interface* plymouth* procps* tty{4,5,6}.conf udev* upstart*

We should have only the following file (init scripts) in /lxc/rootfs.ubuntu/etc/init (remove any init scripts I overlooked in my list above).

mysql.conf
rc-sysinit
rc.conf
ufw.conf

As you can see, we need only a few scripts. ufw.conf is the easiest way, IMO, to enable UFW , if you do not use ufw you may remove it.

We need to edit mysql.conf and ufw.conf and change the start line to read:

start on startup

All the other services should start automatically. If they do not either edit the service .conf file (start on startup usually works) or add a line to start them in rc-sysconf .

With servers not covered in this tutorial, I suggest you move them to a back up location rather then delete them, they try starting your container. If your service does not start , restore the script and change the “start on startup” line in the service.conf file.

Enable iptables / UFW

Iptables / UFW seem to work well , but the LXC container wants to load the relevant kernel modules.

Here is what I did to enable iptables / UFW :

From the host run

mkdir rootfs.lucid/lib/modules/2.6.32-22-generic/kernel
cp /lib/modules/2.6.32-22-generic/modules.dep rootfs.lucid/lib/modules/2.6.32-22-generic/
cp -R /lib/modules/2.6.32-22-generic/kernel/net rootfs.lucid/lib/modules/2.6.32-22-generic/kernel/

You will need to change “2.6.32-22-generic” to your actual kernel and update the LXC container with kernel updates.

You should now be able to run iptables or UFW in the container (once it is started of course).

Create and manage the container

Create the container:

lxc-create -f /lxc/conf.ubuntu -n ubuntu

Start the container

lxc-start -n ubuntu

Assuming you get no error messages , you can start the container with the -d option.

lxc-start -n ubuntu -d

You should now be able to access the container with either lxc-console or ssh

ssh root@192.168.0.60

lxc-console -n ubuntu

Exit lxc-console with Ctrl-a q (you do not need to log out).

Stop the container from the host node

lxc-stop -n ubuntu

Destroy the container

lxc-destroy -n ubuntu

Oddities

Just a few odds and ends …

1. rsyslog logs to the HOST NODE /var/log files, not the container.

2. If you edit the configuration files (config.ubuntu or fstab.ubuntu) you will need to stop, destroy, and recreate the container. This is fast and does not affect the rootfs.

3. How much HD space / RAM does it use ?

On my test system w/ 1 Gb RAM running an xfce desktop (and browsing the web …)

rootfs.ubuntu takes up 474 Mb of HD space.

With the lucid container stopped I am using 402 Mb RAM.

When I start the lucid container I jump up to a whopping 419 Mb RAM.

4. X applications. IMO the easiest way to forward X applications (graphical applications) from the container to the host is with ssh -X.

For example ssh -X user@container_ip xeyes works fine.

Alternately you can use a vnc server , Xephyr, or configure one of your consoles (Ctrl-alt-f3).

StumbleUpon

Posted in Linux

31 Comments »

  1. [...] See original here: Shadows of epiphany » Blog Archive » LXC Configure Ubuntu Lucid … [...]

    Pingback by Shadows of epiphany » Blog Archive » LXC Configure Ubuntu Lucid … | Just linux! — February 5, 2010 @ 4:50 am

  2. Here is a good place where make community tutorials:
    https://help.ubuntu.com/community/LXC

    Comment by ng — March 20, 2010 @ 3:43 pm

  3. Is there any method to cache locally the packages downloaded by debootstrap?
    To improve speed when repeating the process.

    Comment by ng — March 20, 2010 @ 6:46 pm

  4. Why a have this?

    root@srv01:~# lxc-start -n proxy1
    lxc-start: No such file or directory – failed to mount ‘/home/lxc/proxy1/rootfs.ubuntu’->’/tmp/lxc-rdqdyBc’
    lxc-start: failed to set rootfs for ‘proxy1′
    lxc-start: failed to setup the container

    Comment by Osvaldo — March 22, 2010 @ 8:26 pm

  5. @ ng : yes there are several options :

    http://www.debian-administration.org/articles/426

    http://www.debian-administration.org/articles/338

    Comment by bodhi.zazen — March 22, 2010 @ 9:28 pm

  6. @ng : I agree. If you check that page you will see I have contributed to it as well. As this blog is not Ubuntu specific, I have been waiting for the Ubuntu developers to work on LXC, and again if you check Launchpad you will see the “bug reports” I have files.

    Comment by bodhi.zazen — March 22, 2010 @ 9:30 pm

  7. @Osvaldo: I updated your comment as it was the same command and error message 3 times.

    I can not tell from what you submitted, I suggest you either post on the Ubuntu forums or the LXC mailing list, be sure to include sufficient details

    Did you install the rootfs ? did you edit your config file ?

    Comment by bodhi.zazen — March 22, 2010 @ 9:32 pm

  8. How did you figure out the upstart hang problem?

    start on filesystem # and net-device-up IFACE=lo

    If I don’t comment the last part of that line out, the system hangs when booting and never comes up fully. If I DO comment it out, as above, networking never starts. Do you have any hints on how to figure this out?

    Great post! It made it a lot easier for me to create LXC guests.

    Comment by bronson — May 10, 2010 @ 4:54 pm

  9. @bronson Trial and error.

    I am going through the upstart scripts now and plan to blog on what to edit and what to fix.

    Try changing the line to:

    start on startup

    Comment by bodhi.zazen — May 10, 2010 @ 5:04 pm

  10. Changing it to ’start on startup’ works exactly as well as ’start on filesystem’ afaict. So it boots but I still see the missing network issue. I’ll try to write up my config and compare notes.

    Comment by bronson — May 10, 2010 @ 6:46 pm

  11. Since it is so important to follow this howto to the letter in order to have a working container, I trully appreciate those tons of time it took for bodhi.zazen to figure out all those things. Thank you again!

    Now I have a problem with mounting external directories inside virtual guest. I’ve posted a mail into the forum (http://ubuntuforums.org/showthread.php?p=9260568) a few days ago, but I believe it somehow escaped attention.
    It should be elementary to mount something inside the guest, just like it was in openvz, but I really don’t know how to do it. I would very appreciate a bit of advice from someone who knows how to do it.

    Comment by Adam Ryczkowski — May 13, 2010 @ 2:19 am

  12. @Adam Ryczkowski :

    I updated this post just today. See if adding a fstab file helps.

    Comment by bodhi.zazen — May 13, 2010 @ 1:08 pm

  13. ping 192.168.0.60
    PING 192.168.0.60 (192.168.0.60) 56(84) bytes of data.
    64 bytes from 192.168.0.60: icmp_seq=1 ttl=64 time=9.93 ms

    ssh root@192.168.0.60
    The authenticity of host ‘192.168.0.60 (192.168.0.60)’ can’t be established.
    RSA key fingerprint is d7:fb:e7:66:ea:d0:54:bb:16:80:64:0b:e8:98:94:95.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added ‘192.168.0.60′ (RSA) to the list of known hosts.
    root@192.168.0.60’s password:
    PTY allocation request failed on channel 0
    stdin: is not a tty

    What is it?

    Comment by Denis — May 21, 2010 @ 1:31 pm

  14. I did all commands wrote in this post. But then I had this problem:

    root@em:/# locale-gen en_US.UTF-8
    Generating locales…
    en_US.UTF-8… up-to-date
    Generation complete.

    root@em:/# /usr/sbin/update-locale LANG=”en_US.UTF-8″ LANGUAGE=”en_US.UTF-8″ LC_ALL=”en_US.UTF-8″ LC_CTYPE=”C”
    perl: warning: Setting locale failed.
    perl: warning: Please check that your locale settings:
    LANGUAGE = (unset),
    LC_ALL = (unset),
    LANG = “ru_UA.UTF-8″
    are supported and installed on your system.
    perl: warning: Falling back to the standard locale (“C”).
    root@em:/#

    Tell me, please, where I made a mistake

    Comment by Denis — May 21, 2010 @ 1:59 pm

  15. @Denis: Did you fix your devices (with the little script I posted)?

    My guess is a permissions problem on your devices.

    Did you try lxc-console ?

    Comment by bodhi.zazen — May 21, 2010 @ 2:20 pm

  16. Yes. I run your script:
    /usr/local/bin/lxc-config

    Comment by Denis — May 21, 2010 @ 2:42 pm

  17. Not sure, could be a few things.

    Are you working on a partition that is mounted nodev ?
    Did you clear out all the upstart init scripts ?
    What are you using for an init script ?
    What are the permissions in your rootfs/dev ?
    What did you mount in fstab.ubuntu ?
    Can you enter the container with lxc-console ?
    If so, what processes are running ?

    You may need to start a support thread somewhere =)

    From there you would need to start posting your config files.

    Comment by bodhi.zazen — May 21, 2010 @ 2:49 pm

  18. devpts should be mounted with ‘rw,noexec,nosuid,gid=5,mode=0620′, not ‘defaults’

    Comment by Vladimir — May 24, 2010 @ 7:02 am

  19. Container was working when I left fstab file is empty

    Comment by denis — May 24, 2010 @ 9:49 am

  20. Glad it is working. I suggest you confirm the syntax in the fstab line by line, isolation is better.

    Comment by bodhi.zazen — May 24, 2010 @ 11:58 am

  21. Did accordingly, but when I tried to execute from host as root:

    lxc-start -n ubuntu

    Got an error:

    lxc-start: no configuration file for ‘/sbin/init’ (may crash the host)

    Checked the /sbin/init and found to be binary both in the host and the container.

    Any hints? Thanks

    Comment by zenny — June 4, 2010 @ 12:37 pm

  22. @zenny -

    Did you make a configuration file for your lucid template ?

    Comment by bodhi.zazen — June 4, 2010 @ 12:40 pm

  23. I made /lxc/config.ubuntu which looks like:

    lxc.utsname = ubuntu
    lxc.tty = 4
    lxc.network.type = veth
    lxc.network.flags = up
    lxc.network.link = br0
    lxc.network.name = eth0
    lxc.network.mtu = 1500
    lxc.network.ipv4 = 192.168.20.0/24
    lxc.rootfs = /lxc/rootfs.ubuntu
    lxc.mount = /lxc/fstab.ubuntu
    lxc.cgroup.devices.deny = a
    # /dev/null and zero
    lxc.cgroup.devices.allow = c 1:3 rwm
    lxc.cgroup.devices.allow = c 1:5 rwm
    # consoles
    lxc.cgroup.devices.allow = c 5:1 rwm
    lxc.cgroup.devices.allow = c 5:0 rwm
    lxc.cgroup.devices.allow = c 4:0 rwm
    lxc.cgroup.devices.allow = c 4:1 rwm
    # /dev/{,u}random
    lxc.cgroup.devices.allow = c 1:9 rwm
    lxc.cgroup.devices.allow = c 1:8 rwm
    # /dev/pts/* – pts namespaces are “coming soon”
    lxc.cgroup.devices.allow = c 136:* rwm
    lxc.cgroup.devices.allow = c 5:2 rwm
    # rtc
    lxc.cgroup.devices.allow = c 254:0 rwm

    And /lxc/fstab.ubuntu which looks like:

    none /lxc/rootfs.ubuntu/dev/pts devpts defaults 0 0
    none /lxc/rootfs.ubuntu/proc proc defaults 0 0
    none /lxc/rootfs.ubuntu/sys sysfs defaults 0 0
    none /lxc/rootfs.ubuntu/var/lock tmpfs defaults 0 0
    none /lxc/rootfs.ubuntu/var/run tmpfs defaults 0 0
    /etc/resolv.conf /lxc/rootfs.ubuntu/etc/resolv.conf none bind 0 0

    Is there anything else that I need to create?

    Comment by zenny — June 4, 2010 @ 2:04 pm

  24. Looks fine so long as the network line is correct :

    lxc.network.ipv4 = 192.168.0.10/24

    This line sets the ip address of the container and netmask.

    Comment by bodhi.zazen — June 4, 2010 @ 5:45 pm

  25. changing the netmask and IP didn’t help either. Seems LXC is yet at par with ovz :-(

    Comment by zenny — June 5, 2010 @ 12:41 am

  26. yes, i found the same problem… but kernel 2.6.32-r7 works without user-cr

    Comment by steve — June 22, 2010 @ 9:38 am

  27. /lxc/rootfs.ubuntu/init/rc-sysinit should be
    /lxc/rootfs.ubuntu/etc/init/rc-sysinit

    Comment by Sean Whitney — July 7, 2010 @ 4:38 pm

  28. chmod a+x /lxc/rootfs.ubuntu/init/rc-sysinit
    should be
    chmod a+x /lxc/rootfs.ubuntu/etc/init/rc-sysinit

    Comment by SGI — July 8, 2010 @ 9:41 am

  29. Thank you two, will fix that.

    Comment by bodhi.zazen — July 8, 2010 @ 1:46 pm

  30. Hello everyone,
    First tnx for the great tutorial, I am very new to LXCs and I have few questions regarding it:

    1.I cannot start mysql …. when I use chroot I get “ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (111) ” and when I use container on the same rootfs “lxc-staer -n name /bin/bash” i get “ERROR 2002 (HY000): Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)” (In the second case there is no /var/run/mysqld) … pretty weird huh, I cant see what I am doing wrong?
    2. When I do lxc-start -n name after configuration…. it blocks, so I must run it with lxc-start -n name /bin/bash, does anyone knows why is that so?
    3.When I try using lxc-execute it says that smt. is wrong with cgroup, why is that so?

    Thank you VERY much in advance, every solution will be appreciated,
    Nikola

    Comment by Nikola — July 15, 2010 @ 11:57 am

  31. Still a problem with the rc-sysinit script

    cat < /lxc/rootfs.ubuntu/init/rc-sysinit

    should be

    cat < /lxc/rootfs.ubuntu/etc/init/rc-sysinit

    Even with this correction the script does not start when starting the container. I have to run it manually to set the gateway. Any ideas?

    Comment by Mark — August 9, 2010 @ 3:31 am

RSS feed for comments on this post. TrackBack URL

Leave a comment