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-checkconfigIf 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 2Check 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 -dand 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/initctlYou 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/w01where w01 is the container
http://alog.ipduh.com/2011/09/screen-basics.html