Requiring the os - runtime-js

Posted by Marcus Hammarberg on September 20, 2015
Stats

This is my second attempt to write this post. It’s not that the post itself is hard to write but the concept makes my head … go ouchie. That tend to happen to my head when I see potential quantum leaps.

Instead of the fancy intro I had planned, I’m just going to give a short introduction, point you to an awesome article, tell you how to get this to run.

So what is it then? Basically runtimejs is a tiny, unikernel OS that you can bundle together with your application, as a dependency to your application. Which is basically what a OS is, right? Our application needs some libraries like koa, a runtime-platform (like Node) and an OS (like Linux) that the platform can run.

What if that last part just was a dependency like normal to our application? Like this:

"dependencies": {
    "a_small_little_os_just_for_me": "latests"
}

That would be so cool. Let me show to get that to work for a Koa application

Create the application

I’ve created a very basic, but not trivial Koa application (using npm init) and then this single file:

var koa = require('koa');
var app = koa();

app.use(function *(){
    this.body = "Hello World from Koa... In a Unikernel container!";
});

app.listen(9000);
console.log("The app is now listening - try it on http://localhost:9000");

It’s just a little Hello world app, since that’s where we all need to start, right?

Depend on a OS

Let’s me introduce you to an operating system that I almost guarantee you have not heard about: runtimejs. It’s a language-specific unikernel operating system.

Basically that it’s tiny and dedicated to run just a certain type of application. In our case Node-applications. Let’s run our application on that, shall we?

Do this: at the top of our index.js file add this line:

var runtime = require('runtimejs');

This of course mean that we need to install runtimejs as a runtime dependency to our app;

npm install runtimejs --save

Sadly, after that if we try to run it we fail. With a scary error message (kernel is not defined). While this seems like we broke our entire machine at first, it’s actually easy to understand when you have stopped hyperventilating.

We just said that the app now depends on the runtimejs operating system. But you are running it on something else. Me on OsX, you might be on Linux or Windows. The kernel object that runtimejs is looking for is simply not there.

But we’re going to fix all of that now.

Run from an image

To get this too work we need two development-time tools. Let’s install them and I’ll see if I can explain what it does:

npm install runtimeify runtime-tools --save-dev

runtimeify (OMG those names… let’s try something new, shall we?) takes our code and creates an “ramdisk” image with the runtimejs operating system and our application on it. Basically creates a tiny disk with the OS and the application installed on, ready to run. The command to do so is this:

runtimeify index.js -o [name of disk]

Since I’m into scripting with npm and package.json right now, let’s create a command called image:create and add it to our scripts in the package.json file:

"image:create" : "runtimeify index.js -o appImg"

The second tool above, runtime-tools, is a Node wrapper around a virtual machine emulator called QEMU. That’s about everything I know about QEMU… think of it as a lightweight VirtualBox, Parallels or VMWare and then go “la la la la la” - that’s what I do.

To start an image in QEMU using the runtime-tools we should have another script in package.json don’t you think? Here it is:

"image:start" : "runtime-qemu ./appImg" 

Quite simple: just the runtime-qemu and then the name of the file we created with the image:create script. runtime-qemu is the name of the executable for runtime-tools, a bit unfortunate naming there. You can check it with ls node_modules/.bin should you forget it.

Install QEMU

This of course require us to have QEMU installed. Easiest is to do that with Homebrew

brew install qemu

Use sudo apt-get install qemu if you are on Linux. Or download an executable from here if you’re on Windows. Check the install instructions here.

This part is, of course, only required if you don’t have QEMU installed already.

Run it

Now, we create a command to launch our application in a image.

"start" : "npm run image:create && npm run image:start"

This will, the first time, download a 10Mb file for the entire OS. Secondly the command will add your application and finally launch it with QEMU.

The entire scripts-node of my package.json now looks like this:

"scripts": {
  "image:create": "runtimeify index.js -o appImg",
  "image:start": "runtime-qemu ./appImg",
  "start": "npm run image:create && npm run image:start"
}

Fingers crossed.

Ah well… actually - I’ve done that before. I know it fails. For some reason Koa needs bluebird to run on the runtimejs operating system. Don’t really know why. Install it with npm install bluebird --save for better WOW-factor in the demo.

Try it

And now… npm start.

It should start up after a little while (5 min for my Indonesian connection… 10 secs for you guys) the runtimejs OS is downloaded and the application is started. In a separate OS. On a separate image.

For subsequent launches this takes about 3 seconds. Even on Indonesian Internet connections, because it’s all local.

First head to a browser and direct it to http://localhost:9000. And you should see our beautiful site. Running in a container!

Now, check your windows. If you look carefully you should see a QEMU emulator running. That’s you operating system and your applications little cozy environment. Just for your application. Just enough.

Finally - shut the application down with CTRL-C as normal. Notice that QEMU is shutting down too.

Summary

Ok - at this point I was gasping for air. It’s so cool. Without leaving the current environment, NodeJs, I can bundle my application up with the dependency it has on a operating system. A small, unikernel operating system. A language specific, library, require-able operating system.

This image can now be pushed to a cloud host. You have already tried the runtime locally. It’s the same as production runtime… because it’s actually the same image, same disk running in the production environment.

It’s also a tiny operating system, with only the services you need included.

Me thinks… they are onto something here. I think we will see much more of stuff like this in the future.

A couple of things

  • Right now you can only use port 9000. Because that is the default port that QEMU uses
  • I have not investigate where I can push this. But that should be any host for that allow me to run qemu, or that can host those images directly
  • I wanted to read a file from the file system to impress you all … but that threw an error fs.readFileSync is not a function Seems like it’s not supported yet in runtimejs.
  • My code can be found here

Read more

This article was great from the creator of runtime-js

More about runtimejs itself is found on their site. As they say all of this is very early stages of development and much of it can change but still…

Here’s a discussion on unikernels and docker and a lot of stuff that I cannot understand really.



Published by Marcus Hammarberg on Last updated