Unpacking Docker images with Undocker

In some ways, the most exciting thing about Docker isn’t the ability
to start containers. That’s been around for a long time in various
forms, such as LXC or OpenVZ. What Docker brought to the
party was a convenient method of building and distributing the
filesystems necessary for running containers. Suddenly, it was easy
to build a containerized service and to share it with other people.

I was taking a closer at the systemd-nspawn command, which it
seems has been developing it’s own set of container-related
superpowers recently, including a number of options for setting up the
network environment of a container. Like Docker, systemd-nspawn
needs a filesystem on which to operate, but unlike Docker, there is
no convenient distribution mechanism and no ecosystem of existing
images. In fact, the official documentation seems to assume that
you’ll be building your own from scratch. Ain’t nobody got time for
that…

…but with that attracting Docker image ecosystem sitting right next
door, surely there was something we can do?

The format of a Docker image

A Docker image is a tar archive that contains a top level
repositories files, and then a number of layers stored as
directories containing a json file with some metadata about the
layer and a tar file named layer.tar with the layer content. For
example, if you docker save busybox, you get:

In order to re-create the filesystem that would result from starting a
Docker container with this image, you need to unpack the layer.tar
files from the bottom up. You can find the topmost layer in the
repositories file, which looks like this:

From there, you can investigate the json file for each layer looking
for the parent tag.

Introducing undocker

I wrote the undocker command to extract all or part of the layers
of a Docker image onto the local filesystem. In other words, if you
want to use the busybox Docker image, you can fetch and unpack the
image:

# docker pull busybox
# docker save busybox | undocker -o busybox

This will first look in the repositories file for the busybox
entry with the latest tag, then build the necessary chain of layers
and unpack them in the correct order.

Once you have the filesystem extracted, you can boot it with
systemd-nspawn:

I’m using the -i (--ignore-errors) option here because this layer
contains a device node (/dev/console), and I am running this as an
unprivileged user. Without the -i option, we would see:

OSError: [Errno 1] Operation not permitted

A Docker image archive can actually contain multiple images, each with
multiple tags. For a single image, undocker will default to
extracting the latest tag. If the latest tag doesn’t exist,
you’ll see: