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 inruntimejs
. - 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.