Creating LXC containers from docker and OCI images

Creating LXC containers from docker and OCI images

LXC is a set of tools that provides lightweight virtualization with a shared kernel. Linux Containers or LXC for short, provide easy tools for managing Linux kernel cgroups and namespaces in order to allow easy content management. They try to get as close to being a complete Linux installation without wasting resources on a separate kernel per container.  

As we already mentioned in a previous article on how Docker containers work, LXC runs on top of Linux namespaces and cgroups. Namespaces allow you to create virtual “hardware” and assign system resources inside the said namespace. This is how you can get a virtual network interface or any other device inside your LXC or Docker container. Cgroups on the other hand, provide CPU prioritization functionality and ensure resource limits you set are respected.

The previous paragraph might remind you of Docker, and indeed early versions of docker were built on top of LXC. But their approach is significantly different. Docker tries to provide single-app containers to be run in mostly microservice architecture (it can do more, but this is where it shines).  Whereas LXC provides virtual machines, that leverage the Linux kernels to stay as lightweight as possible. Not running a separate kernel has some security considerations, but for many use-cases, this is an adequate way to separate applications while sharing single host resources. 

In case you’d like to know more about Docker and similar cloud-based technologies take a look at the following articles:

LXC images and LXC containers

The standard way to handle LXC images is to use their community-supported image store. Here you can find their current images, as well as their sources. Downloading and running an official image is similar to docker pull syntax:

lxc launch ubuntu:14.04

In case you would like to create your own image from scratch you could use a tool like distrobuilder which is meant to create rootfs Linux filesystems as well as LXC and LXD images. For instance, to create an Ubuntu image you need this example ubuntu build spec and following command:

distrobuilder build-lxd ubuntu.yaml
LXC containers are meant to be similarly
LXC containers are meant to be similarly “contained” as docker containers
Photo by Julius Silver on Pexels.com

Create LXC image from LXC containers

Alternatively, you could start from a pre-existing image, create the container and log as root users using the attach command:

 lxc-attach -n <name>

Then install and configure all components that you need, save it as a snapshot, and create an image from the said snapshot.

1) Create a snapshot:

lxc snapshot alpine current

2) Publish snapshot as an image

lxc publish alpine/current --alias mycontainer

3) in case you want to move it around ether host the files on some webserver (and import via url), or save to file and copy around the place as follows

lxc image export <image name> . 

This will create 2 files, the metadata file containing configuration LXC needs to properly run the image and the rootfs which as name suggest contains the filesystem. You can create an runnable image from such files using:

lxc image import <metadata tarball> <rootfs tarball> --alias some-name

Create LXC containers using docker images

Like every container technology and their dog, LXC nowadays supports OCI images. The Open Container Initiative was created to manage open-sourced parts of Docker. They basically donated image specification, the low lever container runtime, and a few other key system components. OCI images are nowadays the defacto way of handling image Compatability between container runtime platforms.

As both Docker and LXC to some degree support OCI image format, you can create LXC containers using docker images (or using any other OCI image )!  To create an LXC container from a Docker do the following:

lxc-create <<name>> -t oci -- --url docker://alpine:latest

If you would like to do the opposite, or import a LXC container or image into docker, you can do the following:

tar -C ./rootfs -c . | docker import - project/image

Or if you prefer docker build, you can just use the following Dockerfile. Just assume that rootfs-folder is the extracted tar.gz.

FROM scratch
ADD rootfs-folder /
CMD ["/command"]

Alternatively, you can store it in the same folder as the docker file and do Add rootfs.tar.gz /, and docker will automagically do it for you.

Further reading

Back to top