--- author: email: mail@petermolnar.net image: https://petermolnar.net/favicon.jpg name: Peter Molnar url: https://petermolnar.net copies: - http://web.archive.org/web/20160905161411/https://petermolnar.net/lxc-on-debian-wheezy/ lang: en published: '2014-03-26T14:21:07+00:00' summary: LXC - container based virtualisation from scratch on Debian Wheezy - a slightly messy guide to start with tags: - server title: Setting up LXC containers with Debian 7 Wheezy from scratch --- *Forewords: I was trying finish this for nearly half a year. Sorry if some of the things are out of date for now.* For years I've been looking for the most effective virtualisation fitting my requirements. I'd tried VMware, Xen, even used - as user - Virtuozzo until I recently came across LXC[^1]. Even though LXC is not new, a lot of new shiny projects are aiming to utilise it a bit better, for example Docker[^2] What I want is a lightweight semi-virtualisation: a private, virtual network, with virtual containers for a specific task, with backup, clone and export options. This is exactly what LXC is good for. I'm using Debian Wheezy even though 3.10 kernel is highly recommended for LXC. **DISCLAIMER: This is not a copy-paste tutorial, the process is way more complicated than that.** ## Install required tools ``` {.bash} apt-get install lxc bridge-utils debootstrap ``` ## Mount cgroups add to `/etc/fstab`: cgroup /cgroup cgroup defaults 0 0 ``` {.bash} mkdir /cgroups mount cgroups ``` ## Create virtual network This is not the best way to create the network interface & make it persistent, but all other ways have failed for me so far for this specific case. The internal network will be 192.168.42.0/24, the host will have 192.168.42.1 and the first guest will be 192.168.42.10. The external address will be indicated with 10.0.0.1. Please adjust these according to your needs. Add these to `/etc/rc.local`: ``` {.bash} # script to setup a natted network for lxc guests CMD_BRCTL=/sbin/brctl CMD_IFCONFIG=/sbin/ifconfig CMD_IPTABLES=/sbin/iptables CMD_ROUTE=/sbin/route NETWORK_BRIDGE_DEVICE_NAT=lxc-bridge-nat HOST_NETDEVICE=eth0 PRIVATE_GW_NAT=192.168.42.1 PRIVATE_NETMASK=255.255.255.0 PUBLIC_IP=10.0.0.1 LXC_GUEST_NETWORK=192.168.42.0/24 LXC_GUEST1_IP=192.168.42.10 LXC_GUEST1_EXT_SSH_PORT=2222 ${CMD_BRCTL} addbr ${NETWORK_BRIDGE_DEVICE_NAT} ${CMD_BRCTL} setfd ${NETWORK_BRIDGE_DEVICE_NAT} 0 ${CMD_IFCONFIG} ${NETWORK_BRIDGE_DEVICE_NAT} ${PRIVATE_GW_NAT} netmask ${PRIVATE_NETMASK} promisc up ${CMD_IPTABLES} -t nat -A POSTROUTING -o ${HOST_NETDEVICE} -j MASQUERADE ${CMD_IPTABLES} -t nat -A POSTROUTING -d ${LXC_GUEST_NETWORK} -o eth0 -j SNAT --to-source ${PUBLIC_IP} ${CMD_IPTABLES} -t nat -A PREROUTING -d ${PUBLIC_IP} -p tcp -m tcp --dport ${LXC_GUEST1_EXT_SSH_PORT} -j DNAT --to-destination ${LXC_GUEST1_IP}:22 echo 1 > /proc/sys/net/ipv4/ip_forward ``` \_A useful source of this setup: <https://wiki.debian.org/LXC/SimpleBridge%5B%5E3%5D_> ## optinal: logical volume for guest If you're running LVM on the host ( it can make things easy & secure ), you can create a new lv per guest: ``` {.bash} LXC_GUEST1_NAME=lxc-1 lvcreate -L 16G -n ${LXC_GUEST1_NAME} vg0 mkfs.ext4 /dev/vg0/${LXC_GUEST1_NAME} mkdir /lxc/${LXC_GUEST1_NAME} echo -e "/dev/vg0/${LXC_GUEST1_NAME} /lxc/${LXC_GUEST1_NAME} ext4 defaults 0 0n" >> /etc/fstab mount -a ``` ## debootstrap the container ( install the bare operating system ) ``` {.bash} LXC_GUEST1_NAME=lxc-1 mkdir -p /lxc/${LXC_GUEST1_NAME} debootstrap --verbose --include ifupdown,locales,netbase,net-tools,iproute,openssh-server,vim wheezy /lxc/${LXC_GUEST1_NAME} http://http.debian.net/debian/ ``` ## Edit devices, inittab, configuration for the container ### Edit `/lxc/${LXC_GUEST1_NAME}/etc/inittab` as follows: ``` {.bash} # /etc/inittab: init(8) configuration. # $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $ # The default runlevel. id:2:initdefault: # Boot-time system configuration/initialization script. # This is run first except when booting in emergency (-b) mode. si::sysinit:/etc/init.d/rcS # What to do in single-user mode. ~:S:wait:/sbin/sulogin # /etc/init.d executes the S and K scripts upon change # of runlevel. # # Runlevel 0 is halt. l0:0:wait:/etc/init.d/rc 0 # Runlevel 1 is single-user. l1:1:wait:/etc/init.d/rc 1 # Runlevels 2-5 are multi-user. 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 # Runlevel 6 is reboot. l6:6:wait:/etc/init.d/rc 6 # Normally not reached, but fallthrough in case of emergency. z6:6:respawn:/sbin/sulogin # What to do when CTRL-ALT-DEL is pressed. ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now # /sbin/getty invocations for the runlevels. # # The "id" field MUST be the same as the last # characters of the device (after "tty"). # # Format: # ::: # 1:2345:respawn:/sbin/getty 38400 console ``` ### Create the devices needed in the container ``` {.bash} ROOT=/lxc/${LXC_GUEST1_NAME} DEV=${ROOT}/dev mv ${DEV} ${DEV}.old mkdir -p ${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 600 ${DEV}/console c 5 1 mknod -m 666 ${DEV}/tty0 c 4 0 mknod -m 666 ${DEV}/full c 1 7 mknod -m 600 ${DEV}/initctl p mknod -m 666 ${DEV}/ptmx c 5 2 ``` ### Create lxc configuration file in `/var/lib/lxc/${LXC_GUEST1_NAME}/config` ``` {.apache} # name lxc.utsname = ${LXC_GUEST1_NAME} # network lxc.network.type = veth lxc.network.flags = up lxc.network.link = lxc-br lxc.network.name = eth0 lxc.network.hwaddr = 00:FF:12:34:56:78 lxc.network.ipv4 = ${LXC_GUEST1_IP}/24 # lxc.network.ipv6 = # pts lxc.tty = 2 lxc.pts = 1024 # fs lxc.rootfs = /lxc/${LXC_GUEST1_NAME} # devices lxc.cgroup.devices.deny = a # /dev/null and zero lxc.cgroup.devices.allow = c 1:3 rwm # dev/null lxc.cgroup.devices.allow = c 1:5 rwm # dev/zero # consoles lxc.cgroup.devices.allow = c 5:1 rwm # dev/console lxc.cgroup.devices.allow = c 5:0 rwm # dev/tty lxc.cgroup.devices.allow = c 4:0 rwm # dev/tty0 # /dev/{,u}random lxc.cgroup.devices.allow = c 1:9 rwm # dev/urandom lxc.cgroup.devices.allow = c 1:8 rwm # dev/random lxc.cgroup.devices.allow = c 136:* rwm # dev/pts/* lxc.cgroup.devices.allow = c 5:2 rwm # dev/pts/ptmx # rtc lxc.cgroup.devices.allow = c 254:0 rwm # mount points lxc.mount.entry = devpts /lxc/${LXC_GUEST1_NAME}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0 lxc.mount.entry = proc /lxc/${LXC_GUEST1_NAME}/proc proc nosuid,noexec,nodev 0 0 lxc.mount.entry = sysfs /lxc/${LXC_GUEST1_NAME}/sys sysfs nosuid,nodev,noexec 0 0 lxc.mount.entry = tmpfs /lxc/${LXC_GUEST1_NAME}/dev/shm tmpfs nosuid,nodev,noexec,size=64m 0 0 ``` ## Boot the container ``` {.apache} lxc start -n ${LXC_GUEST1_NAME} -d ``` For initial setup, you might need the option without "-d", that will land you in the console of the container. [^1]: <http://lxc.sourceforge.net/> [^2]: <http://www.docker.io/>