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).
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.
How easy is it to use?
The simplest “Hello World” application example looks like this:
If everything is correct, it should launch QEMU and produce the output similar to this:
Then install dependencies, compile and launch it:
npm install runtimejs eshttp
runtimeify ./runtime-http-server.js -o 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
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:)