End to end LXC install on Ubuntu Xenial

After couple of people asking me about complete LXC setup on Ubuntu, I decided to write an ultimate guide on how to start with these containers on your home network.

Advantages of LXC over heavy virtualization or docker:

  • They're light, as light as docker
  • They're slightly more persistent than docker, meaning you can run services inside them

This guide will show you how to:

  • Install and configure LXC container system
  • Bootstrap a base image
  • Setup basic network bridge with your local network
  • Clone this image to create more containers

Here are prerequisites:

  • AMD64/ARM64/ARM32 machine (yes, it works on Odroid and Raspberry too)
  • Ubuntu 15.10/16.04 installed
  • Local network, meaning your WiFi router for DHCP and DNS

Let's get started then!

Installing LXC

The best and the most up to date way to get current packages would be to add ppa:ubuntu-lxc/lxd-stable to your apt repos:

add-apt-repository ppa:ubuntu-lxc/lxd-stable  

If you don't have add-apt-repository, then you will need to apt-get python-software-properties and software-properties-common packages first.

Now we can pull package updates and actually install LXC:

apt-get update  
apt-get install lxc  

Easy, we'll leave it at this for a moment, let's get to setting up our network.

Network setup

The easiest way to use LXC is to use the builtin lxcbr0 bridge interface that will be created upon install, but this has some side effects:

  • It uses dnsmasq to setup DNS and DHCP addresses
  • Containers are isolated in a host-only network, so one needs to create port redirects to pull services out to host IP

The most common way that I'm using for my everyday experimentation is to create a network bridge directly to my home network. This way you don't need to worry about redirecting anything, as you will get DNS/DHCP configured by your home router.

To setup a network bridge in Ubuntu, you need to install bridge-utils package and have a look at the following tutorial:

https://help.ubuntu.com/community/NetworkConnectionBridge

In short, you need to type following in your /etc/network/interfaces:

# The loopback network interface
auto lo  
iface lo inet loopback

auto eno1  
iface eno1 inet manual

auto br0  
iface br0 inet dhcp  
    bridge-ifaces eno1
    bridge-ports eno1
    up ifconfig eno1 up

Remember to replace eno1 with your locally detected interface, obtained by looking at the output of ifconfig. Restart after making changes to this file.

Once your system rebooted, you should be able to see a br0 interface added, with an IP address on it.

There are far more advanced networking options available, including GRE tunnels, VPN, multicasts and so on, for that you need to go and look at Flockport's articles:

https://www.flockport.com/connecting-lxc-hosts-with-gre-tunnels/

Okay, basic network setup is completed now, time to setup our base OS image.

Setting up first LXC image (the template)

Let's setup our first debootstrapped image on LXC, it's as easy as invoking this command:

lxc-create -n template-ubuntu-xenial -t ubuntu -- -r xenial  

After a moment of deboostrap running, we'll have a fresh image of Ubuntu Xenial pulled, we can check that with a following command:

lxc-ls --fancy

NAME                                  STATE   AUTOSTART GROUPS IPV4         IPV6  
template-ubuntu-xenial          STOPPED 0         -      -            -  

Now let's change the default network interface to point to our br0 bridge that we created earlier. For that, we'll need to edit the /var/lib/lxc/template-ubuntu-xenial/config file, and change the line with interfaces to look like this:

lxc.network.link = br0  

For a moment we'll leave it at this. Now you need to start your container:

lxc-start -d -n template-ubuntu-xenial  

Check what IP address does it have:

lxc-ls --fancy

NAME STATE   AUTOSTART GROUPS IPV4         IPV6  
template-ubuntu-xenial STOPPED 0 -     10.21.34.188 -  

Great, we have an IP address from our local network.

This is the moment when you can SSH into the new container, remember that Ubuntu has a default ubuntu/ubuntu user.
After customising the template container, we need to shut it down:

lxc-stop -d -n template-ubuntu-xenial  

That's it, our template is done.

Cloning the template into further containers

Now we can begin stamping the template into clones:

lxc-clone -s -B overlayfs -n child1-xenial-$(date +%s) template-ubuntu-xenial

Created container child1-xenial-1463170628 as snapshot of template-ubuntu-xenial

lxc-start -d -n child1-xenial-1463170628  

What we did here, is we've created a child1-xenial-1463170628 container that is based on our template and uses a differential storage backend (overlayfs).

Let's check whether the child is started properly:

lxc-ls --fancy

NAME                                  STATE   AUTOSTART GROUPS IPV4         IPV6  
template-ubuntu-xenial          STOPPED 0         -      -            -  
child1-xenial-1463170628          RUNNING 0         -      10.21.34.189            -  

That's it, you can now SSH into the child container and do your stuff, it's like another brand new Ubuntu.

To destroy a container, you need to stop it first:

lxc-stop -n child1-xenial-1463170628  
lxc-destroy -n child1-xenial-1463170628

Destroyed container child1-xenial-1463170628  
comments powered by Disqus