runtime.js — JavaScript library OS

Wouldn’t it be cool to use the operating system as a regular application dependency you can simply require()?

How is this possible?

If you’re following the news about cloud computing and operating systems, you may have heard about the library operating systems or unikernels. Huh, sounds like unicorns, but they’re actually the kind of specialized operating systems that are packaged into libraries that applications can depend on. This pretty much makes it possible to bundle up the OS right into the app and produce the standalone image that can be deployed into the cloud.

There is a great article on this topic that describes unikernels and also MirageOS implementation in detail (by Anil Madhavapeddy and
David J. Scott).

Why?

The idea is that instead of installing a full-featured OS, like Ubuntu, and then deploying the server applications that are supposed to run on top of it, one could compile an extremely small and specialized image that includes all the application code and only minimal set of the OS components required for that particular cloud service. For example, there is no need to include all kinds of drivers for various physical hardware, compilers and core utilities, or even a shell.

This way the resulting system is much more compact, has significantly smaller attack surface and, most importantly, it can make assumptions about its environment and expected workload. This means, for example, it can have extra knowledge on hosted application code and for a single-purpose appliance it may run everything in a single process or even in a CPU kernel mode to improve the performance.

And because all the code including the OS is bundled up into the image, accidental breakages on the production servers due to external dependencies changes (like OS libraries updates) can be avoided.

There are quite a few library OS or unikernel implementations, each one of them supports some applications environment. Some systems provide a full UNIX-like API and they can run any compiled applications similar to a general-purpose OS-es. But there are those, that focus on a specific language environment. For example, MirageOS is based on the OCaml runtime and language.

The language-specific systems are interesting, because they don’t have to support an entire POSIX interface, threads and preemptive multitasking, could be optimized for their language and provide an easy-to-use language API for users. As an example, MirageOS is completely event-driven and doesn’t implement threads.

JavaScript OS?

runtime.js is the library operating system or unikernel implementation based on the JavaScript VM. It’s in some way similar to MirageOS. runtime.js is focused on providing the platform for the JavaScript language, and, there are plans to integrate WebAssembly (WASM) in the future. It’s built on the V8 JavaScript engine, the same one used in Chrome and Node.js.

The system is event-driven and doesn’t have processes nor threads, the JavaScript VM runs in the CPU kernel mode with full access to the hardware (in most cases virtualized by the cloud service provider). It’s designed for the cloud and QEMU/KVM is the only supported hypervisor at the moment.

How easy is it to use?

The simplest “Hello World” application example looks like this:

A few commands are required to bundle it up and run locally in the QEMU. QEMU is the machine emulator and virtualizer similar to VirtualBox. runtimeify is the tool based on Browserify that produces ramdisk images out of JavaScript code. runtime-qemu is the wrapper around QEMU that can also download and run prebuilt runtime.js binaries.

If everything is correct, it should launch QEMU and produce the output similar to this:

Awesome! We’ve created our first unikernel image, which is actually two files — the initrd ramdisk image with the JavaScript code, and the precompiled runtime.js binary. The two resulting files could be combined into a single ISO image if necessary. It’s all less than 10 megabytes in size (V8 engine is pretty large, it is at least 8 megabytes).

HTTP server?

Hello World cloud program isn’t very interesting and useful, let’s build a Web server. I’m going to use the eshttp portable JavaScript HTTP library (note: it’s in early development and might be unstable):

Then install dependencies, compile and launch it:

npm install runtimejs eshttp
runtimeify ./runtime-http-server.js -o initrd
runtime-qemu ./initrd

Now it should be possible to curl our server running in the QEMU (runtime-qemu configures the port forwarding for the port 9000 by default):

$ curl localhost:9000
Hello World!

Pretty cool! We’ve got a very small and standalone web server OS image we can run locally or push somewhere into the cloud. It’s also immutable and does not require any installation nor configuration. The resulting server does not use disk and is completely stateless between reboots. And it boots in much less than a second under the KVM!

This also solves the local development problem, because you can run the same exact image locally in QEMU as in production. Image includes the bundled up version of the OS as well, so possible runtime.js patches could be tested locally very easily!

Let me know if you think this is an interesting idea. Would you use something like this for your cloud services? Tweet me @iefserge or #runtimejs. This is my first post, but I’d like to blog more about runtime.js in the future!

Cloneable examples on GitHub

Hello World: https://github.com/runtimejs/helloworld

Web Server: https://github.com/runtimejs/example-web-server

Links and info

runtime.js is an open-source project hosted on GitHub https://github.com/runtimejs/runtime

Some supported API docs are available on Wiki https://github.com/runtimejs/runtime/wiki/API-docs

runtime.js core library on npm https://www.npmjs.com/package/runtimejs

The project is in development and API might (and probably is going to) change. Also it’s not ready for the production use.

Oh, if you’d like to hack on some pretty low level things, contributions are welcome:)