containerd 1.5.0 was released today and now works on a new operating system: FreeBSD! This new release includes a series of patches (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) which allow containerd to build, enable the native and zfs snapshotters, and use a compatible runtime like runj.

I’m really excited about this! It’s awesome that only a small amount of work was needed to make containerd compatible with FreeBSD and that so much of it worked straight out of the box. And with a runtime for jails, containerd’s powerful APIs can now be used to manage FreeBSD’s native process isolation capability.

In the rest of the post, we can take a look at how to use containerd on FreeBSD!

Building containerd from source

containerd is not yet in ports, so the easiest way to get started is to check it out from the upstream git repository and build it. containerd is written in Go, so you’ll need a Go toolchain installed (which is available as a port or pkg). containerd works best with a recent version of Go (1.16.3 is currently available in pkg, and that works well). containerd’s Makefile is written for GNU make, but fortunately Go is easy to build without it.

$ git clone https://github.com/containerd/containerd
Cloning into 'containerd'...
[... output omitted ...]
$ cd containerd
$ git checkout v1.5.0
$ go build ./cmd/containerd
$ go build ./cmd/ctr
$ sudo install -o 0 -g 0 containerd ctr /usr/local/bin

Building runj

runj is in ports, but as I’m continuing to actively work on it you’ll find the most recent commits in my source repository. Like containerd, a Go toolchain is needed to build it.

$ git clone https://github.com/samuelkarp/runj
Cloning into 'runj'...
[... output omitted ...]
$ cd runj
$ make && sudo make install

Configuring containerd

containerd can run without explicit configuration, but the zfs snapshotter does require a bit of setup.

The zfs snapshotter

containerd uses snapshotters to provide the layered filesystems that enable containers to have efficient, copy-on-write storage and fast startup. The zfs snapshotter leverages ZFS to provide these capabilities and works well on FreeBSD.

In order to use the snapshotter, a ZFS filesytsem must be mounted somewhere the snapshotter can find it. The default mountpoint is /var/lib/containerd/io.containerd.snapshotter.v1.zfs (assuming the containerd root is /var/lib/containerd). You can create a filesystem like this:

$ zfs create -o mountpoint=/var/lib/containerd/io.containerd.snapshotter.v1.zfs your-zpool/containerd

If you want to configure a different mountpoint, you can add the following to /etc/containerd/config.toml:

1
2
3
4
version = 2
[plugins]
[plugins."io.containerd.snapshotter.v1.zfs"]
root_path = "/your/preferred/mountpoint"

Running containerd

containerd is a daemon that runs as root. An easy way to get containerd running for testing is to run it in the background or another shell session (and you can easily watch the logs that way too)

$ sudo containerd

Running your first container (jail) with containerd

Once you have containerd up and running, you can use the ctr command-line client to interact with the daemon and run some containers (jails)! First, you’ll need to get an image pulled.

Pulling an image

containerd can pull images from any OCI or Docker-compatible container registry. I’ve published a container image of FreeBSD 12.1-RELEASE on the Amazon ECR gallery. You can pull it with ctr as follows:

$ sudo ctr image pull --snapshotter zfs public.ecr.aws/samuelkarp/freebsd:12.1-RELEASE

Running the container

Running a container with containerd requires an image, a snapshotter, and a container runtime. The runj source repository includes a runtime for containerd called wtf.sbk.runj.v1 which was installed with sudo make install above. Using the image pulled above, the zfs snapshotter, and the runj runtime, you can run a container like this:

$ sudo ctr run \
    --snapshotter zfs \
    --runtime wtf.sbk.runj.v1 \
    --rm \
    public.ecr.aws/samuelkarp/freebsd:12.1-RELEASE \
    my-container-id \
    sh -c 'echo "Hello from the container!"'

A work in progress

containerd on FreeBSD and the runj runtime are both very much experimental and a work in progress. While the functionality demonstrated in this blog post works, there are still lots of missing features. You can find continuing development work in both the containerd repository and the runj repository. I’ll also continue to post here on this blog as more exciting developments occur.

I hope you’re as excited as I am about the future of containerd and the OCI ecosystem on FreeBSD!