Unikraft aims to offer a Linux-compatible environment (so it feels familiar) with the ability to strip out unnecessary internal components in order to improve both boot-time/runtime performance and operational security.
Why would you need a memory allocator and garbage collector if you serve static content? Why would you need a scheduler if your app is run-to-completion?
Linux gives you the safety-net of generality and if you want to do anything remotely performant, you by-pass/hack it altogether.
In the article, Unikraft cold-boots in 150ms in an emulated environment (TCG). If it was running natively with virtualization hardware extensions, it can be even shorter, and without the need for snapshots which means you don't need to store this separately either.
Unikraft is cool, I still have it in my 'todo' list to play around with sometime.
Linking the app with the 'kernel' seems pretty nice, would be cool to see what that looks like for a virtio-only environment.
Just wanted to point out that the 150ms is not snapshot based, you can get <10ms for small vms (128MB ram, 2GB ram moves you to ~15ms range), for 'cold' boots.
This project operates by first building the webassembly module into an ELF binary and then statically linking this against the Mewz library OS in order to become a unikernel binary.
It looks still very early days in terms of supporting all libc/syscalls as well as support for different platforms.
I wonder how this compares in terms of performance to https://unikraft.org which is able to do the same but is a more establish libOS/unikernel project (disclosure I am a maintainer of Unikraft :-)) since this is written in Zig and Unikraft is written in C.
Good point on the Kraftfile syntax and as you've seen, there is a reference document. We can make sure to place a link to this in all guides.
The term "KraftCloud Specification" is in fact incorrect, this should just be "`Kraftfile` specification".
We are working on providing a "Unikraft Hub". Since unikraft.org is a public OCI registry and it works through many popular tools like `crane` or `regtool` as well as our native `kraft` CLI tool; you can actually view it locally by running `kraft pkg ls --all --apps --remote`.
Thanks again for the feedback! We'll get on to updating the docs to make these bits clearer!
Correct -- and you can run multiple kernels on the machine with virtualization extensions. Even Docker Desktop does this. You'd do this for _real_ isolation purposes.
Containers are perfect for build environments and for creating the root filesystem. The issue is that the kernel these days are super bulky and are intended for multi-user, multi-process environments. Running a container runtime on top just makes it worse when you're looking for "isolation".
This paper argues that when you build a extremely minimal kernel (i.e. ditch Linux entirely) and link your application against necessary bits of code to execute _as_ a VM, then you'll get better performance than a container and you'll get that isolation.
I am looking at the examples. They all have a Docker file. If that just for local development on my laptop?
Using the deploy command line tool is the Docker file used to determine dependencies for the hosted VM? What if a developer is using an unusual programming language, like Common Lisp. Is that doable?
A Dockerfile is just a file with a bunch of commands to execute and get a working "computer". https://github.com/combust-labs/firebuild is fairly aged translation of the Dockerfile to a VM rootfs.
> build a extremely minimal kernel (i.e. ditch Linux entirely) and link your application against necessary bits of code
It would be nice, but this is really hard to do when modern software has so many layers of crud. Good luck getting say, a PyTorch app, to work doing this without some serious time investment.
But you don't need to write against all the layers of crud. You only have to write against the bottom layer, the kernel API. This sort of software would have no need to specifically support "libxml" or "TLS", because that is multiple layers above what this sort of software does.
The flip side is that if you want something like low-level access to your specific graphics card you may need to implement a lot of additional support. But of course nothing says you have to use this everywhere at the exclusion of everything else. There's plenty of systems in the world that from the kernel point of view are basically "I need TCP" and a whole bunch of compute and nothing else terribly special.
[Author of the paper here] You hit the nail on the head, this is precisely what we do (kernel API compatibility) with the LF Unikraft project (the evolution of the 2017 paper) at www.unikraft.org, and kraft.cloud, a cloud platform that leverages Unikraft.
Most of that effort should be sharable. if you know you will only have one python process you can get rid of a lot of cruft. If you know you will be running in a VM then you only need the driver for the network interface the VM provides not every network interface every designed (often including ones that your hardware doesn't even physically support). So while there is serious time investment it isn't nearly as much as it would be to write a competitor to linux.
I'm not sure if I missed a bit here, but I have some colleagues doing research on unikernels for HPC and the point is that this unikernel is running directly on the hardware or hypervisor and not inside another VM. The unikernel is effectively a minimal VM and the network stack is one of the things they struggle the most with due to sheer effort.
[One of the authors of the paper] I wouldn't recommend writing a network stack from scratch, that is a lot of effort. Instead, with the Unikraft LF project (www.unikraft.org) we took the lwip network stack and turned it into a Unikraft lib/module. At KraftCloud we also have a port of the FreeBSD stack.
If you're looking for an alternative way to run traefik, we support this out-of-the-box on https://kraft.cloud -- A platform dedicated to running ultra-lightweight VMs based on Dockerfiles, with millisecond cold start times (96ms for Traefik), scale-to-zero, autoscale.
You can, and we've written about the differences also, here [0].
The summary is that there is still a performance hit for boot time (100s of milliseconds to seconds vs. 1 to 100 of milliseconds for Unikraft); performance hit at runtime (even removing the syscall boundaries has a less-than-ideal impact based on previous studies); and, there's extra bloat from the image size itself (the image is still at the very least 30MB+ vs. as little as 100KB for Unikraft) which affects startup time and cost of storage + transport.
We are seeing an increasing trend towards On-prem/Cloud-prem/Co-los[0], mainly due to cost and reduced complexity. Inversely, most smaller companies (1-10 emp) who use hyperscalers do not use their metal offerings, because of cost. They wish to scale with demand which metal cannot provide. Using EKS and other similar services have the benefit of being familiar and elastic, but are in fact slow and soon become quite expensive[1].
This has been a goal of Unikraft for a long time, to make using unikernels simple and familiar to use (in fact, transparent). This is why we use OCI images as the root filesystem; why it's possible to start unikernels through Docker; why we have several types of Kubernetes integrations.
> How do you debug a running app?
For one, you can attach a gdb server and step through both application code and kernel code together. Secondly, at Unikraft at least, we are introducing a virtual shell that allows you to introspect the filesystem, main threads, see system stats, etc.
> Stripped down Linux distros reduces attack surface
This is may reduce the attack surface, but one bad-actor application can still take down the host and all the other containers since they are still process (software) isolated. With unikernels you get hardware-level isolation AND, interestingly, the performance thanks to the lack of strong syscall boundaries.
> Unikernels increase complexity
Give us a chance and try out one of our examples :-)
In fact gVisor is the opposite, it injects more guard instructions between the application and the kernel across the syscall layer in order to make stronger security guarantees. These additional guards slow the application even further by however long it takes to perform necessary permission checks.
It is not necessary to have such checks in a unikernel because the kernel inherently trusts the application because together they were constructed in the same pipeline. The hardware then protects the two together.
Unikraft aims to offer a Linux-compatible environment (so it feels familiar) with the ability to strip out unnecessary internal components in order to improve both boot-time/runtime performance and operational security.
Why would you need a memory allocator and garbage collector if you serve static content? Why would you need a scheduler if your app is run-to-completion?
Linux gives you the safety-net of generality and if you want to do anything remotely performant, you by-pass/hack it altogether.
In the article, Unikraft cold-boots in 150ms in an emulated environment (TCG). If it was running natively with virtualization hardware extensions, it can be even shorter, and without the need for snapshots which means you don't need to store this separately either.