LXD profiles and networking


LXD is a pretty powerful tool, but it is not always immediately obvious how to accomplish certain things such mixing static and dynamic IP address allocation. Many search results on this topic are regarding post-configuration of the container (via e.g. netplan) which is not exactly what we want: ideally, this configuration is managed on the LXD side.

Some background: LXC and LXD are a great platform for running Linux-based applications in a “realistic” environment. For example, at Hatching we test our virtual machine creation and management product using LXD. This enables us to test our product in an environment that is comparable to what a customer would run, so using this approach we hopefully catch deployment errors as well as software bugs.

In our case, our deployment environment is based on Ubuntu 18.04, with a number of services managed by systemd. Running virtual machines also requires access to KVM (hardware acceleration) and some Linux network internals (bridges, tap interfaces, ip route, iptables). We don’t really want to use nested virtualization, so testing all of this in a virtual machine is not an option.

To accomplish this, I’ve created a profile that describes the requirements of our environment:

name: vm-testing
description: VM testing container
config: {}
  # Bridged network with NAT
    name: eth0
    nictype: bridged
    parent: lxdbr0
    type: nic

    path: /
    pool: default
    type: disk

  # Example: share some resources from the host with the guest
  # (e.g. big ISOs)
    source: /data/resources
    path: /usr/share/project/resources
    type: disk

  # Acceleration for QEMU
    path: /dev/kvm
    type: unix-char

  # QEMU uses tap devices for networking
    path: /dev/net/tun
    type: unix-char

To create a container, you run:

lxc launch --profile vm-testing images:ubuntu/bionic/amd64 \

This assigns a dynamic IP address from the lxdbr0 pool, which is ideal for short-lived containers. We don’t have to manage IP address allocation ourselves, as it is managed by LXD and dnsmasq.

But what if you want to assign a static IP address to a container managed by LXD? For example, we also have containers that run the latest development version of our product, (permanently) reachable over the network. While the LXD documentation is not very clear on how to accomplish this, this is actually quite easy:

lxc init --profile vm-testing images:ubuntu/bionic/amd64 \
lxc config device override mystatic1 eth0 ipv4.address=
lxc start mystatic1

You can either override specific configuration keys or even completely replace the eth0 device (by using lxc config device add with NIC with the same name) that would otherwise by specified by the profile. That’s it!