The more I use LXD the less I understand why we're all using Docker. Why oh why?

Exposing lxd container ports on host

You can either used bridged networking or use default NAT networking and add a route to your firewall:


iptables \
  -t nat \
  -i eth0 \
  -p TCP \
  -d $PUBLIC_IP \
  --dport $PORT \
  -j DNAT \
  --to-destination $CONTAINER_IP:$PORT \
  -m comment \
  --comment "forward to the container"'

Export and import a container

The command line interface is so easy to use, you hardly need to look a the documentation.

$ lxc export mycontainer mycontainer.tar.gz

This will include all snapshots. To optimise the backup file, you might want to look into adding --instance-only and --optimized-storage.

This tarball can then be used on the same host or copied to a different machine where you want the same container. To make use of the tarball that you exported, you'll of course use a command called import:

$ lxc import mycontainer.tar.gz
$ lxc start mycontainer

And it just works! mycontainer is now up and running.

Mount your home directory read/write inside an LXD container

To mount your home directory read/write inside an LXD container, do:

$ lxc config device add buster myhome disk source=$HOME path=$HOME
$ lxc config set buster raw.idmap "both 1000 0"
$ lxc restart buster

Files written by the root user (which has user id=0) inside the container are owned by my own torstein user on the host system (which has user id=1000).

The crux here is the user id mapping. To give another example: If my host user had user id 1200 and the user I wanted to map to inside the container had id 3000, I would instead configure:

$ lxc config set buster raw.idmap "both 1200 3000"

AFAIK, there's no Docker equivalent, see issue 2259 in their bugtracker. With docker you need to hack around it by chowning the files after mounting them to make the user inside the container write to them (if it's not a root user) and on the host system, you must chown files created by the container to allow non-root users to write to them.

Run Docker containers inside an LXD container

You can even run Docker containers inside an LXD container By passing security.nesting=true to lxc when creating a container, you can run other containers inside it:

$ lxc launch ubuntu box-in-a-box -c security.nesting=true

You can now lxc exec into the box-in-a-box and install Docker like normal, after which lxc ls will list the Docker interfaces along side the eth0 device which is used for communicating with your lxd container:

❯ lxc ls box-in-a-box
|      NAME    |  STATE  |             IPV4             |                     IPV6                     |   TYPE    | SNAPSHOTS |
| box-in-a-box | RUNNING | (br-b0334a281f15) | fd42:3cb:5f02:b33b:216:3eff:fee5:2320 (eth0) | CONTAINER | 0         |
|              |         | (docker0)         |                                              |           |           |
|              |         | (eth0)          |                                              |           |           |

Note that these 172.x IPs are not accessible from your host machine, so you need to proxy these from something that listens on eth0 in the box-in-a-box container. I prefer running nginx there to proxy requests to the Docker container IPs so that I can easily access them from my machine.

Grow the LXD storage

On my system, I'd just hit ENTER when installing lxd and had thus a BTRFS backed storage pool:

$ lxc storage ls
|  NAME   | DESCRIPTION | DRIVER |                   SOURCE                   | USED BY |
| default |             | btrfs  | /var/snap/lxd/common/lxd/disks/default.img | 18      |

To add 20 GBs to it, I did the following:

First off, to be safe than sorry, I stopped LXD:

# snap stop lxd

After that, I grew the file itself:

# sudo truncate -s +20G /var/snap/lxd/common/lxd/disks/default.img

Then get a hold of which loopback device it's using:

# losetup | grep default.img
/dev/loop6         0      0         1  0 /var/snap/lxd/common/lxd/disks/default.img   0     512

Re-create it:

# losetup -c /dev/loop6

Then finally, mount the device and use btrfs to resize it:

# mkdir /mnt/foo
# mount /dev/loop6 /mnt/foo
# btrfs filesystem resize max /mnt/foo
# umount /mnt/foo

Once that was done, I started LXD again:

# snap start lxd

My containers could now use 20GBs more.

Licensed under CC BY Creative Commons License ~ ✉ torstein.k.johansen @ gmail ~ 🐘 @skybert@emacs.ch ~ 🐦 @torsteinkrause