Containers have revolutionized the way we package and deliver software. Instead of distributing large VM images, the application is assembled in a lightweight and portable container which has its own isolated runtime environment. This is possible thanks to some Linux kernel capabilities like cgroups (system resource accounting and limiting) and namespaces (file system, network, process, and hostname segregation), without incurring the virtualization overhead. Docker, Rkt, or LXC/LXD are some of the most popular container platforms, althought the first of them has the market dominance. In fact, FreeBSD Jails and Solaris Zones have never had the adoption Docker is having, despite Docker is quite younger compared to Solaris Zones which had been there since 2004.

The container engines recently got an opponent which goes step further by pulling the entire application into the minimalistic operating system kernel. It’s called unikernel. Once the app had been packaged, the result is an ultra thin image that can be deployed very fast on a vast majority of hypervisors! Let’s see how.

Language-specific unikernels

The proof we can’t take unikernels for granted is sky-rocketing growth of the language oriented unikernel projects. There are also used to be called as library operating systems. MirageOS provides OCaml programming language runtime facilities to build high-performance network unikernels that runs on Xen hypervisor, Runtime.js mimics the Node.js non-blocking I/O model to build unikernels that run JavaScript code and Rumprun allows running existing POSIX applications as unikernels.

But, what lies behind the motivation for unikernels? They claim to notably reduce the attack vector. As the majority of the OS services are pulled out from the kernel (no compiler tools, no shells, only essential drivers are kept, etc.), the zero day exploits or intrusions are less likely to compromise the system itself. The entire application process is operating in the privileged CPU mode, which means no I/O waits, no competing for resources and no context switches at all! Unikernels are made for immutability. Rather then patching the existing unikernel when a security issue is detected, the application sources are recompiled to a new unikernel and the old one is disposed.

I found OSv the perfect fit to illustrate how to package any C, Node.js or Java application into unikernel. It provides the capstan CLI tool to pull, build and run unikernel images. Issue the following commands to get the binary.

$ CAPSTAN_URL=https://raw.githubusercontent.com/cloudius-systems/capstan/master/scripts/download
$ curl $CAPSTAN_URL | bash
$ $HOME/bin/capstan

We are going to build the Spring Boot microservice unikernel. Clone the github repository which contains Capstanfile configuration to build the jar artifact and assemble it into unikernel image.

$ git clone https://github.com/bhnedo/cloud-rabbit-todo/tree/master/todo-microservice.git
$ cd todo-microservice
$ $HOME/bin/capstan build

You can test the unikernel locally by running capstan run or use the generated QEMU image to boot it straight under KVM hypervisor.

$ virt-install -f $HOME/.capstan/repository/todo-microservice/todo-microservice.qemu \
-n spring-boot-unikernel --boot hd -r 1024

Voila! The Spring Boot microservice is running happily as KVM guest. The image is about 114M (mainly because of openjdk runtime and Spring Boot dependencies), and less than 80M in size when compressed!

Are unikernels production ready?

As every new and disruptive technology, unikernels are getting positive as also as negative feedbacks. Bryan Cantrill has elaborated an extensive post on Joyent’s blog. He is showing a pretty pesimistic attitude about unikernels. His arguments about the undebuggable nature of unikernels are highly debatable. What if unikernel’s embryonic state could be the inception of a new generation of tools engineered and adapted for unikernel monitoring? Recall how before massive container adoption there was a limited visibility into it’s internals. The traditional system tracing tools lack of functionality needed to efficently explore the containers. As a consequence, tools like sysdig has appeared. Unikernels will definetly leave room for innovation.

When it comes to security concerns, saying unikernel’s premise of being more secure isn’t valid because of hypervisor’s flaws is equally applicable to any traditional OS as well. If an attacker breaks into your infrastructure with the hope of finding the full stack OS which could allow a privilege escalation, they’ll found smaller attack surface - less entry points to compromise, less chances for APTs to perform the lateral movement, etc.

The next few years are going to be crucial for unikernels existence. I am eager to see the outcome.