debian linux containers

Notes on LXC linux containers on debian Linux.

Install software
LXC - Userspace Interface for the Linux containment Features ( http://linuxcontainers.org/ )

bridge-utils - Software that connects Ethernet segments.

libvirt-bin - Library, API and shell that interacts with QEMU,KVM,LXC, and other "virtualization" technologies in Linux.

debootstrap - Shell Script that installs a Debian Base System into a directory of another system.

# apt-get update
# apt-get install lxc bridge-utils libvirt-bin debootstrap   


Set fstab to mount the Control Groups hierarchy on boot and mount it now.
# echo "cgroup  /sys/fs/cgroup  cgroup  defaults  0   0" > /etc/fstab
# mount /sys/fs/cgroup


Check the LXC configuration
# lxc-checkconfig 
If everything is green enable you are good to go.

Networking

There a few different ways to network a container. An easy way to access the container through the network is to set up a bridge interface.

Example of a bridge interface stanza in /etc/network/interfaces

auto lo
iface lo inet loopback


auto eth0
iface eth0 inet manual

auto br0
iface br0 inet static
 address 10.21.241.2
 netmask 255.255.255.128
 network 10.21.241.0
 broadcast 10.21.241.127
 gateway 10.21.241.99
 bridge_ports eth0
        bridge_stp off          
        bridge_waitport 0      
        bridge_fd 0             
        bridge_hello 2         
Check if your stanza works
# /etc/init.d/networking restart
# brctl show
bridge name bridge id  STP enabled interfaces
br0  8000.525400225dbc no  eth0


LXC templates

LXC templates are shell scripts that create LXC containers. The debian wheezy template that ships with lxc 0.8.0-rc1 is broken 680469. It says it is fixed now but I did not try it.

A debian wheezy template I stitched together with stuff I found in the internetz.
#!/bin/bash

#
# lxc: linux Container library

# Authors:
# Daniel Lezcano <daniel.lezcano@free.fr>

# 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

# ==============================================================
# This is a slightly modified version by Rob van der Hoeven
# I use it for my FreedomBox project: http://freedomboxblog.nl
# ==============================================================
# modified by g0, http://ipduh.com/contact
# ==============================================================

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

    # squeeze only has /dev/tty and /dev/tty0 by default,
    # therefore creating missing device nodes for tty1-4.
    for tty in $(seq 1 4); do
    if [ ! -e $rootfs/dev/tty$tty ]; then
       mknod $rootfs/dev/tty$tty c 4 $tty
    fi
    done

    # 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 
    cat <<EOF > $rootfs/etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
  address 192.168.169.170
  network 192.168.169.0
  netmask 255.255.255.0
  broadcast 192.168.169.255
  gateway 192.168.169.169

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

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

    return 0
}

download_debian()
{
    packages=\
ifupdown,\
locales,\
libui-dialog-perl,\
dialog,\
netbase,\
net-tools,\
iproute,\
openssh-server,\
vim,\
apt-utils

    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 \
 wheezy $cache/partial-$arch http://ftp.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-wheezy-g0-01"
    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

 if [ "$arch" == "armv5tel" ]; then
     arch=armel
 fi

    if [ "$arch" == "armv7l" ]; then
        arch=armhf
    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

# networking

lxc.utsname = $name
lxc.network.type = veth
lxc.network.flags = up
lxc.network.link = br0
lxc.network.ipv4 = 0.0.0.0/24
lxc.network.hwaddr = 00:1E:$(hex):$(hex):$(hex):$(hex)
EOF

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

    return 0
}

# nice trick from: http://mindref.blogspot.com/2011/01/debian-lxc-create.html
hex() 
{
    echo "`tr -dc A-F0-9 < /dev/urandom | head -c 2 | xargs`"
}
    
clean()
{
    cache="/var/cache/lxc/debian-wheezy-g0-01"

    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"
    echo "attempting to install debootstrap"
    apt-get install debootstrap
    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






     


Get my wheezy template and create a container
# wget kod.ipduh.com/lib/lxc-debian-wheezy-g0-01 
# chmod 744 lxc-debian-wheezy-g0-01 
# mv lxc-debian-wheezy-g0-01 /usr/share/lxc/templates/
# lxc-create -n w01 -t debian-wheezy-g0-01
...
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Root password is 'debian', please change!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
'debian-wheezy-g0-01' template installed
'w01' created



To adjust the container network
# vi /var/lib/lxc/w01/rootfs/etc/network/interfaces


Start the container
# lxc-start -n w01


You should get a console to the container
Debian GNU/Linux 7 w01 console

w01 login: 



You may start a container in the background.
# lxc-start -n w01 -d
and attach to the console later or even better later through a screen.
# lxc-console -n w02


If you used the 'template' above and you want to access the container from the network you will need to be in the 192.168.169.0/24 LAN or add the 192.168.169.169/24 to the host br0 interface.
root@lxchost# ifconfig br0:1 192.168.169.169 netmask 255.255.255.0
root@lxchost# ping 192.168.169.170
PING 192.168.169.170 (192.168.169.170) 56(84) bytes of data.
64 bytes from 192.168.169.170: icmp_req=1 ttl=64 time=1.11 ms
64 bytes from 192.168.169.170: icmp_req=2 ttl=64 time=0.067 ms
^C
--- 192.168.169.170 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms


You may access the container through the LAN or the LXC host virtual ethernet
root@lxchost# ssh root@192.168.169.170
The authenticity of host '192.168.169.170 (192.168.169.170)' can't be established.
ECDSA key fingerprint is a3:b9:e5:81:d7:26:d8:7e:95:0e:37:95:8c:77:16:0f.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.169.170' (ECDSA) to the list of known hosts.
root@192.168.169.170's password: 
Linux w02 3.2.0-4-amd64 #1 SMP Debian 3.2.51-1 x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Nov  1 12:13:23 2013
root@w01:~# 



See the status of a container
# lxc-info -n w01
state:   RUNNING
pid:     18109



Shutdown a container
# lxc-halt -n w01
telinit: timeout opening/writing control channel /run/initctl
You may need to console or ssh into the container and halt it
root@lxchost# lxc-console -n w01
root@w01:~# shutdown -h now
root@lxchost# lxc-stop -n w01
root@lxchost# lxc-info -n w02
state:   STOPPED
pid:        -1



Start container(s) automatically when the host boots
# ln -s /var/lib/lxc/w01/config /etc/lxc/auto/w01
where w01 is the container



http://alog.ipduh.com/2011/09/screen-basics.html