Today, I open-sourced runj, a new experimental, proof-of-concept OCI-compatible runtime for FreeBSD jails. For the past 6.5 years I’ve been working on Linux containers, but never really had much experience with FreeBSD jails. runj (pronounced “run jay”) is a vehicle for me to learn more about FreeBSD in general and jails in particular. With my position on the Technical Oversight Board of the Open Containers Initiative, I’m also interested in understanding how the OCI runtime specification can be adapted to other operating systems like FreeBSD.

An OCI runtime sits at the lowest-level of “make a container work”. The specification is focused around starting processes in isolated environments, but doesn’t cover all the kinds of features you expect in a product like Docker. In particular, OCI runtimes operate in terms of “bundles” rather than images, don’t implement the copy-on-write mechanisms you need for layers, and omit higher-level constructs like networking and storage. In short, OCI runtimes are a low-level tool that usually hides from view behind the container runtime you see like Docker or containerd. The reference OCI runtime implementation is runc, and runj is modeled pretty closely after it.

containerd is a tool that’s one step up in abstraction from the OCI runtime. Its job is to manage container execution, copy-on-write layers, and images. containerd interacts with the underlying OCI runtime with a shim, and currently only has a built-in shim targeting runc. The runj repository also contains a containerd-shim that can be used with runj.

Both runj and the containerd-shim are from-scratch implementations rather than porting runc and containerd’s existing runc shim to FreeBSD. This is because both runc and the runc shim make fairly deep assumptions that they’re running on Linux, and use Linux-specific kernel interfaces like cgroups and namespaces that don’t exist on FreeBSD. Writing from scratch also gives me the opportunity to learn more, and I think it’s more fun. This is my project, after all!

I wasn’t really expecting to write this post today. I recently reached the point in development where runj and the containerd-shim I wrote are functional-enough that the standard I/O streams and exit codes are hooked up, which seemed like it was enough to make public. I only told a few friends about runj, but then one of them decided to post about it on Twitter:

Then, later, it appeared on Hacker News. This was all unexpected, so now I’m writing this post earlier than I had intended.

As I wrote in the file, I’m still using runj as a mechanism to teach myself and I’m not yet ready to accept code contributions. However, I’d love to hear if you get the chance to try it out!

I’ll continue to post more about runj as I continue to develop it. You can also see this previous post about FIFOs that I wrote while building runj. The two things I’m looking to do next are: