Skip to content

Commit 446324b

Browse files
jim-juniorurunc-bot[bot]
authored andcommitted
feat: add hermit unikernel backend support
- Added Hermit unikernel backend (QEMU x86_64, initrd-based boot) - Enabled basic networking support via virtio-net tap - Added Hermit unikernel test cases to e2e suite - Updated documentation and contributor list PR: #567 Fixes: #97 Signed-off-by: jim-junior <jimjunior854@gmail.com> Reviewed-by: Anastassios Nanos <ananos@nubificus.co.uk> Approved-by: Anastassios Nanos <ananos@nubificus.co.uk>
1 parent a04eed8 commit 446324b

9 files changed

Lines changed: 198 additions & 7 deletions

File tree

.github/contributors.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,6 @@ users:
8080
praffq-dev:
8181
name: Prafful
8282
email: praffq.dev@gmail.com
83+
jim-junior:
84+
name: Beingana Jim Junior
85+
email: jimjunior854@gmail.com

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,14 @@ At the moment, `urunc` is available on GNU/Linux for x86\_64 and arm64 architect
139139
In addition, the following table provides an overview of the currently
140140
supported VM/Sandbox monitors and unikernels:
141141

142-
| Unikernel | VM/Sandbox Monitor | Arch | Storage |
143-
|----------- |--------------------------- |------------- |------------------------------ |
144-
| Rumprun | Solo5-hvt, Solo5-spt | x86,aarch64 | Block/Devmapper |
145-
| Unikraft | QEMU, Firecracker | x86 | Initrd, 9pfs |
146-
| MirageOS | QEMU, Solo5-hvt, Solo5-spt | x86,aarch64 | Block/Devmapper |
147-
| Mewz | QEMU | x86 | In-memory |
148-
| Linux | QEMU, Firecracker | x86 | Initrd, Block/Devmapper, 9pfs, Virtiofs |
142+
| Unikernel | VM/Sandbox Monitor | Arch | Storage |
143+
| --------- | -------------------------- | ----------- | --------------------------------------- |
144+
| Rumprun | Solo5-hvt, Solo5-spt | x86,aarch64 | Block/Devmapper |
145+
| Unikraft | QEMU, Firecracker | x86 | Initrd, 9pfs |
146+
| MirageOS | QEMU, Solo5-hvt, Solo5-spt | x86,aarch64 | Block/Devmapper |
147+
| Mewz | QEMU | x86 | In-memory |
148+
| Linux | QEMU, Firecracker | x86 | Initrd, Block/Devmapper, 9pfs, Virtiofs |
149+
| Hermit | QEMU | x86 | Initrd |
149150

150151
We plan to add support for more unikernel frameworks and other platforms too.
151152
Feel free to [contact](#Contact) us for a specific unikernel framework or similar

docs/Sample-images.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,4 @@ We plan to create and maintain multi-platform images soon, as well as enrich thi
5050
- harbor.nbfc.io/nubificus/urunc/whoami-firecracker-linux-initrd:latest
5151
- harbor.nbfc.io/nubificus/urunc/busybox-qemu-linux-raw:latest
5252
- harbor.nbfc.io/nubificus/urunc/busybox-firecracker-linux-raw:latest
53+
- harbor.nbfc.io/nubificus/urunc/hello-world-qemu-hermit-initrd:latest

docs/hypervisor-support.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ Supported unikernel frameworks with `urunc`:
6565
- [MirageOS](../unikernel-support#mirage)
6666
- [Mewz](../unikernel-support#mewz)
6767
- [Linux](../unikernel-support#linux)
68+
- [Hermit](../unikernel-support#hermit)
6869

6970
An example unikernel:
7071

docs/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Sandbox monitors, along with the unikernels that can run on top of them.
6060
| [MirageOS](./unikernel-support#mirage)| [Qemu](./hypervisor-support#qemu), [Solo5-hvt](./hypervisor-support#solo5-hvt), [Solo5-spt](./hypervisor-support#solo5-spt) | x86, aarch64 | Block/Devmapper |
6161
| [Mewz](./unikernel-support#mewz)| [Qemu](./hypervisor-support#qemu) | x86 | In-memory |
6262
| [Linux](./unikernel-support#linux)| [Qemu](./hypervisor-support#qemu), [Firecracker](./hypervisor-support#aws-firecracker) | x86, aarch64 | Initrd, Block/Devmapper, 9pfs, Virtiofs |
63+
| [Hermit](./unikernel-support#hermit)| [Qemu](./hypervisor-support#qemu) | x86 | Initrd |
6364

6465
<!-- ## urunc and the CNCF -->
6566

docs/unikernel-support.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,45 @@ An example of a Redis alpine image transformed to a block file on top of
342342
sudo nerdctl run --rm -ti --runtime io.containerd.urunc.v2 harbor.nbfc.io/nubificus/urunc/redis-firecracker-linux-block:latest
343343
```
344344

345+
## Hermit
346+
347+
[Hermit](https://hermit-os.org/) is a unikernel designed for
348+
high-performance and cloud/HPC workloads.
349+
Its a Rust re-write of the Hermit-Core unikernel in order to leverage the
350+
memory/thread-safety guarantees provided by the Rust ownership model.
351+
352+
Hermit provides support for multiple compiled languages like Rust, C, C++, Go and Fotran. Hermit applications are compiled
353+
into a unikernel image that includes both the application and the operating system.
354+
When the unikernel boots, the application starts execution immediately.
355+
356+
Hermit provides support for multithreading, networking, and basic system
357+
interfaces. It is particularly well-suited for cloud and microservice
358+
environments where lightweight isolation is required.
359+
360+
### VMMs and other sandbox monitors
361+
362+
Hermit runs on top of the [QEMU](https://www.qemu.org/) virtual machine monitor.
363+
It supports standard virtualization interfaces such as virtio devices for networking.
364+
365+
When executed with [QEMU](https://www.qemu.org/), Hermit can access the network through
366+
a `virtio-net` device. Hermit supports both `virtio-fs` and `initrd` as storage options with the respective configuration at build time.
367+
368+
### Hermit and `urunc`
369+
370+
In the case of Hermit, `urunc` provides support for running unikernels on
371+
top of QEMU. If the container is configured with network access, `urunc` will
372+
attach a `virtio-net` device to enable networking for the unikernel. Hermit in `urunc` only supports `initrd` for storage.
373+
374+
For more information on packaging
375+
[Hermit](https://hermit-os.org/) unikernels for `urunc` take
376+
a look at our [packaging](../package/) page.
377+
378+
An example of running a Hermit unikernel with `urunc`:
379+
380+
```bash
381+
sudo nerdctl run --rm -ti --runtime io.containerd.urunc.v2 harbor.nbfc.io/nubificus/urunc/hello-world-qemu-hermit-initrd:latest
382+
```
383+
345384
## Future unikernels and frameworks:
346385

347386
In the near future, we plan to add support for the following frameworks:
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright (c) 2023-2026, Nubificus LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package unikernels
16+
17+
import (
18+
"fmt"
19+
"runtime"
20+
"strings"
21+
22+
"github.com/urunc-dev/urunc/pkg/unikontainers/types"
23+
)
24+
25+
const HermitUnikernel string = "hermit"
26+
27+
type Hermit struct {
28+
Command string
29+
Monitor string
30+
Net HermitNet
31+
}
32+
33+
type HermitNet struct {
34+
Address string
35+
Mask int
36+
Gateway string
37+
}
38+
39+
func (h *Hermit) CommandString() (string, error) {
40+
var args []string
41+
42+
if h.Net.Address != "" {
43+
args = append(args, fmt.Sprintf("ip=%s/%d", h.Net.Address, h.Net.Mask))
44+
}
45+
if h.Net.Gateway != "" {
46+
args = append(args, fmt.Sprintf("gateway=%s", h.Net.Gateway))
47+
}
48+
49+
// Add separator ONLY if we have net args AND a command
50+
appArgs := strings.TrimSpace(h.Command)
51+
if len(args) > 0 && appArgs != "" {
52+
args = append(args, "--")
53+
}
54+
55+
if appArgs != "" {
56+
args = append(args, appArgs)
57+
}
58+
59+
return strings.Join(args, " "), nil
60+
}
61+
62+
func (h *Hermit) SupportsBlock() bool {
63+
return false
64+
}
65+
66+
func (h *Hermit) SupportsFS(fsType string) bool {
67+
return fsType == "initrd"
68+
}
69+
70+
func (h *Hermit) MonitorNetCli(ifName string, mac string) string {
71+
switch h.Monitor {
72+
case "qemu":
73+
netdev := fmt.Sprintf(" -netdev tap,id=net0,ifname=%s,script=no,downscript=no", ifName)
74+
75+
var deviceArgs string
76+
77+
// QEMU on x86_64 typically uses virtio-net-pci.
78+
// On arm64 virtio-net-device is the safer default.
79+
if runtime.GOARCH == "arm64" {
80+
deviceArgs = " -device " + "virtio-net-device" + ",netdev=net0"
81+
} else {
82+
deviceArgs = " -device " + "virtio-net-pci" + ",netdev=net0,disable-legacy=on"
83+
}
84+
85+
if mac != "" {
86+
deviceArgs += ",mac=" + mac
87+
}
88+
89+
return netdev + deviceArgs
90+
default:
91+
return ""
92+
}
93+
}
94+
95+
func (h *Hermit) MonitorBlockCli() []types.MonitorBlockArgs {
96+
return nil
97+
}
98+
99+
func (h *Hermit) MonitorCli() types.MonitorCliArgs {
100+
return types.MonitorCliArgs{
101+
OtherArgs: " -no-reboot",
102+
}
103+
}
104+
105+
func (h *Hermit) Init(data types.UnikernelParams) error {
106+
107+
if data.Net.Mask != "" {
108+
mask, err := subnetMaskToCIDR(data.Net.Mask)
109+
if err != nil {
110+
return err
111+
}
112+
h.Net.Address = data.Net.IP
113+
h.Net.Gateway = data.Net.Gateway
114+
h.Net.Mask = mask
115+
}
116+
117+
h.Command = strings.Join(data.CmdLine, " ")
118+
h.Monitor = data.Monitor
119+
120+
return nil
121+
}
122+
123+
func newHermit() *Hermit {
124+
return new(Hermit)
125+
}

pkg/unikontainers/unikernels/unikernel.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ func New(unikernelType string) (types.Unikernel, error) {
3939
case LinuxUnikernel:
4040
unikernel := newLinux()
4141
return unikernel, nil
42+
case HermitUnikernel:
43+
unikernel := newHermit()
44+
return unikernel, nil
4245
default:
4346
return nil, ErrNotSupportedUnikernel
4447
}

tests/e2e/test_cases.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,23 @@ func ctrTestCases() []containerTestArgs {
733733
ExpectOut: "UID: 0 GID: 42 WD: /test_dir URUNC: urunc",
734734
TestFunc: matchTest,
735735
},
736+
{
737+
Image: "harbor.nbfc.io/nubificus/urunc/hello-world-qemu-hermit-initrd:latest",
738+
Name: "Qemu-hermit-hello-world",
739+
Devmapper: false,
740+
Seccomp: true,
741+
UID: 0,
742+
GID: 0,
743+
Groups: []int64{},
744+
Memory: "",
745+
Cli: "",
746+
Volumes: []containerVolume{},
747+
StaticNet: false,
748+
SideContainers: []string{},
749+
Skippable: false,
750+
ExpectOut: "Hello, world!",
751+
TestFunc: matchTest,
752+
},
736753
}
737754
}
738755

0 commit comments

Comments
 (0)