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
@jay, this one was AWESOME! I’ve been a Linux desktop user for a while on my home and spare machines, but have done very little on the server side. Containers, Docker, and Podman are still a tech that I’m struggling to wrap my head around. I loved your Docker series, that was excellent. I think that LXD clicks better with my brain. Also when I realized from this video how easy it was to add snaps to Debian, I decided to upgrade my Debian 10 box to Debian 11 and add snapd to experiment with LXD. I would be in favor of more LXD content. I doubt that I would get into clustering with LXD because I have mostly old boxes that I use in my homelab that people have gotten rid of because they are too slow for Windows, but I’m interested to see how I can use containers on these older boxes to do homelab things. Thanks Jay for making this one.
Welcome to the forum!
I agree with you on LXD being underrated and LXC being a (Linux) VM alternative (somewhat). But docker / k8s is not really an app store. Sure, you can get whatever stuff you want from the docker hub, but that’s not the point. You can create your own containers from a base image and only add whatever you need.
Docker focuses more on the programs themselves, LXD focuses on the system as a whole. LXD is an orchestrator to more easily manage LXC. LXC aims to be somewhat like what VMs are today, but lighter and more efficient. LXD aims to be something like a more integrated solution for managing LXC, kind of like OpenStack is, but with way less things that it does (and LXD is available for OpenStack). With LXC, you won’t get the benefit of running your own kernel, but you may also have other advantages that come with LXD because of that. So if you program doesn’t have a specific need for a kernel or kernel module, LXC should work great. Easiest things to set up in LXC are web servers and databases
Managing LXD is just like managing any other VM infrastructure. You automate stuff to update your systems, or in many cases, that automation is already in place, just use whatever OS you need for the container. Backing up data from LXC is also easier IMO.
On Docker, you still get an OS base image, but managing it is a completely different beast. All containers are supposed to be ephemeral. You use docker-compose or whatever other tools to create a container, spin it up and have it run whatever you want. If you want persistent storage, you either point the containers to a network share or a DB or something similar, outside of them, or you create a persistent volume for the OCI container and you point other ephemeral ones to those.
OCI containers are supposed to be administered via whatever orchestrator you have (k8s, k3s, microk8s, k0s, docker, docker swarm, podman etc.). The programs inside never get updated, you just create a new container with an updated program and delete the old one. This does technically give admins a lot of flexibility, but it makes for a more complicated setup process, unlike just spinning up a new OS.
In addition, whatever you put on an OCI container will run and behave the same anywhere. Technically you can just tar a LXC file system and send it to people, but it’s a bit clunkier than how OCI containers do versioning. But those technologies don’t really compete with each other. And you can even run OCI containers inside LXC.
With that said, I find myself using LXD and not using OCI containers unless strictly necessary.