Monday, January 24, 2011

Debian Squeeze/Testing LXC container patch

Prepare Debian Squeeze/Testing container

  1. Copy the following into file lxc-debian-testing. This is a modified version of /usr/lib/lxc/templates/lxc-debian to get it working with squeeze/testing release of dedian:
    #!/bin/bash
    
    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
    EOF
     
        # create tty devices
        chroot $rootfs mknod -m 666 /dev/tty1 c 4 1
        chroot $rootfs mknod -m 666 /dev/tty2 c 4 2
    
        # 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
    
        # set dhcp hostname
        cat <<EOF >> $rootfs/etc/dhcp/dhclient.conf
    send host-name "$hostname";
    EOF
    
        # set default locale
        cat <<EOF > $rootfs/etc/locale.gen
    en_US.UTF-8 UTF-8
    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 password is 'root', please change !"
    
        return 0
    }
    
    download_debian()
    {
        packages=\
    ifupdown,\
    locales,\
    libui-dialog-perl,\
    dialog,\
    isc-dhcp-client,\
    netbase,\
    net-tools,\
    iproute,\
    vim,\
    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 \
        testing $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-testing"
        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
    lxc.network.flags = up
    lxc.network.link = br0
    # It is fine to be commented out
    #lxc.network.ipv4 = 192.168.10.21/24
    # Change this
    # lxc.network.hwaddr = 00:11:22:33:44:00
    EOF
    
        if [ $? -ne 0 ]; then
            echo "Failed to add configuration"
            return 1
        fi
    
        return 0
    }
    
    clean()
    {
        cache="/var/cache/lxc/debian-testing"
    
        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
    
  2. Make the file executable:
    chmod +x lxc-debian-testing
    

Create LXC Linux Container

We are going create a linux container based on debian testing.
  1. Let give the machine name vm0.
    lxc1:~# mkdir -p /var/lib/lxc/vm0
    lxc1:~# ./lxc-debian-testing -p /var/lib/lxc/vm0 -n vm0
    debootstrap is /usr/sbin/debootstrap
    Checking cache download in /var/cache/lxc/debian-testing/rootfs-i386 ... 
    Downloading debian minimal ...
    ...
    Download complete.
    Copying rootfs to /var/lib/lxc/vm0/rootfs...Generating locales (this might take a while)...
      en_US.UTF-8... done
    Generation complete.
    ...
    Root password is 'root', please change !
    
  2. Set network adapter mac address (must be unique):
    lxc1:~# cd /var/lib/lxc/vm0
    lxc1:/var/lib/lxc/vm0# echo "lxc.network.hwaddr = 00:AF:22:33:44:00" >> config
    
  3. Make some clean up and backup:
    
    lxc1:/var/lib/lxc/vm0# chroot rootfs/
    root@lxc1:/# apt-get update && apt-get -y upgrade && apt-get clean && apt-get autoclean
    ...
    lxc1:/# exit
    lxc1:/var/lib/lxc/vm0# du -hs rootfs
    235M vm0
    lxc1:/var/lib/lxc/vm0# tar czf ../vm0.tgz config rootfs/
    lxc1:/var/lib/lxc/vm0# cd .. && ls -lh | grep tgz
    -rw-r--r-- 1 root root  80M vm0.tgz
    

No comments :

Post a Comment