Getting started with LXD Containerization

LXD is a next generation container manager that provides additional features that are similar to virtual machines, such as snapshots, storage pools, and more. Using Linux containers (LXC) as the container type, LXD gives you the best of two worlds. In this video, I’ll go over the basics of LXD. You’ll learn how to set it up and launch containers. For this particular video, we’ll focus on LXC commands – but a follow-up that dives more into LXD’s more advanced features is a possibility if there’s enough interest.

All of the commands I’m going to be using will be run against a server running Ubuntu Server 20.04. but, you don’t have to be running Ubuntu. If you’re not a fan of Ubuntu, then Debian is also a good choice. Other distributions are supported as well. Basically, any distribution of Linux with access to the snapd package should work just fine.

The first thing I recommend you do, is to create a user for yourself if you don’t already have one. If you are running Ubuntu and installed it manually, then you would’ve already created a user during installation and you won’t need to do this. Some providers of Ubuntu Server, especially VPS providers, will often give you access to the root account and leave it up to you to create a user. So, if you’re logging into the server as root, consider creating a user for yourself.

To do that, run the following command:

adduser myusername

We should add the user to the sudo group as well:

usermod -aG sudo myusername

We can switch to the newly created user with the following command:

su - myusername

Next, I always recommend starting out with a fully updated server. So make sure you’ve installed all available updates. On Ubuntu, Debian, and related distros, the following commands will do the trick:

sudo apt update && sudo apt dist-upgrade

If there were updates on your end, you should reboot your server to make sure that everything is fresh:

sudo reboot

Let’s get LXD installed and running. First, we need to make sure that we have support for snap packages:

which snap

If you get no response from this command, then that means your server doesn’t have support for snap packages. At least not yet.

Snap packages are a type of universal package, which is a package type that is not specific to any one distribution of Linux. A developer can publish their application as a snap package, and any distribution that supports snap packages will be able to install it. And quite a few distributions are supported.

Ubuntu Server often gives you this by default, but depending on where your Ubuntu server installation came from, you may need to set it up.

On Ubuntu, distributions based on Ubuntu, as well as Debian, we can run the following command to set up snap packages:

sudo apt install snapd

For other distributions, you can browse to the following URL to set up snapd:

https://snapcraft.io/docs/installing-snapd

If you already had snapd installed, next check to see if LXD is already present on the system:

snap list

The snap list command gives you a list of all the snap packages that you have installed. If you have a bunch, you can narrow down the list:

snap list | grep lxd

If you’ve only now set up snapd, you won’t have any snaps installed. Either way, you can install LXD with the following command:

snap install lxd

Although it’s optional, adding yourself to the lxd group will allow you to manage LXD without needing to use sudo:

sudo usermod -aG lxd

Now that we have LXD installed, we need to initialize it to get it going:

sudo lxd init

The first prompt will ask us if we’d like to enable clustering. I’m going to say no here, that’s beyond the scope of the tutorial. Just keep in mind that clustering is a possibility, and is highly recommended if you are running LXD in production.

Next, it’s asking us if we would like to set up a new storage pool. This is one of my favorite features of LXD, the storage options are awesome. We’ll definitely want to create a new pool.

The third question will ask us for the name of the pool. I’ll just leave it as “default” here.

Now it’s asking us for the type of storage we want to use. ZFS is default, and it’s a really great choice. But you’ll want a dedicated disk for this, and not everyone will have a second disk on their system. ZFS is recommended if you can though. I’m going to choose dir here, but make a note of the other options here in case you want to try something else later.

It’s asking us if we would like to connect to a MAAS server. This is beyond the scope of today’s video, but it is something I am thinking about covering in a separate tutorial. If you’d like me to do a video on MAAS, click the like button and drop a note in the comments. If enough people ask, I’ll definitely consider it.

Now it’s asking us if we would like to create a new bridge. I’m going to keep the default of yes for this.
And I’m also going to leave the default name of lxdbr0. I’ll keep the default of auto here as well. LXD gives you full flexibility as far as how you set up networking, so as you get more advanced with it, you may want to consider setting up a dedicated network at some point.

For ipv6, I’m going to leave that as the default as well.

Next, it’s asking us whether or not we’d like the LXD server to be available from the outside. I’m going to leave this as no, you should never make something externally available until it’s fully vetted and you’re going to start using the service in production. And this mindset isn’t specific to LXD, I don’t care what it is. Keep it private until you run into a use-case that requires otherwise.

I’m going to accept the defaults for the rest.

Now, lets check out some basic commands we can use.

lxc list will give us a list of the containers we have on our system as well as their status, but right now we haven’t created any yet.

To create a container, we’ll need to find an image we want to base our container on. Images come from ‘remotes’, and the following command will give us a list of remote repositories we have available to us:

lxc remote list

For listing images that are available on a remote, we can use the following command for that:

lxc image list images:

Note the colon at the end.

You can add a search term at the end if you want to search for an image based on a specific distribution:

lxc image list images: debian

You can also add additional search terms to narrow down the list, so if I wanted to list Ubuntu images that are from 20.04, I can add its release code-name here:

lxc image list images: ubuntu focal

To launch a container, the following command will do the trick:

lxc launch images:ubuntu/focal ubuntu

I’m going to create a Debian instance also:

lxc launch images:debian/10 debian

Now that we’ve created a container, the image for that container will be available on our server for faster access. You can see a list of images that are available locally with the following command:

lxc image list

Now that we have a container, we can run a command against it:

lxc exec mycontainer -- apt install apache2

When you run a command against your container, it will run the command, and then exit.

Notice the double hyphen – that separates lxc commands from commands that are intended to be run from the container.

We now have Apache installed on the container. We can actually curl its IP address and we should see the output of Apache’s default page:

lxc list

curl <ip address>

As you can see, we can see the code from Apache’s start page. If the container was allowed to be externally available, we would be able to view that start page from outside the server.

Now that we have a container running, we should take a look at commands we can use to start, stop, and restart it.

First, grab a list of the current containers:

lxc list

To stop a container:

lxc stop

Now the state of that container will show “stopped”:

lxc list

To start it back up:

lxc start

We can also restart a container as well:

lxc restart

One of the biggest differences between Docker containers and LXD is that the containers are stateful. This means that since we restarted our container after installing apache, we still have apache on that container. LXC containers, which is the underlying technology with LXD, are almost like virtual machines in nature. They are containers, so they are light weight, but contents on their filesystem are going to be more Linux-like than container-like.


Next, let’s look at deleting containers. That’s simple actually. First, we’ll stop the container:

lxc stop

lxc delete

Couldn’t be any simpler than that.

One of my favorite things to do is to create snapshots of containers, so I can test configuration changes and roll them back if for some reason things don’t go as planned. This is another aspect of LXD containers that are similar to virtual machines in behavior.

To take a snapshot, we can use the lxc snapshot command:

lxc snapshot

That’s done. Now let’s check the container list again:

lxc list

Notice that the snapshot count is now 1.

The lxc info command will show us the snapshots that exist for a container:

lxc info <container name>

We get quite a bit of useful information here, not just a list of snapshots. At the bottom, we can see snapshots by name. Note that this section will not be shown if there are no snapshots.

Let’s take a look at setting resource limits. You definitely don’t want to allow a container to saturate your servers RAM if something spirals out of control.

lxc config set <container name> limits.memory 1GB

We can see the current configuration for a container with the following command:

lxc config show <container name>

You can set the limit to whatever you want it to be.

Another thing you might want to consider doing, is setting up the container to automatically start when the server boots up.

lxc config set boot.autostart 1

Now in the info printout, a new line will appear showing that autostart is enabled:

lxc config show <container name>

Something to consider is that you may not want a container to start right away. For example, maybe you have a container that acts as a database server, and that one needs to be online first. You can add a delay to the container to make sure it doesn’t immediately start:

lxc config set boot.autostart.delay 30

Or, you can set a startup order if you want to be very specific:


lxc config set boot.autostart.order 8