Home 5 min read

0x005 - Unikernels 🏍️

Hi, y’all! This is the fifth issue of unzip.dev, a newsletter dedicated to developer trends, where we unpack trending dev concepts. My name is Agam More, and I’m a developer generalist. Join the ride and have fun!

Unikernels

Deploy with a bare-essentials mindset.

TL;DR:

  • Problem: You want faster and leaner VMs/containers.
  • Solution: Compile a slim and performant OS custom-made for your application.
  • In Sum: Unikernels have not caught up yet, but the tides may change, because of all the progress, improvements, and serious players pushing it.

How does it work? 💡

The Unikernel has modular parts such as memory allocators, schedulers, and network stacks, so you can pick what your application specifically needs.

The process depends on whether you are using an interpreted or compiled language:

Interpreted language (Python, JS, PHP…)

  1. You pick a pre-built base image: the Unikernel usually has a pre-built image for each runtime with all the necessary libraries (e.g. Ruby/PHP will need libxml).
  2. Pick application-specific libraries, either by hand or by utilizing a Unikernel compiler that can determine libraries from code-specific dependencies (e.g. Node’s package.json).

Compiled language (C, Golang…)

  1. You compile your code.
  2. The Unikernel does binary analysis and rewriting, replacing syscalls with direct calls to its modular parts.
  3. (Optional) You can pick extra libraries you know you need.

Deploy:

  1. Compile the application with the selected libraries and produce a statically linked kernel image (embedding only the kernel bits that are needed by the application) that is bootable with a single address space.
  2. Deploy the compiled image to the cloud on a hypervisor or hardware (rare).
    1. Some even produce an AMI (for AWS).

Your application can still be performant on a Hypervisor (type I) because the Hypervisor is running your compiled OS against the bare-metal components, plus, you don’t have to deal with hardware-related drivers.

Use cases ✅

  • Docker speed doesn’t cut it, as it duplicates both storage and networking layers and still uses the Linux kernel behind the hood without optimizations.
  • Linux speed doesn’t cut it, you need to squeeze even more performance by optimizing what you can (context switches, address space…) - Unikernels try to achieve that.
  • Interesting for micro-services because of fast boot times and inherent single responsibility.

Why? 🤔

  • Performance increase: Running target software directly in a single kernel binary eliminates many performance-costly low level operations at the syscall, context-switch and memory management levels and allows for highly minimized overhead. Note, this is very Unikernel implementation-specific. See off-the-shelf boost of 1.7x-2.7x performance of Nginx, SQLite, and Redis - reference.
  • Size: Fewer libraries = size reduction, typical image size ranges can range between 1-10 MB.
  • Memory usage: Less code needs to be allocated, so there is less RAM needed.
  • Boot speed: Unikernels tend to boot quickly because of their minimalistic nature, typical boot times are sub-second (sometimes in ms units!).
  • Security: The attack surface is smaller (as an example and assuming it is not needed: no need for Bluetooth, shell access, USB, file-sharing support...). Plus, you are not sharing a kernel like containers do.
  • Manageability: No need to mess around with most of the OS updates and IT. Unikernels lend themselves to immutable deployments (IaC style).
  • Cheaper cloud costs: Because you are running faster and leaner images, you can run smaller instances or be charged less for usage. (Cutting costs by half - a marketing piece, but the data is still interesting).

Why not? 🙅

  • General-purpose computing: By definition, Unikernels are compiled to contain the bare essentials, if a new need arises you need to typically compile a new Unikernel image.
  • Security: Security measures such as ASLR, stack canaries, and others are not present in some Unikernels which reduces security (Reference).
  • New: Modern Unikernels don’t seem to be mature for every use case. Some vulnerabilities and security issues are still present, plus the learning curve to migrate to such a methodology can be hard for many organizations.
  • Manageability: Adopting Unikernels may be hard to implement on a large scale, it doesn’t seem to have prevalent tooling for updating and deploying Unikernels at scale at the moment.
  • Limited debugging capabilities: Most often you need to reproduce failures on a dev environment.
  • Optimizations aren’t necessary: If you are developing an MVP for a startup that produces basic CRUD operations, speed isn’t a big deal relative to your delivery time of the project. Unikernels won’t necessarily help you get there faster, until they are widely adopted and part of your normal development flow (like containers are today).

Tools & players 🛠️

  • Unikraft - Unikernel that supports x86 & Arm and plenty of IaaS providers.
  • nanovms - An enterprise-level Unikernel solution with security features you’d see in a normal OS (closed-source).
    • Nanos & ops - The open-source offerings from nanovms.
  • MirageOS - OCaml based Unikernel, in active development.
  • OSv - A Linux compatible Unikernel.
  • HermiTux - A Binary Linux compatible Unikernel (still a proof-of-concept).
  • unik - A tool for compiling an application source into a Unikernel.
  • eggos - A Go Unikernel for x86 bare-metal deployments.
  • Solo5 - Sandboxed execution environment for running Unikernel applications.
  • Hypervisors - Xen, KVM, QEMO, BHyve (FreeBSD), VMM (OpenBSD) - check what your Unikernel supports.
🤠
My opinion: If you need the most production-ready solution and are willing to spend money, I’d check out nanovms. Otherwise, I would probably play with Unikraft/ops as their developer experience seems the most intuitive, they mitigated most of the cons above, and are very active.

Forecast 🧞

  • Market adoption: For Unikernels to be widely adopted I think there needs to be more developer-friendly tooling and articles to make this subject accessible. Also, production and security concerns must be mitigated and talked about. It seems like we’ve come a long way, but there still seems some way to go.
    • POSIX-compliant Unikernels (like nanovms and Unikraft and HermiTux) could be real game-changers as you won’t need to port your application.
    • Assuming this happens, I’m not sure what the whole ecosystem of containers will look like, but I bet it will be a very different place to be a DevOps engineer 😅
  • Hobby projects will die: Some open-source projects like IncludeOS and Rumprun are stagnant. Unikernels are hard to develop. Before you commit to a Unikernel, make sure the development is active and support is present.
  • Serverless & edge computing: All the advantages can play right into those deployment methodologies which can help propel Unikernels grow. Unzip.dev will cover both concepts soon ✨
  • Idea: Create a Unikernel-centric k8s…

Examples ⚗️

Try it out yourself?

Extra

Thanks 🙏

I wanted to thank Roy Feldman (One of the smartest & nicest people I know who currently teaches security for B2Bs), Omer Katz (Who has some great security & low-level insights - follow this guy!) & Pierre Olivier from The University of Manchester (Who helped review some technical aspects in this issue, he really knows a thing or two about Unikernels 😉).

EOF

I recently found out about a delightful little newsletter gem by a Senior engineering manager named Csaba. He writes about leadership in tech. I really like that his emails are very short, elegant and contain a cute foreign reference (currently Japanese) - go check it out here.


Any questions, feedback, or suggestions are welcome 🙏

Simply reply to this e-mail or tweet at me @agammore - I promise to reply!