How does snap work in a Ubuntu 20.04 container?

I created an ubuntu:20.04 container on an Ubuntu 18.04 host with snap LXD 4.0.1.
I then start a shell in the new container and run: “snap list”. I see the following:

Name    Version   Rev    Tracking         Publisher   Notes
core18  20200311  1705   latest/stable    canonical✓  base
lxd     4.0.1     14890  latest/stable/…  canonical✓  -
snapd   2.44.3    7264   latest/stable    canonical✓  snapd

Why and how did these get installed? Were they included in the image, or downloaded by snapd? I was hoping that they are somehow shared from the host and not downloaded from scratch, but the snap versions are different from the host. The host has:

> Name    Version    Rev    Tracking       Publisher   Notes
> core    16-2.44.3  9066   latest/stable  canonical✓  core
> core18  20200427   1754   latest/stable  canonical✓  base
> lxd     4.0.1      14890  latest/stable  canonical✓  -

The lxd snap is the same version on both the host and the container. core18 has an older version in the container than the host has. core is present only in the host. And snapd is present only in the container.

Since snaps are mostly read-only filesystems, couldn’t they be shared between the host and containers, or between containers?

snapd is included in the official ubuntu images by default. LXD is installed if you invoke it via lxc command.

Example:

lxc launch ubuntu:20.04 c1
lxc exec c1 -- snap list
No snaps are installed yet. Try 'snap install hello-world'.

lxc exec c1 -- lxc ls
<pause>
If this is your first time running LXD on this machine, you should also run: lxd init
To start your first instance, try: lxc launch ubuntu:18.04

+------+-------+------+------+------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+------+-------+------+------+------+-----------+

lxc exec c1 -- snap list
Name    Version   Rev    Tracking         Publisher   Notes
core18  20200311  1705   latest/stable    canonical✓  base
lxd     4.0.1     14890  latest/stable/…  canonical✓  -
snapd   2.44.3    7264   latest/stable    canonical✓  snapd

They can be different from the host package versions as they are not linked.

However you can use the LXD built images which do not include snapd and lxd by default if you prefer:

lxc launch images:ubuntu/focal c1
lxc exec c1 -- snap list
-bash: snap: command not found
lxc exec c1 -- lxc ls
-bash: lxc: command not found

snaps are installed in the ubuntu:20.04 container without me doing anything other than “snap list”:

lxc launch ubuntu:20.04 u1
lxc exec u1 bash
snap list
snap list
snap list

First I see:

No snaps are installed yet. Try 'snap install hello-world'.

Then I see the snaps getting installed one by one, in this order: snapd, core18, lxd.

I also tried ubuntu:20.04 container on an ubuntu:20.04 host, with the same result: The lxd snap is installed automatically in the container.

When you launch a container from, for example, ubuntu:20.04,

  1. you get the generic container container image for Ubuntu 20.04
  2. you get the additional usability features such as the ubuntu non-root account created.
  3. you get the snapd service start running, that will eventually finishing setting up by retrieving the core18, lxd and snapd snaps.

When you have just launched an ubuntu:20.04 container and you try to get a shell very quickly, you may get an error that there is no ubuntu account (yet!).

$ lxc launch ubuntu:20.04 mycontainer
Creating mycontainer
Starting mycontainer
$ lxc ubuntu mycontainer
groups: cannot find name for group ID 1000
I have no name!@mycontainer1:/$ 

In such a case, you are faster than the fast LXD container creation. Just wait one more second and try again. Or, you can programmatically check when the container finished the setup.

However, snapd is a service. The container (well, cloud-init) reports that it finished the setup, but the snapd service just started and is about to download

  1. core18, 57MB
  2. snapd, 28MB
  3. lxd, 72MB

It should take a few tens of seconds for these downloads.

You can launch a container, then wait for a minute, and when you snap list in the container, you can see that snapd has been configured properly.

These snaps don’t seem to take that much space in the container:
lxc info shows just:

Disk usage:
root: 36.62MB

I’m curious why the snap disk usage is so much smaller than their download size.

In any case, why is LXD installed by default in the container? It is not installed by default on a brand new Ubuntu 20.04 Hetzner VPS, and it is not installed by default on an Ubuntu 20.04 desktop.

In ubuntu 18.04 containers, one of the first things I did after creating an ubuntu container was to remove lxd:

apt-get -y remove lxd lxd-client

You would compare with Ubuntu Server. Hetzner makes changes to the images.

The LXD service was not active unless you were to wake it up through the client (activated by socket).

Trying to summarize the answers here.

The official Ubuntu images (ubuntu:20.04) have an identical package list everywhere they are used. That mostly means the major (and some smaller) public clouds as well as LXD.

Some hosting providers instead rely on unofficial, custom images which may then have a differing package selection.

The official Ubuntu 20.04 cloud image includes the lxd snap. That’s of more use in the cloud that it is for most LXD users, but again, we want things to be consistent so cloud-init data used against the cloud can work with LXD and vice/versa without having to think about potential package list differences.

When you lxc start or lxc launch, LXD considers the container started as soon as its init process is running. That doesn’t however mean the container is done booting.
It’s during boot the snapd discovers the pre-installed snaps, explaining why it can take a few seconds for them to show up. Same is true of cloud-init creating user accounts (as mentioned by @simos) or networking coming up in the container.

If you want an unofficial (built by the LXD team) image which does not include LXD and is generally a bit slimmer than the official cloud image, you may want to consider:

  • images:ubuntu/20.04 (no cloud-init installed)
  • images:ubuntu/20.04/cloud (with cloud-init installed)
1 Like

My specific questions are answered, but I still want to discuss the synergy of snaps with containers, or the lack of it.

Couldn’t containers in the same host somehow share the same snap “images” so each snap version is downloaded only once per host and share the same disk space in all containers that use it? That would be very nice.

Yes, but snapd is active and it keeps upgrading snaps that I don’t need. In an LXD host with lots of these containers, each container would keep downloading versions of snaps. I have been trying to avoid upgrading containers once I deploy them, by separating my data from the guest OS, through attached devices. When the OS needs upgrading, I would build a new one and use it to replace container that needs it. Snapd prevents me from doing this, as it upgrades itself independently of the OS. I know I can delay this upgrade for about two months, or perhaps indefinitely, but still, I need to do more work to make this happen.

But let’s say I start using snaps in containers and let them upgrade themselves. If a snap is shared among all containers that use it in the same host, that would go a long way towards my goal of sharing the same software between containers (instead of replicating it) and instead of swapping guest OSes, I could simply organize all my software in snaps that would be swapped in containers.