What you should know: I am currently working for Orbit Cloud Solutions as Cloud Advisor, but any posts on this blog reflect my own views and opinions only.

I have to admit, that after reading about the rump kernels, i was a both fascinated and scared to tinker around with unikernels. There has been some hype around unikernels running on cloud infrastructure as it really sounds like the concept was a perfect fit for the challenges we see in these environments: demand for high elasticity, robustness, efficiency, easy of deployment and of course security. When Amazon AWS came up with Firecracker, it seems that it might be the right time for these concepts to be tried out in real world scenarios.

So let’s take a look at one way to get a simple microservice running in Oracle OCI.

Setting up OPS

For easily building a nanovm/unikernel a great tool is OPS. Installation is dead simple, all you need to do is run this in your shell:

curl https://ops.city/get.sh -sSfL | sh

After the installation you can do a quick check with ops version. That’s it.

Setting up some example microservice

Just to see some code running on a unikernel, i picked a microservice from the Oracle mushop sample application that is showing the of a highly heterogeneous cloud-native implementation of a pet supplies shop. Just clone it from github and build one sample microservice. Then you can test it by simply starting it from the command line.

Great, we now got a working microservice. Now it is time to build a unikernel from that.

Creating the payment unikernel

As you saw, i was able to run the payment service locally on my machine. Unfortunately it is running macOS – and OPS is expecting a Linux binary here. So i need to recompile the code using

GOOS=linux go build -o payment cmd/main.go

Now the binary will not run on macOS anymore, but we can do something more interesting: build a microkernel and run that in an emulator (qemu).

Very nice. This is running now, but we will not be able to access it as port 8080 has not been exposed yet. So there still is some config to be done, luckily for this example nothing much needs to be done. We create a JSON file containing some rudimentary info:

{
  "RunConfig": {
    "Verbose": true,
    "Bridged": true,
    "Ports": [8080]
  }
}

Now building the unikernel image is more repeatable and well documented when the config is used. And actually now everything is done for this example – we got a tiny image file that we can run in qemu – and eventually import in a cloud environment as well.

Import Custom Image to OCI

So, the next step is of course to import the image that was just built in OCI. There is not much magic here, just make sure to use the qemu (QCOW2) format when importing the image. This can be done via GUI or via CLI. I created a little script for doing that import and put it on Github. What it basically does is creating a temporary object storage bucket, upload the image to this bucket, trigger the import of the image, wait until that has finished und clean everything up afterwards.

If you already have some bucket set up in OCI, then in CLI the upload and import can be done with these commands.

oci os object put -ns $oci_namespace -bn $oci_bucket --name payment.img
oci compute image import from-object -c $oci_compartment -ns $oci_namespace -bn $oci_bucket --name payment.img

Importing the image will take several minutes.

Launch the instance

Once the image has been imported, a new instance running it can be created. You will need a VCN and a subnet, as well make sure to loop up several OCIDs:

  • Compartment
  • Subnet
  • Availability Domain (get the list with oci iam availability-domain list)
  • Custom Image (that just got imported)

If you want to access the microservice from public internet, remember to open port 8080 in your security list. An now it’s time to launch the instance:

oci compute instance launch -c $ocicomp --shape VM.Standard2.1 --availability-domain $oci_ad --subnet-id $oci_subnet --image-id $oci_image --display-name 'unikernel-payment'

Once it is up and running, you can get the IP and try to call the payment microservice with curl.

curl http://xxx.xxx.xxx.xxx:8080/health
Conclusion

So is this unikernel running in OCI actually of any use for solving any real problem? Well, the exact setup here does not make sense apart from being a fun proof of concept. Even though i run the unikernel in the smallest compute shape on OCI, this still is way too big for this tiny thing. For any real case you probably will need to run the unikernels on some bare metal infrastructure where you can exploit most advantages, e.g. running hundreds or thousands of these. And then there is the need for some orchestration and management infrastructure, even though this probably is solved by the product offered by NanoVMs (the company behind OPS).

On the other hand it might already make sense to use a unikernel for components that will be exposed to high loads and possibly hostile clients, e.g. reverse proxies and api gateways. In a follow-up to this post i might look into some load testing of such clients running on unikernel basis.