Linux containers, or LXC, is a lightweigt yet powerful container solution. It can run applications or distros but (unlike virtual machines) share the same kernel and hardware resources and (unlike Docker) persistently.

This is not a cutting-edge technology and is fully supported in Fedora. However, the official Wiki page describes only a hard way to create and run LXC containers. It is time for a missing (but not the only) guide.

Install LXC and Supporting Tools

LXC and, additionally, related template files needs to be installed to enable easy usage of LXC.

$ sudo dnf install lxc lxcfs lxc-templates

Now we can get familiar with all LXC executables or commands:

$ ls /usr/bin/lxc*
lxc-attach          lxc-config          lxc-device          lxc-ls              lxc-top             lxc-wait          
lxc-autostart       lxc-console         lxc-execute         lxc-monitor         lxc-unfreeze                          
lxc-cgroup          lxc-copy            lxc-freeze          lxc-snapshot        lxc-unshare                           
lxc-checkconfig     lxc-create          lxcfs               lxc-start           lxc-update-config                     
lxc-checkpoint      lxc-destroy         lxc-info            lxc-stop            lxc-usernsexec 
All LXC executables

The templates package will add useful scripts in the LXC templates directory:

$ ls /usr/share/lxc/templates
lxc-busybox  lxc-download  lxc-local  lxc-oci

Currently (until Mar 2021), LXD is not packaged in Fedora.

Configure Linux Containers

Define UID Mappings

LXC is shipped with some default vaules. Unfortunately some of them is not correct and block the creating process of unprivileged containers:

lxc-create: example_container: parse.c: lxc_file_for_each_line_mmap: 80 No such file or directory - Failed to open file "/home/asaba/.config/lxc/default.conf"
lxc-create: example_container: conf.c: userns_exec_mapped_root: 4489 No uid mapping for container root
....
lxc-create: example_container: lxccontainer.c: do_lxcapi_create: 1871 Failed to create (none) storage for example_container
lxc-create: example_container: tools/lxc_create.c: main: 319 Failed to create container example_container

This could be fixed by creating ~/.config/lxc/default.conf with the recommended content:

lxc.include = /etc/lxc/default.conf
lxc.idmap = u 0 100000 65536
lxc.idmap = g 0 100000 65536
~/.config/lxc/default.conf

Configure LXC Network

We can re-use virbr0 created by libvirtd to simplify the configuration process:

$ BRIF=virbr0
$ echo "`whoami` veth ${BRIF} 10" > /etc/lxc/lxc-usernet

Create Containers

LXC container images could be either pulled (downloaded and imported) or built. Either method requires some scripting to generate images. Lucky we can use templates, and we also have a tool script from lxc-templates package to pull images from linuxcontainers.org or other download server.

List Available Images

First we can have a look at what images are available:

$ /usr/share/lxc/templates/lxc-download --list
Setting up the GPG keyring
Downloading the image index

---
DIST    RELEASE ARCH    VARIANT BUILD
---
....

Create Privileged Containers

Containers could be created as privileged where the container uid 0 is mapped to the host's uid 0.

$ CONTAINER_NAME=guilin
$ sudo lxc-create -n ${CONTAINER_NAME} -t /usr/share/lxc/templates/lxc-download -- --dist debian --release stretch --arch amd64
Setting up the GPG keyring
Downloading the image index
Downloading the rootfs
Downloading the metadata
The image cache is now ready
Unpacking the rootfs

---
You just created a Debian stretch amd64 (20210309_05:24) container.

To enable SSH, run: apt install openssh-server
No default root or user password are set by LXC.

Create Unprivileged Containers

Containers could also be unprivileged.

$ CONTAINER_NAME=guilin
$ lxc-create -n ${CONTAINER_NAME} -t /usr/share/lxc/templates/lxc-download -- --dist debian --release stretch --arch amd64

Grant execute permission on container root and related directories to the world:

$ chmod +x ~ ~/.local ~/.local/share

To start and attach to the container:

$ systemd-run --unit=java --user --scope -p "Delegate=yes" lxc-start -n ${CONTAINER_NAME} -F
$ systemd-run --user --scope -p "Delegate=yes" lxc-attach ${CONTAINER_NAME}

Additional Parameters

You can add --server mirrors.tuna.tsinghua.edu.cn/lxc-images to download from mirrors or alternative download servers.

Manage and Delete Containers

Privileged containers are stored at /var/lib/lxc/${NAME} while unprivileged ones are stored at ~/.local/share/lxc. Tools like lxc-ls and lxc-info are oftenly used to manage them.

To delete a container, there is nothing like lxc-delete or lxc-remove, but lxc-destroy.

References