I recently wrote a DNS server that can boot unikernels on demand called Jitsu. The following diagram shows a simplified version of how Jitsu works. The client sends a DNS query to a DNS server (Jitsu). The DNS server starts a unikernel and sends a DNS response back to the client while the unikernel is booting. When the client receives the DNS response it opens a TCP connection to the unikernel, which now has completed booting and is ready to respond to the TCP connection.

The unikernels are built using MirageOS, a library operating system that allows applications to be compiled directly to small Xen VMs. These unikernels only include the operating system components the application needs - nothing else is added. This results in very small VMs with low resource requirements that boot quickly.

Now, what if I wanted to use Jitsu to boot my unikernel website when someone accesses it? My website is fairly low traffic, so this could potentially save me some resource use and hosting costs. Unfortunately, there are always a few requests per hour to some of the more popular sections, which likely would make my unikernel run most of the time. But what if I could split my unikernel into even smaller unikernels? What if I went to an extreme and had one unikernel per URL? Then I could only boot unikernels for the URLs that are being used and they would only need to know how to serve a single page. This could also have a number of benefits, such as the ability to spin up multiple unikernels for an extremely popular web page and use DNS to direct clients to the unikernel that is closest to them — while keeping the rest of the site inactive (let's ignore web crawlers for now). If I had dynamic sections of my website there could also be security benefits: Every dynamic page would run as a separate VM. An attack on a single page would not have to bring down the rest of the site nor reveal any data stored in other unikernels.

As an experiment, I wanted to see if I could run every URL hosted under my domain as a separate virtual machine. The goal was to map each URL to a domain name, which in turn was directed to a separate VM running a web server that hosts a single page. For example, the URL http://www.skjegstad.com/index.html becomes http://index.html.www.skjegstad.com/. Each domain is then mapped to a single IPv4 address on my local network.

Here is an abstract from the DNS zone file.

index . html . www . skjegstad . com IN A 192.168.56.10 images . profile . jpg . www . skjegstad . com IN A 192.168.56.11 ardrone - experiment - 1. blog . images . ardrone - test . m4v . www . skjegstad . com IN A 192.168.56.12 ardrone - experiment - 1. blog . images . camera - 33. jpg . www . skjegstad . com IN A 192.168.56.13 ardrone - experiment - 1. blog . images . ardrone - test . png . www . skjegstad . com IN A 192.168.56.14 [...]

You can see that even individual images have their own DNS entry, and will be served separately.

There is an OCaml web server library, called CoHTTP, which we can use with MirageOS. Using this library, unikernels can be written that host static web pages. The web content itself can either be compiled into the unikernel (as a data structure) or be stored directly on a block storage device. For this experiment, I use the built-in data structure to store a single file per unikernel.

For the unikernel code, I take the static_webserver example from mirage-skeleton. The code automatically creates a web server that hosts the files located in the ./htdocs subdirectory when the unikernel is built.

The demo code (available here) accepts a directory with static web pages as input. I will use my own website in the examples below, but any site with static web pages should work.

First, mirror (or copy) a static website:

$ wget - m www . skjegstad . com

Then run the create.py script to generate a unikernel with a web server for each file, which will serve that single file from memory. Note that the folder name and domain name must match - otherwise the script will become confused and not rewrite the URLs properly. My site has 49 pages and I've copied the entire output below. This step should only take a few seconds on a reasonably modern machine.

# Run create.py on the contents of the www.skjegstad.com folder. Folder name and domain name must match. $ python create . py www . skjegstad . com Indexing www . skjegstad . com ... Preparing unikernel for index . html . www . skjegstad . com / index . html in staging / 85956378 dc89cf3a2729 Preparing unikernel for images . profile . jpg . www . skjegstad . com / profile . jpg in staging / f7fb9c68d5c3701996b3 Preparing unikernel for ardrone - experiment - 1. blog . images . ardrone - test . m4v . www . skjegstad . com / ardrone - test . m4v in staging / c286eccb0f59b299cca1 Preparing unikernel for ardrone - experiment - 1. blog . images . camera - 33. jpg . www . skjegstad . com / camera_33 . jpg in staging / 5 bef80428ab04abb98c3 Preparing unikernel for ardrone - experiment - 1. blog . images . ardrone - test . png . www . skjegstad . com / ardrone - test . png in staging / 41 d9ee421440ceec86a4 Preparing unikernel for ardrone - experiment - 1. blog . images . ardrone1 . jpg . www . skjegstad . com / ardrone1 . jpg in staging / a9fdfed9d054ee4d48de Preparing unikernel for ardrone - experiment - 1. blog . images . camera - 28. jpg . www . skjegstad . com / camera_28 . jpg in staging / 5 ca0d87ae96d8648c36d Preparing unikernel for ardrone - experiment - 1. blog . images . screenshot1 . png . www . skjegstad . com / screenshot1 . png in staging / 5 b1ce89d1c806c4234f2 Preparing unikernel for mirage - dev . blog . images . ubuntu - in - vm - overview . jpg . www . skjegstad . com / ubuntu_in_vm_overview . jpg in staging / 0 d368ef42317b28f6243 Preparing unikernel for mirage - dev . blog . images . xen - in - vm - overview . jpg . www . skjegstad . com / xen_in_vm_overview . jpg in staging / 2 a4e519b0d91b8967b62 Preparing unikernel for uavexperiment . blog . images . MobileNode . png . www . skjegstad . com / MobileNode . png in staging / 390 a92f0488aa32f17e3 Preparing unikernel for uavexperiment . blog . images . image6 . jpg . www . skjegstad . com / image6 . jpg in staging / f9a90e263ac465d53558 Preparing unikernel for uavexperiment . blog . images . image1 . jpg . www . skjegstad . com / image1 . jpg in staging / fc21dfa295c33c6e3bd3 Preparing unikernel for uavexperiment . blog . images . image5 . jpg . www . skjegstad . com / image5 . jpg in staging / afc6634e807f1bddad22 Preparing unikernel for uavexperiment . blog . images . image4 . jpg . www . skjegstad . com / image4 . jpg in staging / 1f 7 b97ef7d3a4a1ba0f4 Preparing unikernel for uavexperiment . blog . images . image3 . jpg . www . skjegstad . com / image3 . jpg in staging / 4 dedbc5bfcd11fe49a83 Preparing unikernel for uavexperiment . blog . images . image2 . jpg . www . skjegstad . com / image2 . jpg in staging / 8f15f a23ae6563d2d890 Preparing unikernel for software . index . html . www . skjegstad . com / index . html in staging / 855 d32b8905249554f69 Preparing unikernel for macvim - and - funnel - pl .05.01.2012 . blog . index . html . www . skjegstad . com / index . html in staging / cb72fc8606b734fd7322 Preparing unikernel for ardrone - test - flight - 1.12.01.2012 . blog . index . html . www . skjegstad . com / index . html in staging / 570 b6f207695db4d2898 Preparing unikernel for mirageos - xen - virtualbox .19.01.2015 . blog . index . html . www . skjegstad . com / index . html in staging / 9 ada75a179f0d6c6cdff Preparing unikernel for experimenting - with - distributed - chat .02.12.2011 . blog . index . html . www . skjegstad . com / index . html in staging / 0 d0613c7f413609ab402 Preparing unikernel for a - stand - alone - java - bloom - filter .20.10.2011 . blog . index . html . www . skjegstad . com / index . html in staging / c11e5af4b1a8ee667bf5 Preparing unikernel for virtualbox . categories . blog . index . html . www . skjegstad . com / index . html in staging / 198f10ff b77757798200 Preparing unikernel for bloom - filters . categories . blog . index . html . www . skjegstad . com / index . html in staging / da3c099920c48f77b625 Preparing unikernel for mist . categories . blog . index . html . www . skjegstad . com / index . html in staging / ec590d332b74f3521787 Preparing unikernel for unikernel . categories . blog . index . html . www . skjegstad . com / index . html in staging / befa876942eb63d806d0 Preparing unikernel for experiments . categories . blog . index . html . www . skjegstad . com / index . html in staging / 2 d14e6010e04324f1fa9 Preparing unikernel for vim . categories . blog . index . html . www . skjegstad . com / index . html in staging / d09920f7a15c2f930686 Preparing unikernel for xen . categories . blog . index . html . www . skjegstad . com / index . html in staging / 9 bd2e2788f6309bc762c Preparing unikernel for mirageos . categories . blog . index . html . www . skjegstad . com / index . html in staging / 8 b08718e16dddf30473f Preparing unikernel for ardrone . categories . blog . index . html . www . skjegstad . com / index . html in staging / dfc57a0ce3fc7382a001 Preparing unikernel for java . categories . blog . index . html . www . skjegstad . com / index . html in staging / a13890b437ef10df36e4 Preparing unikernel for papers . skjegstad - mistsd - milcom2010 . pdf . www . skjegstad . com / skjegstad_mistsd_milcom2010 . pdf in staging / 2 b39a34888b769596fe0 Preparing unikernel for papers . milcom09skjegstad . pdf . www . skjegstad . com / milcom09skjegstad . pdf in staging / 09854f 35 b4a6c9bafe01 Preparing unikernel for papers . milcom11 - distributed - chat . pdf . www . skjegstad . com / milcom11_distributed_chat . pdf in staging / 759 daabffb7ac70f3c82 Preparing unikernel for publications . index . html . www . skjegstad . com / index . html in staging / 2434 cc8c7a5f966b2bc9 Preparing unikernel for about . index . html . www . skjegstad . com / index . html in staging / 6ff 5 ef4c2d9236d7a398 Preparing unikernel for js . theme . modernizr - 2.0 . js . www . skjegstad . com / modernizr - 2.0 . js in staging / 1 b8ff82e33ce3d777d9e Preparing unikernel for js . theme . octopress . js . www . skjegstad . com / octopress . js in staging / 2e5 e43546763b649cd3b Preparing unikernel for js . theme . ender . js . www . skjegstad . com / ender . js in staging / edf18f0bba513af40346 Preparing unikernel for js . theme . github . js . www . skjegstad . com / github . js in staging / a577cb04bac38034dc95 Preparing unikernel for images . theme . noise . png . www . skjegstad . com / noise . png ? 1395516324 in staging / e9d12885cf941b2f149c Preparing unikernel for images . theme . search . png . www . skjegstad . com / search . png ? 1395516324 in staging / c23144b5f096a13a71bb Preparing unikernel for images . theme . code - bg . png . www . skjegstad . com / code_bg . png ? 1395516324 in staging / 19e1 de022f4a565bc1e2 Preparing unikernel for images . theme . line - tile . png . www . skjegstad . com / line - tile . png ? 1395516324 in staging / 29ff 05 b603a5d0cdebdc Preparing unikernel for images . theme . email . png . www . skjegstad . com / email . png ? 1395516324 in staging / 4 d4e8d94047cf9c45080 Preparing unikernel for images . theme . rss . png . www . skjegstad . com / rss . png ? 1395516324 in staging / 433115 bed52cbea861a0 Preparing unikernel for css . theme . main . css . www . skjegstad . com / main . css in staging / 1 bacfdf7b71099057d8c Zone file generated in www . skjegstad . com . zone . Makefile generated . Type ' make ' to build , ' make run ' to run and ' make destroy ' to stop VMs . Start local DNS server with ' make dns '

When the script completes, a unikernel has been created in ./staging for each file in the www.skjegstad.com directory. To compile the unikernels using the mirage-tool, run make . Note that this requires a working MirageOS development environment and I have written a guide for setting this up here. This step will take some time, depending on how many pages you have. In my case, it was around 4 minutes in Virtualbox on my laptop.

When all the unikernels have been successfully built, make run will start each of them using Xen's xl tool. Use sudo xl list to see the running unikernels. This is the xl output for 49 MirageOS virtual machines hosting www.skjegstad.com on my local network:

$ sudo xl list Name ID Mem VCPUsStateTime ( s ) Domain - 0 0 292 1 r ----- 2156.1 85956378 dc89cf3a2729 39 32 1 - b ---- 0.1 f7fb9c68d5c3701996b3 40 32 1 - b ---- 0.1 c286eccb0f59b299cca1 41 32 1 - b ---- 0.1 5 bef80428ab04abb98c3 42 32 1 - b ---- 0.1 41 d9ee421440ceec86a4 43 32 1 - b ---- 0.1 a9fdfed9d054ee4d48de 44 32 1 - b ---- 0.1 5 ca0d87ae96d8648c36d 45 32 1 - b ---- 0.1 5 b1ce89d1c806c4234f2 46 32 1 - b ---- 0.1 0 d368ef42317b28f6243 47 32 1 - b ---- 0.1 2 a4e519b0d91b8967b62 48 32 1 - b ---- 0.1 390 a92f0488aa32f17e3 49 32 1 - b ---- 0.1 f9a90e263ac465d53558 50 32 1 - b ---- 0.1 fc21dfa295c33c6e3bd3 51 32 1 - b ---- 0.1 afc6634e807f1bddad22 52 32 1 - b ---- 0.1 1f 7 b97ef7d3a4a1ba0f4 53 32 1 - b ---- 0.1 4 dedbc5bfcd11fe49a83 54 32 1 - b ---- 0.1 8f15f a23ae6563d2d890 55 32 1 - b ---- 0.1 855 d32b8905249554f69 56 32 1 - b ---- 0.1 cb72fc8606b734fd7322 57 32 1 - b ---- 0.1 570 b6f207695db4d2898 58 32 1 - b ---- 0.1 9 ada75a179f0d6c6cdff 59 32 1 - b ---- 0.1 0 d0613c7f413609ab402 60 32 1 - b ---- 0.1 c11e5af4b1a8ee667bf5 61 32 1 - b ---- 0.1 198f10ff b77757798200 62 32 1 - b ---- 0.1 da3c099920c48f77b625 63 32 1 - b ---- 0.1 ec590d332b74f3521787 64 32 1 - b ---- 0.1 befa876942eb63d806d0 65 32 1 - b ---- 0.1 2 d14e6010e04324f1fa9 66 32 1 - b ---- 0.1 d09920f7a15c2f930686 67 32 1 - b ---- 0.1 9 bd2e2788f6309bc762c 68 32 1 - b ---- 0.1 8 b08718e16dddf30473f 69 32 1 - b ---- 0.1 dfc57a0ce3fc7382a001 70 32 1 - b ---- 0.1 a13890b437ef10df36e4 71 32 1 - b ---- 0.1 2 b39a34888b769596fe0 72 32 1 - b ---- 0.1 09854f 35 b4a6c9bafe01 73 32 1 - b ---- 0.0 759 daabffb7ac70f3c82 74 32 1 - b ---- 0.0 2434 cc8c7a5f966b2bc9 75 32 1 - b ---- 0.0 6ff 5 ef4c2d9236d7a398 76 32 1 - b ---- 0.0 1 b8ff82e33ce3d777d9e 77 32 1 - b ---- 0.0 2e5 e43546763b649cd3b 78 32 1 - b ---- 0.0 edf18f0bba513af40346 79 32 1 - b ---- 0.0 a577cb04bac38034dc95 80 32 1 - b ---- 0.0 e9d12885cf941b2f149c 81 32 1 - b ---- 0.0 c23144b5f096a13a71bb 82 32 1 - b ---- 0.0 19e1 de022f4a565bc1e2 83 32 1 - b ---- 0.0 29ff 05 b603a5d0cdebdc 84 32 1 - b ---- 0.0 4 d4e8d94047cf9c45080 85 32 1 - b ---- 0.0 433115 bed52cbea861a0 86 32 1 - b ---- 0.0 1 bacfdf7b71099057d8c 87 32 1 - b ---- 0.0

The create.py-script also generated a DNS zone file that maps the domain names to IP addresses. This is the generated zone file for www.skjegstad.com:

$ cat www . skjegstad . com . zone @ IN SOA ns . www . skjegstad . com . postmaster . www . skjegstad . com . ( 1 600 600 600 60 ) www . skjegstad . com . IN CNAME index . html . www . skjegstad . com . index . html . www . skjegstad . com IN A 192.168.56.10 images . profile . jpg . www . skjegstad . com IN A 192.168.56.11 ardrone - experiment - 1. blog . images . ardrone - test . m4v . www . skjegstad . com IN A 192.168.56.12 ardrone - experiment - 1. blog . images . camera - 33. jpg . www . skjegstad . com IN A 192.168.56.13 ardrone - experiment - 1. blog . images . ardrone - test . png . www . skjegstad . com IN A 192.168.56.14 ardrone - experiment - 1. blog . images . ardrone1 . jpg . www . skjegstad . com IN A 192.168.56.15 ardrone - experiment - 1. blog . images . camera - 28. jpg . www . skjegstad . com IN A 192.168.56.16 ardrone - experiment - 1. blog . images . screenshot1 . png . www . skjegstad . com IN A 192.168.56.17 mirage - dev . blog . images . ubuntu - in - vm - overview . jpg . www . skjegstad . com IN A 192.168.56.18 mirage - dev . blog . images . xen - in - vm - overview . jpg . www . skjegstad . com IN A 192.168.56.19 uavexperiment . blog . images . MobileNode . png . www . skjegstad . com IN A 192.168.56.20 uavexperiment . blog . images . image6 . jpg . www . skjegstad . com IN A 192.168.56.21 uavexperiment . blog . images . image1 . jpg . www . skjegstad . com IN A 192.168.56.22 uavexperiment . blog . images . image5 . jpg . www . skjegstad . com IN A 192.168.56.23 uavexperiment . blog . images . image4 . jpg . www . skjegstad . com IN A 192.168.56.24 uavexperiment . blog . images . image3 . jpg . www . skjegstad . com IN A 192.168.56.25 uavexperiment . blog . images . image2 . jpg . www . skjegstad . com IN A 192.168.56.26 software . index . html . www . skjegstad . com IN A 192.168.56.27 macvim - and - funnel - pl .05.01.2012 . blog . index . html . www . skjegstad . com IN A 192.168.56.28 ardrone - test - flight - 1.12.01.2012 . blog . index . html . www . skjegstad . com IN A 192.168.56.29 mirageos - xen - virtualbox .19.01.2015 . blog . index . html . www . skjegstad . com IN A 192.168.56.30 experimenting - with - distributed - chat .02.12.2011 . blog . index . html . www . skjegstad . com IN A 192.168.56.31 a - stand - alone - java - bloom - filter .20.10.2011 . blog . index . html . www . skjegstad . com IN A 192.168.56.32 virtualbox . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.33 bloom - filters . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.34 mist . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.35 unikernel . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.36 experiments . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.37 vim . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.38 xen . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.39 mirageos . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.40 ardrone . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.41 java . categories . blog . index . html . www . skjegstad . com IN A 192.168.56.42 papers . skjegstad - mistsd - milcom2010 . pdf . www . skjegstad . com IN A 192.168.56.43 papers . milcom09skjegstad . pdf . www . skjegstad . com IN A 192.168.56.44 papers . milcom11 - distributed - chat . pdf . www . skjegstad . com IN A 192.168.56.45 publications . index . html . www . skjegstad . com IN A 192.168.56.46 about . index . html . www . skjegstad . com IN A 192.168.56.47 js . theme . modernizr - 2.0 . js . www . skjegstad . com IN A 192.168.56.48 js . theme . octopress . js . www . skjegstad . com IN A 192.168.56.49 js . theme . ender . js . www . skjegstad . com IN A 192.168.56.50 js . theme . github . js . www . skjegstad . com IN A 192.168.56.51 images . theme . noise . png . www . skjegstad . com IN A 192.168.56.52 images . theme . search . png . www . skjegstad . com IN A 192.168.56.53 images . theme . code - bg . png . www . skjegstad . com IN A 192.168.56.54 images . theme . line - tile . png . www . skjegstad . com IN A 192.168.56.55 images . theme . email . png . www . skjegstad . com IN A 192.168.56.56 images . theme . rss . png . www . skjegstad . com IN A 192.168.56.57 css . theme . main . css . www . skjegstad . com IN A 192.168.56.58

The zone file can be loaded in your favorite DNS server (e.g. bind or unbound). It is also relatively easy to build a quick DNS server in OCaml based on ocaml-dns:

open Dns open Lwt let () = Lwt_main . run ( let address = "0.0.0.0" in let port = 53 in Dns_server_unix . serve_with_zonefile ~ address ~ port "www.skjegstad.com.zone" )

I have written an extended version with support for forwarding unknown DNS requests to another DNS server. It is available for download here and is included in the demo code. In fact, you could also run the DNS server as a unikernel, but I will leave that as an exercise for the reader (this blog post by Heidi Howard is a good starting point with lots of examples).

Point your DNS server to the IP of the DNS server that hosts the zone file to start browsing the static website. Each static page should map to a separate domain name which is run by a single MirageOS unikernel!

Conclusion / discussion

Currently this is just a quick experiment and is not very practical. I would still need a unikernel or Linux VM to run the DNS server and I have not been able to find a hosting provider that has a minimum configuration which would be appropriate for large or small unikernels (e.g. 8MB vs 64MB RAM). Each VM/URL would also require a unique public IP address unless they are placed behind another service (NAT) that can route the HTTP requests to an internal network.

If you followed along, then you would also notice that the compiled unikernels in ./staging take up around 175MB (49 unikernels). When running, they collectively consume around 1.6GB of memory. However, it was a lot easier to try this experiment using unikernels than it would have been with a traditional OS stack.

A more practical architecture would perhaps be to run a website and DNS server from a single host initially. As each web page is mapped to a URL, the DNS server could then be configured to automatically boot new unikernels only if a subdomain experienced high load. It could, for example, deploy unikernels automatically to Amazon EC2 that serve a single file and start returning its IP address in DNS queries in periods with high load. Once the website has been 'disaggregated' this way, it would even be possible to start VMs in availability zones that are geographically close to the where the spike in traffic is originating! This could all be configured to happen automatically, with DNS entries being updated as new pages are added and with unikernels being deployed to places where they are in demand.

(Thanks to Amir Chaudry for commenting on a draft of this post)