Lxc

From Oh Mad Lab
Jump to navigation Jump to search

Install Linux Containers (lxc)

Setup Host

  • Install the following
aptitude install bridge-utils libcap2-bin lxc debootstrap
  • Setup Bridging for lxc
vim /etc/network/interfaces

I changed:

allow-hotplug eth0
#iface eth0 inet static
#       address 192.168.0.60
#       netmask 255.255.255.0
#       network 192.168.0.0
#       broadcast 192.168.0.255
#       gateway 192.168.0.5

To the following:

auto br0
iface br0 inet static
        address 192.168.0.60
        netmask 255.255.255.0
        gateway 192.168.0.5
        bridge_ports eth0
        bridge_fd 0
  • Create a directory for the cgroup
mkdir /share/cgroup
  • Setup cgroup to mount automatically
vim /etc/fstab

I added:

cgroup          /share/cgroup   cgroup  defaults        0       0

Then run:

mount cgroup
  • Make sure everything is fine
lxc-checkconfig

I had the following:

Cgroup memory controller: missing

It's not required, but allows for allocating memory. Looks like it's being left out due to it not being optimized and will chew 2% to 3% of the CPU, etc.

  • Create a workspace:
mkdir /var/lib/lxc/lupin-captivate

Containers

You can either do the default lenny container, which already has a template or you can create the squeeze template + container.

Lenny Guest (old)

  • Debootstrap the debian image for the new vm container:
/usr/lib/lxc/templates/lxc-debian -p /var/lib/lxc/lupin-captivate

Squeeze Guest (new)

Creating the Template
  • At the time of this documentation, lxc only had a lenny template (see above), so for squeeze we must roll our own.
 vim /usr/lib/lxc/templates/lxc-debian-squeeze
  • Add the following
#!/bin/bash

#
# lxc: linux Container library

# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>
# Hayden Owens <ohayden#gmail#com>

# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.

# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.

# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

configure_debian()
{
    rootfs=$1
    hostname=$2

    # configure the inittab
    cat <<EOF > $rootfs/etc/inittab
id:3:initdefault:
si::sysinit:/etc/init.d/rcS
l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin
1:2345:respawn:/sbin/getty 38400 console
c1:12345:respawn:/sbin/getty 38400 tty1 linux
c2:12345:respawn:/sbin/getty 38400 tty2 linux
c3:12345:respawn:/sbin/getty 38400 tty3 linux
c4:12345:respawn:/sbin/getty 38400 tty4 linux
EOF

    # disable selinux in debian
    mkdir -p $rootfs/selinux
    echo 0 > $rootfs/selinux/enforce

    # configure the network using the dhcp
    cat <<EOF > $rootfs/etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet dhcp
EOF

    # set the hostname
    cat <<EOF > $rootfs/etc/hostname
$hostname
EOF

    # reconfigure some services
    if [ -z "$LANG" ]; then
	chroot $rootfs locale-gen en_US.UTF-8
	chroot $rootfs update-locale LANG=en_US.UTF-8
    else
	chroot $rootfs locale-gen $LANG
	chroot $rootfs update-locale LANG=$LANG
    fi

    # remove pointless services in a container
    chroot $rootfs /usr/sbin/update-rc.d -f umountfs remove
    chroot $rootfs /usr/sbin/update-rc.d -f hwclock.sh remove
    chroot $rootfs /usr/sbin/update-rc.d -f hwclockfirst.sh remove

    # create tty devices
    chroot $rootfs mknod -m 666 /dev/tty1 c 4 1
    chroot $rootfs mknod -m 666 /dev/tty2 c 4 2

    echo "root:root" | chroot $rootfs chpasswd
    echo "Root password is 'root', please change !"

    return 0
}

download_debian()
{
    packages=\
ifupdown,\
locales,\
libui-dialog-perl,\
dialog,\
isc-dhcp-client,\
netbase,\
net-tools,\
iproute,\
vim,\
wget,\
iputils-ping,\
screen,\
openssh-server

    cache=$1
    arch=$2

    # check the mini debian was not already downloaded
    mkdir -p "$cache/partial-$arch"
    if [ $? -ne 0 ]; then
        echo "Failed to create '$cache/partial-$arch' directory"
        return 1
    fi

    # download a mini debian into a cache
    echo "Downloading debian minimal ..."
    debootstrap --verbose --variant=minbase --arch=$arch \
        --include $packages \
        squeeze $cache/partial-$arch http://ftp.us.debian.org/debian
    if [ $? -ne 0 ]; then
        echo "Failed to download the rootfs, aborting."
        return 1
    fi

    mv "$1/partial-$arch" "$1/rootfs-$arch"
    echo "Download complete."

    return 0
}

copy_debian()
{
    cache=$1
    arch=$2
    rootfs=$3

    # make a local copy of the minidebian
    echo -n "Copying rootfs to $rootfs..."
    cp -a $cache/rootfs-$arch $rootfs || return 1
    return 0
}

install_debian()
{
    cache="/var/cache/lxc/debian-squeeze"
    rootfs=$1
    mkdir -p /var/lock/subsys/
    (
        flock -n -x 200
        if [ $? -ne 0 ]; then
            echo "Cache repository is busy."
            return 1
        fi

        arch=$(arch)
        if [ "$arch" == "x86_64" ]; then
            arch=amd64
        fi

        if [ "$arch" == "i686" ]; then
            arch=i386
        fi

        echo "Checking cache download in $cache/rootfs-$arch ... "
        if [ ! -e "$cache/rootfs-$arch" ]; then
            download_debian $cache $arch
            if [ $? -ne 0 ]; then
                echo "Failed to download 'debian base'"
                return 1
            fi
        fi

        copy_debian $cache $arch $rootfs
        if [ $? -ne 0 ]; then
            echo "Failed to copy rootfs"
            return 1
        fi

        return 0

        ) 200>/var/lock/subsys/lxc

    return $?
}

copy_configuration()
{
    path=$1
    rootfs=$2
    name=$3

    cat <<EOF >> $path/config
lxc.tty = 4
lxc.pts = 1024
lxc.rootfs = $rootfs
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
lxc.cgroup.devices.allow = c 136:* rwm
lxc.cgroup.devices.allow = c 5:2 rwm
# rtc
lxc.cgroup.devices.allow = c 254:0 rwm

# mounts point
lxc.mount.entry=proc $rootfs/proc proc nodev,noexec,nosuid 0 0
lxc.mount.entry=devpts $rootfs/dev/pts devpts defaults 0 0
lxc.mount.entry=sysfs $rootfs/sys sysfs defaults  0 0

lxc.utsname = $name
lxc.network.type = veth
# up = start up with host
lxc.network.flags = up
lxc.network.link = br0
# FLC - TODO - UNCOMMENT AND CONIFGURE THESE:
# container's mac address
#lxc.network.hwaddr = 00:aa:bb:cc:00:01
# container's ip address
#lxc.network.ipv4 = 192.168.0.230/24

# flc - change theses
#lxc.network.ipv4 = 192.168.0.230/24
#lxc.network.hwaddr = 00:aa:bb:cc:dd:00
EOF

    if [ $? -ne 0 ]; then
        echo "Failed to add configuration"
        return 1
    fi

    return 0
}

clean()
{
    cache="/var/cache/lxc/debian-squeeze"

    if [ ! -e $cache ]; then
        exit 0
    fi

    # lock, so we won't purge while someone is creating a repository
    (
        flock -n -x 200
        if [ $? != 0 ]; then
            echo "Cache repository is busy."
            exit 1
        fi

        echo -n "Purging the download cache..."
        rm --preserve-root --one-file-system -rf $cache && echo "Done." || exit 1
        exit 0

    ) 200>/var/lock/subsys/lxc
}

usage()
{
    cat <<EOF
$1 -h|--help -p|--path=<path> --clean
EOF
    return 0
}

options=$(getopt -o hp:n:c -l help,path:,name:,clean -- "$@")
if [ $? -ne 0 ]; then
        usage $(basename $0)
        exit 1
fi
eval set -- "$options"

while true
do
    case "$1" in
        -h|--help)      usage $0 && exit 0;;
        -p|--path)      path=$2; shift 2;;
        -n|--name)      name=$2; shift 2;;
        -c|--clean)     clean=$2; shift 2;;
        --)             shift 1; break ;;
        *)              break ;;
    esac
done

if [ ! -z "$clean" -a -z "$path" ]; then
    clean || exit 1
    exit 0
fi

type debootstrap
if [ $? -ne 0 ]; then
    echo "'debootstrap' command is missing"
    exit 1
fi

if [ -z "$path" ]; then
    echo "'path' parameter is required"
    exit 1
fi

if [ "$(id -u)" != "0" ]; then
    echo "This script should be run as 'root'"
    exit 1
fi

rootfs=$path/rootfs

install_debian $rootfs
if [ $? -ne 0 ]; then
    echo "failed to install debian"
    exit 1
fi

configure_debian $rootfs $name
if [ $? -ne 0 ]; then
    echo "failed to configure debian for a container"
    exit 1
fi

copy_configuration $path $rootfs $name
if [ $? -ne 0 ]; then
    echo "failed write configuration file"
    exit 1
fi

if [ ! -z $clean ]; then
    clean || exit 1
    exit 0
fi
  • Look for "# FLC - TODO - UNCOMMENT AND CONIFGURE THESE" and change ip and mac address, then mark the file as executable
 chmod +x /usr/lib/lxc/templates/lxc-debian-squeeze
Creating the Container
  • Debootstrap the debian image for the new vm container:
/usr/lib/lxc/templates/lxc-debian-squeeze -p /var/lib/lxc/lupin-squeeze

Setup Guest

<guest name> is the name of guest from above. In my case is either lupin-captivate or lupin-squeeze.

  • Configure the container
vim /var/lib/lxc/<guest name>/config

I added the following:

lxc.utsname = <guest name>
lxc.network.type = veth
# up = start up with host
lxc.network.flags = up
lxc.network.link = br0
# container's mac address
lxc.network.hwaddr = 00:aa:bb:cc:00:01
# container's ip address
lxc.network.ipv4 = 192.168.0.230/24
  • Fix the containers network interface
vim /var/lib/lxc/<guest name>/rootfs/etc/network/interfaces

I changed to:

auto eth0
iface eth0 inet static
        address 192.168.0.230
        netmask 255.255.255.0
        network 192.168.0.0
        broadcast 192.168.0.255
        gateway 192.168.0.5
  • Start the container in daemon mode
lxc-start -n <guest name> -d
  • Connect to the console
lxc-console -n <guest name>
  • Login in with root (default password is root as well, which you should change)

Tips

  • Start container
lxc-start -n lupin-captivate
  • Start container in daemon mode
lxc-start -n lupin-captivate -d
  • Connect to container in daemon mode
lxc-console -n lupin-captivate
  • Container status
lxc-info -n lupin-captivate
  • Stop the container (whilst in in the container)
poweroff
  • Stop the container from the host
lxc-stop -n lupin-captivate
  • Hibernate the container
lxc-freeze -n lupin-captivate
  • Restore container from hibernation
lxc-unfreeze -n lupin-captivate
  • Running graphical apps

On the host:

Xephyr -ac :1 -screen 1280x960

In the container:

export DISPLAY=<host name>:1

If you want to use export in a bash script then you need to separate the setter and export:

DISPLAY=<host name>:1
export DISPLAY

Now you can run any graphical program and the display will be redirected to the host. Another tip is to install "openbox" on the guest and run that along with any graphic program so it will give you a nice light weight window manger.