Materials for the LambdaNantes 4 workshop: An Introduction to Unikernels with OCaml!
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Some code

xvw 6d654d35 52f0b918

+319 -1
+1 -1
.gitignore
··· 34 34 35 35 # Local OPAM switch 36 36 _opam/ 37 - _vendors/ 37 + vendors/ 38 38 39 39 # Slipshow artifact 40 40 support/slides.html
+7
.ocamlformat
··· 1 + version = 0.29.0 2 + profile = janestreet 3 + ocaml-version = 5.4 4 + margin = 80 5 + parse-docstrings = true 6 + break-separators = before 7 + break-infix = fit-or-vertical
+10
dune-project
··· 27 27 (merlin :with-dev-setup) 28 28 (ocaml-lsp-server :with-dev-setup))) 29 29 30 + (package 31 + (name unikernels) 32 + (synopsis "Project Unikernel Catalog") 33 + (description "Umbrella package for unikernels") 34 + (depends 35 + (ocaml (>= 5.4.0)) 36 + solo5 37 + ocaml-solo5 38 + mkernel 39 + mnet))
+7
dune-workspace
··· 1 + (lang dune 3.21) 2 + (context (default)) 3 + (context (default 4 + (name solo5) 5 + (host default) 6 + (toolchain solo5) 7 + (disable_dynamically_linked_foreign_archives true)))
+91
support/slides.md
··· 1 1 --- 2 2 dimension:16:9 3 3 --- 4 + 5 + <style> 6 + table, td, th { 7 + border: 1px solid black; 8 + } 9 + td, th { 10 + padding: 0.5rem; 11 + } 12 + table { 13 + border-collapse: collapse; 14 + } 15 + </style> 16 + 17 + {#title} 18 + # Our first Unikernels in OCaml — _for fun and profit_! 19 + 20 + {pause .intro #punchline-intro up=title} 21 + 22 + Hello! In this **interactive presentation** (_a workshop_), we’ll get 23 + started with creating **unikernels** using the wonderful 24 + [OCaml](https://ocaml.org) language. 25 + 26 + _A relatively impractical way to get started with OCaml programming_! 27 + 28 + --- 29 + 30 + {pause .plan #plan} 31 + # Plan 32 + 33 + - Understanding **What Unikernels Are** {pause up=plan} 34 + - Understanding **what they solve** {pause} 35 + - Understanding the approaches offered by OCaml {pause} 36 + 37 + 38 + - Get familiar with the OCaml toolchain (specifically for building 39 + OCaml Unikernels) {pause} 40 + - Build System/Package Manager {pause} 41 + - Set up a project (and understand its components) {pause} 42 + - Understanding the Challenges Associated with Unikernel Development {pause} 43 + 44 + - **Developing multiple small unikernels** {pause} 45 + 46 + {.block} 47 + By the end of this presentation, I hope you’ll have 48 + **successfully built a Unikernel**, and that this will potentially 49 + open your eyes to using **them when appropriate** (in OCaml, obviously). 50 + 51 + This presentation was made possible by [the 52 + work](https://robur-coop.github.io/mnet/) of the [Robur 53 + cooperative](https://blog.robur.coop/), and specifically thanks to 54 + [Romain (Dinosaure)](https://github.com/dinosaure)! 55 + 56 + {pause up=plan down=unikernel-what} 57 + 58 + {#unikernel-what} 59 + # What Unikernels Are 60 + 61 + {blockquote} A unikernel is **a single-application VM** image where 62 + the application and **minimal operating system** are compiled into one 63 + optimized binary. 64 + 65 + {pause up=unikernel-what #what-regular-vm} 66 + ## Regular VM 67 + 68 + - **Full Linux Kernel** 69 + - Shell tools 70 + - Package Manager 71 + - A lot of drivers 72 + - Multiple processus 73 + - Multiple users 74 + - **Finally your API process** 75 + 76 + {pause up=what-regular-vm #what-unikernel} 77 + ## Unikernel 78 + 79 + - **Your API** 80 + - Compiled into one **sealed image** 81 + - Boots **directly** as a VM guest (using the _Hypervisor_) 82 + 83 + {pause up=what-unikernel #what-container} 84 + ### Container VS Unikernels 85 + 86 + | Container | Unikernel | 87 + |-------------------------------|--------------------------------------| 88 + | Shares the host Linux kernel | Has its **own** minimal kernel image | 89 + | Lightweight process isolation | Stronger isolation | 90 + | | Even smaller runtime surface | 91 + | Great tooling ecosystem | | 92 + | isolated process | isolated single-purpose mini-OS | 93 + 94 +
+35
unikernels.opam
··· 1 + # This file is generated by dune, edit dune-project instead 2 + opam-version: "2.0" 3 + version: "dev" 4 + synopsis: "Project Unikernel Catalog" 5 + description: "Umbrella package for unikernels" 6 + maintainer: ["xvw <xaviervdw@gmail.com>"] 7 + authors: ["xvw <xaviervdw@gmail.com>"] 8 + license: "MIT" 9 + homepage: "https://tangled.org/xvw/ln-workshop-4-ocaml-unikernel" 10 + bug-reports: "https://tangled.org/xvw/ln-workshop-4-ocaml-unikernel/issues" 11 + depends: [ 12 + "dune" {>= "3.21"} 13 + "ocaml" {>= "5.4.0"} 14 + "solo5" 15 + "ocaml-solo5" 16 + "mkernel" 17 + "mnet" 18 + "odoc" {with-doc} 19 + ] 20 + build: [ 21 + ["dune" "subst"] {dev} 22 + [ 23 + "dune" 24 + "build" 25 + "-p" 26 + name 27 + "-j" 28 + jobs 29 + "@install" 30 + "@runtest" {with-test} 31 + "@doc" {with-doc} 32 + ] 33 + ] 34 + dev-repo: "git+https://tangled.org/xvw/ln-workshop-4-ocaml-unikernel" 35 + x-maintenance-intent: ["(latest)"]
+26
unikernels/echo/dune
··· 1 + (executable 2 + (name main) 3 + (package unikernels) 4 + (public_name unikernels.echo) 5 + (link_flags :standard -cclib "-z solo5-abi=hvt") 6 + (foreign_stubs 7 + (language c) 8 + (names echo_manifest)) 9 + (libraries mkernel mirage-crypto-rng-mkernel mnet gmp)) 10 + 11 + (rule 12 + (targets echo_manifest.c) 13 + (deps echo_manifest.json) 14 + (enabled_if 15 + (= %{context_name} "solo5")) 16 + (action 17 + (run solo5-elftool gen-manifest echo_manifest.json echo_manifest.c))) 18 + 19 + (rule 20 + (targets echo_manifest.c) 21 + (enabled_if 22 + (= %{context_name} "default")) 23 + (action 24 + (write-file echo_manifest.c ""))) 25 + 26 + (vendored_dirs vendors)
+1
unikernels/echo/echo_manifest.json
··· 1 + {"type":"solo5.manifest","version":1,"devices":[{"type":"NET_BASIC","name":"service"}]}
+62
unikernels/echo/main.ml
··· 1 + module TCP = Mnet.TCP 2 + 3 + (* Initialize a Secure Random Number generator. *) 4 + let rng = 5 + Mkernel.map 6 + (fun () -> 7 + Mirage_crypto_rng_mkernel.initialize (module Mirage_crypto_rng.Fortuna)) 8 + [] 9 + ;; 10 + 11 + (* An helper for finalizing resources (because Miou, the Scheduler, ask 12 + for every task to be terminated) *) 13 + let ( let@ ) finally fn = Fun.protect ~finally fn 14 + let clean_rng rng () = Mirage_crypto_rng_mkernel.kill rng 15 + let clean_stack stack () = Mnet.kill stack 16 + 17 + (* Since we handle active connection, we need to iterate on every orphans 18 + to clean them. *) 19 + let rec clean_children orphans = 20 + match Miou.care orphans with 21 + | Some None | None -> () 22 + | Some (Some prm) -> 23 + (match Miou.await prm with 24 + | Ok () -> clean_children orphans 25 + | Error _ -> Logs.err (fun p -> p "Unexpected exception")) 26 + ;; 27 + 28 + (* General Handler *) 29 + let handler flow () = 30 + let resource = Miou.Ownership.create ~finally:TCP.close flow in 31 + let () = Miou.Ownership.own resource in 32 + let buffer = 33 + Bytes.create 0x7ff 34 + (* default size of the buffer, Almost 2kb *) 35 + in 36 + let rec loop () = 37 + match TCP.read flow buffer with 38 + | 0 -> Miou.Ownership.release resource 39 + | len -> 40 + let str = Bytes.sub_string buffer 0 len in 41 + let () = TCP.write flow ("Response: " ^ str) in 42 + loop () 43 + in 44 + loop () 45 + ;; 46 + 47 + (* Main program *) 48 + let () = 49 + let ipv4 = Ipaddr.V4.Prefix.of_string_exn "10.0.0.2/24" in 50 + Mkernel.run 51 + [ rng; Mnet.stack ~name:"service" ipv4 ] 52 + (fun rng (stack, tcp, _) () -> 53 + let@ () = clean_rng rng in 54 + let@ () = clean_stack stack in 55 + let rec loop orphans listen = 56 + let () = clean_children orphans in 57 + let flow = TCP.accept tcp listen in 58 + let _ = Miou.async ~orphans (handler flow) in 59 + loop orphans listen 60 + in 61 + loop (Miou.orphans ()) (TCP.listen tcp 8888)) 62 + ;;
+26
unikernels/hello/dune
··· 1 + (executable 2 + (name main) 3 + (package unikernels) 4 + (public_name unikernels.hello) 5 + (link_flags :standard -cclib "-z solo5-abi=hvt") 6 + (foreign_stubs 7 + (language c) 8 + (names hello_manifest)) 9 + (libraries mkernel)) 10 + 11 + (rule 12 + (targets hello_manifest.c) 13 + (deps hello_manifest.json) 14 + (enabled_if 15 + (= %{context_name} "solo5")) 16 + (action 17 + (run solo5-elftool gen-manifest hello_manifest.json hello_manifest.c))) 18 + 19 + (rule 20 + (targets hello_manifest.c) 21 + (enabled_if 22 + (= %{context_name} "default")) 23 + (action 24 + (write-file hello_manifest.c ""))) 25 + 26 + (vendored_dirs vendors)
+1
unikernels/hello/hello_manifest.json
··· 1 + {"type":"solo5.manifest","version":1,"devices":[]}
+1
unikernels/hello/main.ml
··· 1 + let () = Mkernel.run [] (fun () -> print_endline "Hello, Lambda Nantes!")
+26
unikernels/hello_server/dune
··· 1 + (executable 2 + (name main) 3 + (package unikernels) 4 + (public_name unikernels.hello_server) 5 + (link_flags :standard -cclib "-z solo5-abi=hvt") 6 + (foreign_stubs 7 + (language c) 8 + (names hello_server_manifest)) 9 + (libraries mkernel mirage-crypto-rng-mkernel mnet gmp)) 10 + 11 + (rule 12 + (targets hello_server_manifest.c) 13 + (deps hello_server_manifest.json) 14 + (enabled_if 15 + (= %{context_name} "solo5")) 16 + (action 17 + (run solo5-elftool gen-manifest hello_server_manifest.json hello_server_manifest.c))) 18 + 19 + (rule 20 + (targets hello_server_manifest.c) 21 + (enabled_if 22 + (= %{context_name} "default")) 23 + (action 24 + (write-file hello_server_manifest.c ""))) 25 + 26 + (vendored_dirs vendors)
+1
unikernels/hello_server/hello_server_manifest.json
··· 1 + {"type":"solo5.manifest","version":1,"devices":[{"type":"NET_BASIC","name":"service"}]}
+24
unikernels/hello_server/main.ml
··· 1 + (* Initialize a Secure Random Number generator. *) 2 + let rng = 3 + Mkernel.map 4 + (fun () -> 5 + Mirage_crypto_rng_mkernel.initialize (module Mirage_crypto_rng.Fortuna)) 6 + [] 7 + ;; 8 + 9 + (* An helper for finalizing resources (because Miou, the Scheduler, ask 10 + for every task to be terminated) *) 11 + let ( let@ ) finally fn = Fun.protect ~finally fn 12 + let clean_rng rng () = Mirage_crypto_rng_mkernel.kill rng 13 + let clean_stack stack () = Mnet.kill stack 14 + 15 + (* Main program *) 16 + let () = 17 + let ipv4 = Ipaddr.V4.Prefix.of_string_exn "10.0.0.2/24" in 18 + Mkernel.run 19 + [ rng; Mnet.stack ~name:"service" ipv4 ] 20 + (fun rng (stack, _, _) () -> 21 + let@ () = clean_rng rng in 22 + let@ () = clean_stack stack in 23 + print_endline "Hello, Lambda Nantes (from a server)") 24 + ;;