Deploying Nanos Node.JS Unikernels to AWS

We recently added the t2 instance type so that you can deploy Nanos unikernels to AWS. T2s are nice because they are 1 VCPU, cost less than $5/month and are perfect to getting your feet wet with unikernels - also this instance type comes under the 'free tier'.

You can follow along in the video here or you can read the article - whatever works.

Note: This is an older article an an older video - YMMV.

Before we get started let's ensure we have three things:

  • AWS Account
  • S3 Bucket
  • OPS

I'm assuming you have an aws account - if not go sign up for one. Then OPS will need a spare s3 bucket in which to store images temporarily. There is no need to make it world readable so please don't do that. If you must you can re-use an existing s3 bucket but we'd just encourage a fresh one for ops images.

Finally, don't have OPS yet? Goto OPS.city and download it. We provide binary downloads but you can always choose to build from the source as well.

It's good to have an aws default config with your preferred region in it so you don't have to type it in each time - this is mine:

➜  ~  cat ~/.aws/config
[default]
output = json
region = us-west-1

You'll also want to have your aws credentials set up. You probably already have this if you've been deploying stuff to aws recently. Note: these are obviously fake credentials that we generated just as an example.

➜  ~  cat .aws/credentials
[default]
aws_access_key_id=AKNWQJPBGJVMALRYASAV
aws_secret_access_key=QTRNJEGYOOQOEAPAFOQKIHJIUMMJKBNPWJQVBHHB

To verify if your credentials are ok you can run this aws check:

aws sts get-caller-identity

Next let's create a working directory and slap two files in it. The first one is our config.json:

{
    "CloudConfig" :{
        "ProjectID" :"prod-1000",
        "Zone": "us-west-1",
        "BucketName":"my-s3-bucket"
    }
}

ProjectID can be set to whatever, zone should be your preferred zone. Bucketname is the s3 bucket you created earlier.

In hi.js put this in:

var http = require('http');
http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello World\n');
}).listen(80, "0.0.0.0");
console.log('Server running at http://127.0.0.1:80/');

Now let's create the image. It can take a few minutes. This process is much faster on Google Cloud, yet it's still faster than doing something like terraform. What's happening behind the scenes is that OPS instantly creates a disk image locally, uploads it to s3, creates a snapshot out of it and finally registers an ami that we can use. After that the ami is left around as an artifact image but the temporary s3 disk image is removed.

➜  node  ops image create -t aws -c config.json -p eyberg/node:20.5.0 -a hi.js
[node hi.js]
Successfully uploaded "node-image" to "nanos-test"
waiting for snapshot - can take like 5min....
import done - took 3.018038 minutes
deleting...
done deleting.
{

}
snap: 0xc000635648
{
  ImageId: "ami-03d09dbc3547f5481"
}
aws image 'node-image' created...
Once that's done we can see the images we've created:
➜  node  ops image list -t aws -z us-west-1
+------------+-------------------------------+-----------+--------------------------+
|    NAME    |              ID               |  STATUS   | CREATED                  |
+------------+-------------------------------+-----------+--------------------------+
| node-image | node-image1569526618413056000 | available | 2019-09-26T19:36:58.000Z |
+------------+-------------------------------+-----------+--------------------------+
| node-image | node-image1572367714886277000 | available | 2019-10-29T16:48:35.000Z |
+------------+-------------------------------+-----------+--------------------------+
| node-image | node-image1569528624219532000 | available | 2019-09-26T20:10:24.000Z |
+------------+-------------------------------+-----------+--------------------------+
| node-image | node-image1569529198030710000 | available | 2019-09-26T20:19:58.000Z |
+------------+-------------------------------+-----------+--------------------------+

As you can see I've uploaded a node image a few times. We can the name non-unique but will add a timestamp modifier to signify which image is what so you do things like canary, blue/green deploys, and rollbacks.

Then we can spin up an instance like so:

➜  node  ops instance create node-image -t aws -z us-west-1
Created security group sg-0f8efa77e463ce558 with VPC vpc-01507366.
Created instance i-02088b58772c35463

As you can see this process is fairly instant and unlike Linux it doesn't take minutes to boot and fork a thousand processes off. Nanos, the underlying kernel supports multiple threads but not multiple processes cause it's 2020 not 1980. It jumps straight into your application. By default it will create a security group tied to the port you opened up.

Now if we list the instances we can see it running:

➜  node  ops instance list -t aws -p prod-1033 -z us-west-1
+------------+---------------------+---------+-------------------------------+---------------+---------------+
|    NAME    |         ID          | STATUS  |            CREATED            |  PRIVATE IPS  |  PUBLIC IPS   |
+------------+---------------------+---------+-------------------------------+---------------+---------------+
| node-image | i-02088b58772c35463 | running | 2019-10-29 16:54:34 +0000 UTC | 172.31.10.212 | 13.57.181.233 |
+------------+---------------------+---------+-------------------------------+---------------+---------------+
| node-image | i-02a6cadbb1c9d3fd7 | running | 2019-10-25 18:07:33 +0000 UTC | 172.31.1.57   | 54.193.39.9   |
+------------+---------------------+---------+-------------------------------+---------------+---------------+

Now if we hit it up with curl we can it is listening:

➜  ~  curl -XGET http://13.57.181.233
Hello World
➜  ~  curl -XGET http://13.57.181.233
Hello World

Once you're done don't forget to spin the instance down.

➜  node  ops instance delete -p
prod-1033 -t aws -z us-west-1 i-02088b58772c35463

Great! You just deployed your first unikernel to amazon using node.js! Don't forget to start the repo and open up any pull requests if you've got them.

Deploy Your First Open Source Unikernel In Seconds

Get Started Now.