LXD networking: lxdbr0 explained

Recently, LXD stopped depending on lxc, and thus moved to using its own bridge, called lxdbr0. lxdbr0 behaves significantly differently than lxcbr0: it is ipv6 link local only by default (i.e. there is no ipv4 or ipv6 subnet configured by default), and only HTTP traffic is proxied over the network. This means that e.g. you can't SSH to your LXD containers with the default configuration of lxdbr0.

The motivation for this change mostly to avoid picking subnets for users, because this can cause breakage, and have users pick their own subnets. Previously, the script that set up lxcbr0 looked around on the host's network, and picked the first 10.0.*.1 address for the bridge that was available. Of course, in some cases (e.g. networks which weren't visible at the time of bridge creation) this can break routing for users' networks.

So, if you want to have parity with lxcbr0, you'll need to configure the bridge yourself. There are a few ways to do this. For a step by step walkthrough of just configuring the bridge, simply do:

sudo dpkg-reconfigure -p medium lxd

And answer the questions however you like. If you've never configured LXD at all (and e.g. want to use a fancy filesystem like ZFS), try:

sudo lxd init

Which will configure all of LXD (both the filesystem and lxdbr0). Finally, you can edit the file /etc/default/lxd-bridge and then do a:

sudo service lxd-bridge stop && sudo service lxd restart

For feature parity with lxcbr0, you can use something like the following (note the 10.0.4.*, so as not to conflict with lxcbr0):

# Whether to setup a new bridge or use an existing one

# Bridge name
# This is still used even if USE_LXD_BRIDGE is set to false
# set to an empty value to fully disable

# Path to an extra dnsmasq configuration file

# DNS domain for the bridge

# IPv4
## IPv4 address (e.g.

## IPv4 netmask (e.g.

## IPv4 network (e.g.

## IPv4 DHCP range (e.g.,

## IPv4 DHCP number of hosts (e.g. 250)

## NAT IPv4 traffic

# IPv6
## IPv6 address (e.g. 2001:470:b368:4242::1)

## IPv6 CIDR mask (e.g. 64)

## IPv6 network (e.g. 2001:470:b368:4242::/64)

## NAT IPv6 traffic

# Run a minimal HTTP PROXY server

And that's it! That's all you need to do to configure lxdbr0.

Sometimes, though, you don't really want your containers to live on a separate network than the host because you want to ssh to them directly or something. There are a few ways to accomplish this, the simplest is with macvlan:

lxc profile device set default eth0 parent eth0
lxc profile device set default eth0 nictype macvlan

Another way to do this is by adding another bridge which is bridged onto your main NIC. You'll need to edit your /etc/network/interfaces.d/eth0.cfg to look like this:

# The primary network interface
auto eth0
iface eth0 inet manual # note the manual here

And then add a bridge by creating /etc/network/interfaces.d/containerbr.cfg with the contents:

auto containerbr
iface containerbr inet dhcp
  bridge_ports eth0

Finally, you'll need to change the default lxd profile to use your new bridge:

lxc profile device set default eth0 parent containerbr

Restart the networking service (which if you do it over ssh, may boot you :), and away you go. If you want some of your containers to be on one bridge, and some on the other, you can use different profiles to accomplish this.

linux.conf.au 2016 talk

Last week I did this ridiculous thing where I flew around the world in the easterly direction, giving talks at FOSDEM and linux.conf.au. The linux.conf.au staff always do a great job of making talk videos, and this year was no exception.

My talk was on LXD and live migration, a brief history of both as well as a status update and some discussion of future work on both. There were also lots of questions in this talk, so there's a lot of discussion of basic migration questions and inner workings.

Unforatunately, I can't embed it here, so I'll give you a link instead. Also, keep in mind at the time I was giving this talk I had been up for ~40 hours, so I forgot some English words here and there :)


Amazing Grace

Having sung competitively in several a capella choirs, I've always loved gospel music. As I was traveling back from South Africa recently, I watched the movie American Gangster, which has a particularly fantastic arrangement of Amazing Grace. Unfortunately, I can't find a non-movie version of it (it's uncredited on the soundtrack), but I'd very much appreciate a link to where to buy it if someone finds it.

Nicki Minaj - Only

I love the hook from this song, which I suppose means the production is great. Dr. Luke strikes again.

Meshuggah - Lethargica

The (Ophidian Trek) live version of Meshuggah's Lethargica is awesome; it is almost a completely different song than the album version, because of the tempo slowing down at various points in the song. This matches the lyrics (which are great), and gives you the feeling of a lurching machine.

Halsey - Gasoline

Halsey has kind of an interesting story. I know I've heard some of her music before, but this song caught my ear on the radio of the internets today.

Song 2

Where would my sense of humor be if the second tune I posted here wasn't Blur's Song 2? This is a track that I listened to a lot in high school, and most recently I've heard in an ad on TV somewhere, which I think means I'm getting old. Anyway, woohoo!

Blog o' tunes

For a while now I've been kicking around the idea of trying to post one song a week that I've enjoyed. Mostly as an archival tool for myself, but also potentially to share with others. I was hoping to write a little bit about why I like each song as well, but to start out with I'm just going to try to post one track a week.

Anyway, here's a pretty kickass piano tune. I like piano stuff in minor keys.

Using the LXD API from Python

After our recent splash at ODS in Vancouver, it seems that there is a lot of interest in writing some python code to drive LXD to do various things. The first option is to use pylxd, a project maintained by a friend of mine at Canonical named Chuck Short. However, the primary client of this is OpenStack, and thus it is python2. We also don't want to add a lot of dependencies in this module, so we're using raw python urllib and friends, which as you know can sometimes be...painful :)

Another option would be to use python's awesome requests module, which is considerably more user friendly. However, since LXD uses client certificates, it can be a bit challenging to get the basic bits going. Here's a small program that just does some GETs to the API, to see how it might work:

import os.path

import requests

conf_dir = os.path.expanduser('~/.config/lxc')
crt = os.path.join(conf_dir, 'client.crt')
key = os.path.join(conf_dir, 'client.key')

print(requests.get('', verify=False, cert=(crt, key)).text)

which gives me (piped through jq for sanity):

$ python3 lxd.py | jq .
  "type": "sync",
  "status": "Success",
  "status_code": 200,
  "metadata": {
    "api_compat": 1,
    "auth": "trusted",
    "config": {
      "trust-password": true
    "environment": {
      "backing_fs": "ext4",
      "driver": "lxc",
      "kernel_version": "3.19.0-15-generic",
      "lxc_version": "1.1.2",
      "lxd_version": "0.9"

It just piggy backs on the lxc client generated certificates for now, but it would be great to have some python code that could generate those as well!

Another bit I should point out for people is lxd's --debug flag, which prints out every request it receives and response that it sends. I found this useful while developing the default lxc client, and it will probably be useful to those of you out there who are developing your own clients.

Happy hacking!

Live Migration in LXD

There has been a lot of interest on the various mailing lists as well as internally at Canonical about the state of migration in LXD, so I thought I'd write a bit about the current state of affairs.

Migration in LXD today passes the "Doom demo" test, i.e. it works well enough to reproduce the LXD announcement demo under certain conditions, which I'll cover below. There is still a lot of ongoing work to make CRIU (the underlying migration technology) work with all these configurations, so support will eventually arrive for everything. For now, though, you'll need to use the configuration I describe below.

First, I should note that things currently won't work on a systemd host. Since systemd re-mounts the rootfs as MS_SHARED, lots of things automatically become shared mounts, which confuses CRIU. There are several mailing list threads about ongoing work with respect to shared mounts in CRIU and I expect something to be merged that will resolve the situation shortly, but for now your host machine needs to be a non-systemd host (i.e. trusty or utopic will work just fine, but not vivid).

You'll need to install the daily versions of liblxc and lxd from their respective PPAs on each host:

sudo apt-add-repository -y ppa:ubuntu-lxc/daily
sudo apt-add-repository -y ppa:ubuntu-lxc/lxd-git-master
sudo apt-get update
sudo apt-get install lxd

Also, you'll need to uninstall lxcfs on both hosts:

sudo apt-get remove lxcfs

liblxc currently doesn't support migrating the mount configuration that lxcfs uses, although there is some work on that as well. The overmounting issue has been fixed in lxcfs, so I expect to land some patches in liblxc soon that will make lxcfs work.

Next, you'll want to set a password for your new lxd instance:

lxc config set password foo

You need some images in lxd, which can be acquired easily enough by lxd-images (of course, this only needs to be done on the source host of the migration):

lxd-images import lxc ubuntu trusty amd64 --alias ubuntu

You'll also need to set a few configuration items in lxd. First, the container needs to be privileged, although there is yet more ongoing work to remove this restriction. There are also a few things that CRIU does not support, so we need to set our container config to respect those as well. You can do all of this using lxd's profiles mechanism, that is:

lxc config profile create migratable
lxc config profile edit migratable

And paste the following content in instead of what's there:

name: migratable
  raw.lxc: |
    lxc.console = none
    lxc.cgroup.devices.deny = c 5:1 rwm
    lxc.start.auto =
    lxc.start.auto = proc:mixed sys:mixed
  security.privileged: "true"
    nictype: bridged
    parent: lxcbr0
    type: nic

Finally, launch your contianer:

lxc launch ubuntu migratee -p migratable

Finally, add both of your LXDs as non unix-socket remotes (required for now, but not forever):

lxc remote add lxd thishost:8443   # don't use localhost here
lxc remote add lxd2 otherhost:8443 # use a publicly addressable name

Profiles used by a particular container need to be present on both the source of the migration and the sink, so we should copy the profile to the sink as well:

lxc config profile copy migratable lxd2:

And now, you're ready for the magic!

lxc start migratee
lxc move lxd:migratee lxd2:migratee

With luck, you'll have migrated the container to lxd2. Of course, things don't always go right the first time. The full log file for the migration attempts should be available in /var/log/lxd/migratee/migration_{dump|restore}_<timestamp>.log, on the respective host where the dump or restore took place. If you aren't successful in migrating things (or parsing the dump/restore log), feel free to mail lxc-users, and I can help you debug what went wrong.

Happy hacking!