Build a unikernel
A unikernel links one application with only the operating-system libraries it needs. There is no general-purpose guest OS inside the service image. Compared with a Linux service, this usually means a smaller boot path, faster startup, and a narrower isolation boundary.
The Platform supports two unikernel families:
- MirageOS for OCaml services where memory safety and a small trusted computing base (less code that has to be correct for the system to be secure) are the main design goals.
- Unikraft for C, C++, Rust, and POSIX-oriented services closer to an existing Linux application.
You do not need a local OCaml, mirage, or kraft toolchain, and no Docker
daemon is involved: space build runs the matching toolchain inside the
disposable builder VM.
Prerequisites
- A local SpaceOS environment from the quickstart.
Describe the app
An app.yaml declares the kind and pins the toolchain.
MirageOS:
schema: space.appversion: "1"name: my-servicesource: .kind: mirage
mirage_version: "4.9.0"ocaml_version: "5.4.1"opam_repo: https://github.com/ocaml/opam-repository.gitopam_repo_rev: "<full-git-commit>"
targets: - platform: hvt arch: arm64
policy: network: replay reproducible: true
outputs: flight: platform: hvt path: dist/my-service.hvt kind: unikernelUnikraft differs only in the toolchain fields:
schema: space.appversion: "1"name: my-servicesource: .kind: unikraftkraftkit_image: kraftkit.sh/base@sha256:<digest>targets: - platform: qemu arch: arm64policy: network: replay reproducible: trueoutputs: flight: platform: qemu path: .unikraft/build/app_qemu kind: unikernelBuild it:
space build app.yamlspace build generates a pinned build, runs it in the builder VM, and emits
an OCI artifact plus an artifact manifest. The output key (flight) is
architecture-independent; the manifest carries the per-architecture
variants.
Run it directly
A single unikernel image needs no manifests at all. space run IMAGE
recognizes an image whose root filesystem is a single .hvt or .spt
binary and boots it under the matching
Solo5 tender, the small host program
that sandboxes and runs a unikernel:
space run my-service:dev --headlessCompose it into a system
For a multi-service system, reference the artifact from build.yaml:
schema: space.buildversion: "1"kernel: linuxkit/kernel:6.6.13output: _build/spaceos
artifacts: my-service: manifest: _build/oci/my-service/artifacts.yaml
partitions: payload: init: pid1 services: - name: my-service artifact: my-service#flightAn artifact reference derives the runtime and variants from the manifest,
so no runtime field is needed. Then place it in run.yaml:
schema: space.runversion: "1"image: _build/spaceos
partitions: payload: memory: 64 apids: [0x010, 0x01F] send_to: [ground] services: - name: my-service isolation: hvt cpus: [0]
relay: from: payload to: [ground]
ground: port: 8080Use isolation: hvt where the target provides KVM hardware virtualization,
and spt where it does not. Supported
isolation backends vary by target. Build and run the
composition:
space build . -t my-service:devspace run my-service:dev --runtime run.yamlPackaging by hand
The OCI image is a distribution format, not a build requirement. If you already build unikernels with your own toolchain, wrap the binary yourself and any standard OCI client can push it:
FROM scratchCOPY my-service.hvt /An image with that shape is detected and launched as a unikernel exactly
like an image built by space build.
Deploy
Build a release-signed image and target a connected board:
space build . -t my-service:release --release --signing-profile releasespace deploy my-service:release --target cm5-demo --planspace deploy my-service:release --target cm5-demoLinux-container use cases
Use the Linux service path when your workload depends on a broad Linux userland, runtime-loaded plugins, kernel-specific features, or a dependency tree that is not worth porting.