Making LXC (and Juju) fly on Ubuntu

If like me you use LXC containers a lot, and are often on the road, you might have also been frustrated about how network-hungry LXC is, in particular when used with Juju. I will show you how to make it automagically use a deb packages cache, to drastically speed up subsequent downloads and installations.

Installing the cache client

We'll use a clever piece of software called "squid-deb-proxy-client" to do the heavy lifting for us. On the host of your LXC installation, simply pull in and install it with:

sudo apt-get install squid-deb-proxy-client

This will add a little script that detects squid-deb-proxies on your networks via multicast DNS, so that APT will use a proxy if it finds one. More information about this awesome piece of software can be found here .

It's great - I have a small local cache (10Gb) on my laptop (inside an LXC container), and a bigger one on my home network (40Gb). This allows APT to always know what is available.

Enter LXC hooks

We don't want to have to install the package on every LXC container we spawn, so instead, we'll inject the detected proxy setting in the container's apt config when it boots. LXC provides a very handy "hooks" mechanism for that, so we simply need to drop a script somewhere and add a simple config line in the container's config file:

# In /var/lib/lxc/<container name>/config,
lxc.hook.pre-start=/path/to/an/executable/script

The script will now be run before LXC starts a new container. It is passed some handy environment variables to help us tweak the container's apt config before it starts.

The code

It's not rocket science - simply query the little executable provided by squid-apt-proxy-client, and write the found URLs in the container's /etc/apt/apt.conf.d/ directory (in an aptly named "50squid-deb-proxy" file).

Instead of reproducing the code here, I encourage you to download it from github instead:

curl -L http://git.io/YlfYIQ | sudo tee /usr/share/lxc/hooks/squid-deb-proxy-client
sudo chmod +x /usr/share/lxc/hooks/squid-deb-proxy-client

As an added bonus, the script checks for similar config files in the host, and forwards it directly to the guest. That means nested containers will also benefit from the caches the host can see :)

You just need to edit your container's config file and point it at the hook:

# Append the following to /var/lib/lxc/<container>/config
lxc.hook.pre-start=/usr/share/lxc/hooks/squid-deb-proxy-client

A small workaround is needed for the time being, where you need to grant the pre-start hook apparmor privileges to interact with dbus. It's quite easy however, as simply adding:

dbus,

to the beginning of the /etc/apparmor.d/abstractions/lxc/start-container file will do the trick. That will not be necessary in future releases of LXC in Ubuntu, but is required at the time of this writing.

More awesome with templates!

Even better, we can use the same technique to make creating completely new LXC images much faster too! Creating a container for a new Ubuntu release can take a little bit of time since debootstrap needs to download all of the base packages, that can take a while on a slow internet connection or when you do this several times a day.

Changing the base Ubuntu template to check for squid-deb-proxy servers using the same mechanism when it's not supplied any other HTTP or apt proxy (we don't want to override user input obviously) solves that problem.

The code

It is a little more involved than simply adding a pre-start hook, as you'll need to modify the Ubuntu template for this to work.

Here is an already patched version you can immediately use:

# backup your existing template
sudo mv /usr/share/lxc/templates/lxc-ubuntu /usr/share/lxc/templates/BACKUP.lxc-ubuntu
curl -L http://git.io/VJ7ZUQ | sudo tee /usr/share/lxc/templates/lxc-ubuntu
sudo chmod +x /usr/share/lxc/templates/lxc-ubuntu

Creating a new LXC container will now use the proxy for the debootstrap phase as well!

Playing with Juju

It all comes together quite nicely when adding the proxy pre-start hook on the lxc-ubuntu-cloud template as well, since that will make all new containers spawned with Juju use the cache too! Great for when you need to rapidly spawn environments for development!:

# backup your existing template
sudo mv /usr/share/lxc/templates/lxc-ubuntu-cloud /usr/share/lxc/templates/BACKUP.lxc-ubuntu-cloud
curl -L http://git.io/CIAkrA | sudo tee /usr/share/lxc/templates/lxc-ubuntu-cloud
sudo chmod +x /usr/share/lxc/templates/lxc-ubuntu-cloud

Conclusion

These tricks really save me a considerable amount of time on my daily business deploying containers, and since I hope it'll help other people too I'll submit the patched templates and new hook to the core LXC code.

Hope this helps!