Running Rust on the Rumprun unikernel

The Rust programming language has been able to run on bare-metal without the standard library for quite some while now. However, most Rust applications depend on the std crate, and therefore still need a full operating system to run.

This is where the Rumprun unikernel platform comes into play. It allows you to build your POSIX applications into bootable single-purpose images. Because unikernels are tailored to run a single application, they come without the footprint of a full-featured operating system. This makes them a great tool for application virtualization. Supported platforms of Rumprun include not only Xen/EC2 and KVM, but you can also run your image on bare-metal hardware.

Rumprun is based on rump kernels, it reuses NetBSD’s libc and drivers as components to provide a POSIX-y interface – the interface which the Rust standard library is built upon.

For the last couple of days we have been working on Rumprun support for Rust – you can now deploy your Rust application as a Rumprun unikernel. With our toolchain set up, a single cargo command is all you need to turn your Rust application into a Rumprun unikernel image.

Here is a screenshot of an example TCP/IP server written in Rust and built with cargo, running in a Rumprun unikernel on QEMU.

An example Rust TCP/IP server on Rumprun

Note that running Rust on bare-metal without a standard library is different from running Rust on bare-metal Rumprun: Rust’s #![no_std] feature means you write your own drivers and environment. Rust on Rumprun on the other hand already provides you with production-quality NetBSD drivers and a standard library. You can choose which subsystems and drivers you want to compile into your image.

A significant portion of the work was spent on making std work correctly on NetBSD. As a side effect of this project, you can now also compile your Rust binaries for NetBSD/amd64.

Getting started

The remaining part of this blog post briefly guides you through the necessary steps to build your Rust application into a Rumprun unikernel image. This is what you have to do:

  • Build the Rumprun unikernel platform, it provides the tools and libraries to build Rumprun unikernels.
  • Set up a Rust cross-compiler and standard library for Rumprun. This allows you to compile binaries that you can later “bake” into a Rumprun unikernel.
  • Compile your Rust application using the Rust cross-compiler.
  • Bake the generated Rust binary into a Rumprun unikernel image, which you can then run on a hypervisor or bare-metal machine of your choice.

Building Rumprun

First, we need to build Rumprun. The repository provides its own cross-compile tools that are needed in the following steps. Check out the excellent Tutorial - Building Rumprun Unikernels for instructions. I recommend following the whole tutorial, but if you are in a hurry, the section “Building the Rumprun Platform” is all you need to continue to the next step.

Building a Rust cross-compiler

The Rust source tree already contains all patches needed to build for Rumprun, but you will have to enable the Rumprun target. We provide the scripts for building a Rust cross-compiler and the std crate automatically in the rumprun-packages repository. Just follow the instructions on how to build the Rust package.

Compiling and baking your Rust application

If everything is working properly, building your Rust application as a unikernel image is as easy as running cargo rumpbake. Be aware though that at the time of writing, some crates on crates.io don’t have proper NetBSD support yet, and might fail to compile or execute.

Congratulations! You are now set up to build your own Rust applications into Rumprun unikernel images.

Acknowledgments

This project is all about taking existing pieces of software and putting them together. Without the awesome previous work of the Rust and the rump kernel hackers, this could not exist. A special thank you goes to @anttikantee for his support along the way.